diff options
-rw-r--r-- | Makefile.in | 11 | ||||
-rw-r--r-- | cgexec.c | 193 |
2 files changed, 201 insertions, 3 deletions
diff --git a/Makefile.in b/Makefile.in index aeab421..ba6a7a3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 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; +} |