]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
cgexec: A command line tool to execute a task in a cgroup
authorDhaval Giani <dhaval@linux.vnet.ibm.com>
Wed, 13 Aug 2008 20:01:16 +0000 (20:01 +0000)
committerDhaval Giani <dhaval@linux.vnet.ibm.com>
Wed, 13 Aug 2008 20:01:16 +0000 (20:01 +0000)
From: Vivek Goyal <vgoyal@redhat.com>

o cgexec, a command line tool for placing the task in right cgroup
  in advance so that no help is needed from rules daemon and user can
  avoid delay in execution of rules.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Dhaval Giani <dhaval@linux.vnet.ibm.com>
git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/trunk@137 4f4bb910-9a46-0410-90c8-c897d4f1cd53

Makefile.in
cgexec.c [new file with mode: 0644]

index aeab421dc2e660395edf1ef3302ad845390f9dca..ba6a7a3bb8a7a1c7956819542e8cb417579f21f2 100644 (file)
@@ -29,12 +29,15 @@ PACKAGE_VERSION=@PACKAGE_VERSION@
 CFLAGS=@CFLAGS@ $(INC) -DPACKAGE_VERSION=$(PACKAGE_VERSION)
 VERSION=1
 
-all: libcgroup.so cgconfigparser
+all: libcgroup.so cgconfigparser cgexec
 
 cgconfigparser: libcgroup.so config.c y.tab.c lex.yy.c libcgroup.h file-ops.c
        $(CC) $(CFLAGS) -o $@ y.tab.c lex.yy.c config.c file-ops.c \
        $(LDFLAGS) $(LIBS)
 
+cgexec: libcgroup.so cgexec.c libcgroup.h
+       $(CC) $(CFLAGS) -Wall -o $@ cgexec.c $(LDFLAGS) $(LIBS)
+
 y.tab.c: parse.y lex.yy.c
        $(YACC) -v -d parse.y
 
@@ -46,12 +49,13 @@ libcgroup.so: api.c libcgroup.h wrapper.c
        wrapper.c
        ln -sf $@ $@.$(VERSION)
 
-install: libcgroup.so
+install: libcgroup.so cgexec
        $(INSTALL_DATA) -D libcgroup.h $(DESTDIR)$(includedir)/libcgroup.h
        $(INSTALL) -D libcgroup.so $(DESTDIR)$(libdir)/libcgroup-$(PACKAGE_VERSION).so
        ln -sf libcgroup-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libcgroup.so.$(VERSION)
        ln -sf libcgroup.so.$(VERSION) $(DESTDIR)$(libdir)/libcgroup.so
        $(INSTALL) -D cgconfigparser $(DESTDIR)$(sbindir)
+       $(INSTALL) cgexec $(DESTDIR)$(bindir)/cgexec
 
 uninstall: libcgroup.so
        rm -f $(DESTDIR)$(includedir)/libcgroup.h
@@ -59,7 +63,8 @@ uninstall: libcgroup.so
        rm -f $(DESTDIR)$(libdir)/libcgroup.so.$(VERSION)
        rm -f $(DESTDIR)$(libdir)/libcgroup-$(PACKAGE_VERSION).so
        rm -f $(DESTDIR)$(sbindir)/cgconfigparser
+       rm -f $(DESTDIR)$(bindir)/cgexec
 
 clean:
        \rm -f y.tab.c y.tab.h lex.yy.c y.output libcgroup.so \
