/src/tools/cgexec.c

https://bitbucket.org/bosp/external-libcg · C · 173 lines · 126 code · 18 blank · 29 comment · 19 complexity · 668441ba645ad697787833512d8d7a6d MD5 · raw file

  1. /*
  2. * Copyright RedHat Inc. 2008
  3. *
  4. * Authors: Vivek Goyal <vgoyal@redhat.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of version 2.1 of the GNU Lesser General Public License
  8. * as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it would be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. *
  14. */
  15. #ifndef _GNU_SOURCE
  16. #define _GNU_SOURCE
  17. #endif
  18. #include <errno.h>
  19. #include <grp.h>
  20. #include <libcgroup.h>
  21. #include <limits.h>
  22. #include <pwd.h>
  23. #include <search.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <unistd.h>
  28. #include <getopt.h>
  29. #include <sys/mount.h>
  30. #include <sys/stat.h>
  31. #include <sys/types.h>
  32. #include "tools-common.h"
  33. static struct option longopts[] = {
  34. {"sticky", no_argument, NULL, 's'},
  35. {"help", no_argument, NULL, 'h'},
  36. {0, 0, 0, 0}
  37. };
  38. static void usage(int status, const char *program_name)
  39. {
  40. if (status != 0)
  41. fprintf(stderr, "Wrong input parameters,"
  42. " try %s --help' for more information.\n",
  43. program_name);
  44. else {
  45. printf("Usage: %s [-h] [-g <controllers>:<path>] "
  46. "[--sticky] command [arguments] ...\n",
  47. program_name);
  48. }
  49. }
  50. int main(int argc, char *argv[])
  51. {
  52. int ret = 0, i;
  53. int cg_specified = 0;
  54. int flag_child = 0;
  55. uid_t uid;
  56. gid_t gid;
  57. pid_t pid;
  58. int c;
  59. struct cgroup_group_spec *cgroup_list[CG_HIER_MAX];
  60. memset(cgroup_list, 0, sizeof(cgroup_list));
  61. while ((c = getopt_long(argc, argv, "+g:sh", longopts, NULL)) > 0) {
  62. switch (c) {
  63. case 'g':
  64. ret = parse_cgroup_spec(cgroup_list, optarg,
  65. CG_HIER_MAX);
  66. if (ret) {
  67. fprintf(stderr, "cgroup controller and path"
  68. "parsing failed\n");
  69. return -1;
  70. }
  71. cg_specified = 1;
  72. break;
  73. case 's':
  74. flag_child |= CGROUP_DAEMON_UNCHANGE_CHILDREN;
  75. break;
  76. case 'h':
  77. usage(0, argv[0]);
  78. exit(0);
  79. default:
  80. usage(1, argv[0]);
  81. exit(1);
  82. }
  83. }
  84. /* Executable name */
  85. if (!argv[optind]) {
  86. usage(1, argv[0]);
  87. exit(1);
  88. }
  89. /* Initialize libcg */
  90. ret = cgroup_init();
  91. if (ret) {
  92. fprintf(stderr, "libcgroup initialization failed: %s\n",
  93. cgroup_strerror(ret));
  94. return ret;
  95. }
  96. /* Just for debugging purposes. */
  97. uid = geteuid();
  98. gid = getegid();
  99. cgroup_dbg("My euid and eguid is: %d,%d\n", (int) uid, (int) gid);
  100. uid = getuid();
  101. gid = getgid();
  102. pid = getpid();
  103. ret = cgroup_register_unchanged_process(pid, flag_child);
  104. if (ret) {
  105. fprintf(stderr, "registration of process failed\n");
  106. return ret;
  107. }
  108. /*
  109. * 'cgexec' command file needs the root privilege for executing
  110. * a cgroup_register_unchanged_process() by using unix domain
  111. * socket, and an euid/egid should be changed to the executing user
  112. * from a root user.
  113. */
  114. if (setresuid(uid, uid, uid)) {
  115. fprintf(stderr, "%s", strerror(errno));
  116. return -1;
  117. }
  118. if (setresgid(gid, gid, gid)) {
  119. fprintf(stderr, "%s", strerror(errno));
  120. return -1;
  121. }
  122. if (cg_specified) {
  123. /*
  124. * User has specified the list of control group and
  125. * controllers
  126. * */
  127. for (i = 0; i < CG_HIER_MAX; i++) {
  128. if (!cgroup_list[i])
  129. break;
  130. ret = cgroup_change_cgroup_path(cgroup_list[i]->path,
  131. pid,
  132. (const char*const*) cgroup_list[i]->controllers);
  133. if (ret) {
  134. fprintf(stderr,
  135. "cgroup change of group failed\n");
  136. return ret;
  137. }
  138. }
  139. } else {
  140. /* Change the cgroup by determining the rules based on uid */
  141. ret = cgroup_change_cgroup_flags(uid, gid,
  142. argv[optind], pid, 0);
  143. if (ret) {
  144. fprintf(stderr, "cgroup change of group failed\n");
  145. return ret;
  146. }
  147. }
  148. /* Now exec the new process */
  149. ret = execvp(argv[optind], &argv[optind]);
  150. if (ret == -1) {
  151. fprintf(stderr, "%s", strerror(errno));
  152. return -1;
  153. }
  154. return 0;
  155. }