summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.in11
-rw-r--r--cgexec.c193
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;
+}