-       libcgroup.so.$(VERSION) cgconfigparser config.log config.status
+       libcgroup.so.$(VERSION) cgconfigparser config.log config.status cgexec
diff --git a/cgexec.c b/cgexec.c
new file mode 100644 (file)
index 0000000..d91207f
--- /dev/null
+++ b/cgexec.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright RedHat Inc. 2008
+ *
+ * Authors:    Vivek Goyal <vgoyal@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <errno.h>
+#include <grp.h>
+#include <libcgroup.h>
+#include <limits.h>
+#include <pwd.h>
+#include <search.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define CG_HIER_MAX    CG_CONTROLLER_MAX
+#define CG_CONT_NAMELEN_MAX    128
+
+struct cgroup_data {
+       char path[FILENAME_MAX];
+       char *controllers[CG_CONTROLLER_MAX];
+};
+
+int parse_cgroup_data(struct cgroup_data *cdptr[], char *optarg)
+{
+       struct cgroup_data *ptr;
+       int i, j;
+       char *cptr, *pathptr, *temp;
+
+       ptr = *cdptr;
+
+       /* Find first free entry inside the cgroup data array */
+       for (i = 0; i < CG_HIER_MAX; i++, ptr++) {
+               if (!cdptr[i])
+                       break;
+       }
+
+       if (i == CG_HIER_MAX) {
+               /* No free slot found */
+               fprintf(stderr, "Max allowed hierarchies %d reached\n",
+                               CG_HIER_MAX);
+               return -1;
+       }
+
+       /* Extract list of controllers */
+       cptr = strtok(optarg, ":");
+       dbg("list of controllers is %s\n", cptr);
+       if (!cptr)
+               return -1;
+
+       /* Extract cgroup path */
+       pathptr = strtok(NULL, ":");
+       dbg("cgroup path is %s\n", pathptr);
+       if (!pathptr)
+               return -1;
+
+       /* instanciate cgroup_data. */
+       cdptr[i] = malloc(sizeof(struct cgroup_data));
+       if (!cdptr[i]) {
+               fprintf(stderr, "%s\n", strerror(errno));
+               return -1;
+       }
+       /* Convert list of controllers into an array of strings. */
+       j = 0;
+       do {
+               if (j == 0)
+                       temp = strtok(cptr, ",");
+               else
+                       temp = strtok(NULL, ",");
+
+               if (temp) {
+                       cdptr[i]->controllers[j] =
+                                       (char *) malloc(strlen(temp) + 1);
+                       if (!cdptr[i]->controllers[j]) {
+                               free(cdptr[i]);
+                               fprintf(stderr, "%s\n", strerror(errno));
+                               return -1;
+                       } else
+                               strcpy(cdptr[i]->controllers[j], temp);
+               }
+               j++;
+       } while (temp);
+
+       /* Store path to the cgroup */
+       strcpy(cdptr[i]->path, pathptr);
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       int ret = 0, i;
+       int cg_specified = 0;
+       uid_t euid;
+       pid_t pid;
+       gid_t egid;
+       char c;
+       struct cgroup_data *cgroup_list[CG_HIER_MAX];
+
+       if (argc < 2) {
+               fprintf(stderr, "Usage is %s"
+                       " [-g <list of controllers>:<relative path to cgroup>]"
+                       " command [arguments]  \n",
+                       argv[0]);
+               exit(2);
+       }
+
+       memset(cgroup_list, 0, sizeof(cgroup_list));
+
+       while ((c = getopt(argc, argv, "+g:")) > 0) {
+               switch (c) {
+               case 'g':
+                       if (parse_cgroup_data(cgroup_list, optarg)) {
+                               fprintf(stderr, "cgroup controller and path"
+                                               "parsing failed\n");
+                               return -1;
+                       }
+                       cg_specified = 1;
+                       break;
+               default:
+                       fprintf(stderr, "Invalid command line option\n");
+                       exit(1);
+                       break;
+               }
+       }
+
+       /* Executable name */
+       if (!argv[optind]) {
+               fprintf(stderr, "No command specified\n");
+               exit(1);
+       }
+
+       /* Initialize libcg */
+       ret = cgroup_init();
+       if (ret) {
+               fprintf(stderr, "libcgroup initialization failed:%d", ret);
+               return ret;
+       }
+
+       euid = geteuid();
+       egid = getegid();
+       pid = getpid();
+
+       if (cg_specified) {
+               /*
+                * User has specified the list of control group and
+                * controllers
+                * */
+               for (i = 0; i < CG_HIER_MAX; i++) {
+                       if (!cgroup_list[i])
+                               break;
+
+                       ret = cgroup_change_cgroup_path(cgroup_list[i]->path,
+                                                       pid,
+                                               cgroup_list[i]->controllers);
+                       if (ret) {
+                               fprintf(stderr,
+                                       "cgroup change of group failed\n");
+                               return ret;
+                       }
+               }
+       } else {
+
+               /* Change the cgroup by determining the rules based on euid */
+               ret = cgroup_change_cgroup_uid_gid(euid, egid, pid);
+               if (ret) {
+                       fprintf(stderr, "cgroup change of group failed\n");
+                       return ret;
+               }
+       }
+
+       /* Now exec the new process */
+       ret = execvp(argv[optind], &argv[optind]);
+       if (ret == -1) {
+               fprintf(stderr, "%s", strerror(errno));
+               return -1;
+       }
+       return 0;
+}