diff --git a/chkconfig.8 b/chkconfig.8 index b677b844..1f27abc8 100644 --- a/chkconfig.8 +++ b/chkconfig.8 @@ -4,17 +4,17 @@ chkconfig \- updates and queries runlevel information for system services .SH SYNOPSIS -\fBchkconfig\fR [\fB--list\fR] [\fB--type\fR \fItype\fR] [\fIname\fR] +\fBchkconfig\fR [\fB--root\fR \fIpath\fR] [\fB--list\fR] [\fB--type\fR \fItype\fR] [\fIname\fR] .br -\fBchkconfig\fR \fB--add\fR \fIname\fR +\fBchkconfig\fR [\fB--root\fR \fIpath\fR] \fB--add\fR \fIname\fR .br -\fBchkconfig\fR \fB--del\fR \fIname\fR +\fBchkconfig\fR [\fB--root\fR \fIpath\fR] \fB--del\fR \fIname\fR .br -\fBchkconfig\fR \fB--override\fR \fIname\fR +\fBchkconfig\fR [\fB--root\fR \fIpath\fR] \fB--override\fR \fIname\fR .br -\fBchkconfig\fR [\fB--level\fR \fIlevels\fR] [\fB--type\fR \fItype\fR] [\fB--no-redirect\fR] \fIname\fR <\fBon\fR|\fBoff\fR|\fBreset\fR|\fBresetpriorities\fR> +\fBchkconfig\fR [\fB--level\fR \fIlevels\fR] [\fB--root\fR \fIpath\fR] [\fB--type\fR \fItype\fR] [\fB--no-redirect\fR] \fIname\fR <\fBon\fR|\fBoff\fR|\fBreset\fR|\fBresetpriorities\fR> .br -\fBchkconfig\fR [\fB--level\fR \fIlevels\fR] [\fB--type\fR \fItype\fR] [\fB--no-redirect\fR] \fIname\fR +\fBchkconfig\fR [\fB--level\fR \fIlevels\fR] [\fB--root\fR \fIpath\fR] [\fB--type\fR \fItype\fR] [\fB--no-redirect\fR] \fIname\fR .br .SH DESCRIPTION @@ -80,6 +80,11 @@ Specifies the run levels an operation should pertain to. It is given as a string of numbers from 0 to 6. For example, \fB--level 35\fR specifies runlevels 3 and 5. +.TP +\fB-\-root \fIpath\fR +When used with on/off, use alternative root path when looking for unit +files same as by \fBsystemctl\fR. + .TP \fB-\-no-redirect\fR When chkconfig is run on a system that uses systemd as its init system, diff --git a/chkconfig.c b/chkconfig.c index 96646606..ce9b7ebe 100644 --- a/chkconfig.c +++ b/chkconfig.c @@ -44,18 +44,18 @@ static void usage(char *name) { "the GNU Public License.\n")); fprintf(stderr, "\n"); if (!strcmp(name, "install_initd") || !strcmp(name, "remove_initd")) { - fprintf(stderr, _("usage: %s [name]\n"), progname); + fprintf(stderr, _("usage: %s [name] [--root ]\n"), progname); } else if (!strcmp(name, "systemd-sysv-install")) { - fprintf(stderr, _("usage: %s [name] \n"), + fprintf(stderr, _("usage: %s [name] [--root ] \n"), progname); } else { - fprintf(stderr, _("usage: %s [--list] [--type ] [name]\n"), + fprintf(stderr, _("usage: %s [--list] [--root ] [--type ] [name]\n"), progname); - fprintf(stderr, _(" %s --add \n"), progname); - fprintf(stderr, _(" %s --del \n"), progname); - fprintf(stderr, _(" %s --override \n"), progname); + fprintf(stderr, _(" %s --add [--root ]\n"), progname); + fprintf(stderr, _(" %s --del [--root ]\n"), progname); + fprintf(stderr, _(" %s --override [--root ]\n"), progname); fprintf(stderr, - _(" %s [--level ] [--type ] %s\n"), + _(" %s [--level ] [--root ] [--type ] %s\n"), progname, ""); } exit(1); @@ -106,13 +106,13 @@ static void reloadSystemd(void) { system("systemctl daemon-reload > /dev/null 2>&1"); } -static int delService(char *name, int type, int level) { +static int delService(char *name, int type, int level, char *root_path) { int i, j, k, numservs, rc; glob_t globres; struct service s; struct service *services; - if ((rc = readServiceInfo(name, type, &s, 0))) { + if ((rc = readServiceInfo(name, type, &s, 0, root_path))) { readServiceError(rc, name); return 1; } @@ -122,7 +122,7 @@ static int delService(char *name, int type, int level) { checkRoot(); if (LSB && level == -1) { - numservs = readServices(&services); + numservs = readServices(&services, root_path); if (numservs < 0) return 1; @@ -222,7 +222,7 @@ static void checkDeps(struct service *s, struct dep *deps, struct service *serv, } static int frobOneDependencies(struct service *s, struct service *servs, - int numservs, int target, int depfail) { + int numservs, int target, int depfail, char *root_path) { int i; int s0 = s->sPriority; int k0 = s->kPriority; @@ -274,12 +274,12 @@ static int frobOneDependencies(struct service *s, struct service *servs, int new_priority = on ? s->sPriority : s->kPriority; if (new_priority != priority || (on ? 'S' : 'K') != type) { - delService(s->name, TYPE_INIT_D, i); - doSetService(*s, i, on); + delService(s->name, TYPE_INIT_D, i, root_path); + doSetService(*s, i, on, root_path); } } else if (target) { - delService(s->name, TYPE_INIT_D, i); - doSetService(*s, i, ((1 << i) & s->levels)); + delService(s->name, TYPE_INIT_D, i, root_path); + doSetService(*s, i, ((1 << i) & s->levels), root_path); } } return 1; /* Resolved something */ @@ -290,13 +290,13 @@ static int frobOneDependencies(struct service *s, struct service *servs, /* LSB-style dependency frobber. Calculates a usable start priority * and stop priority. * This algorithm will almost certainly break horribly at some point. */ -static int frobDependencies(struct service *s) { +static int frobDependencies(struct service *s, char *root_path) { struct service *servs = NULL; int numservs = 0; int nResolved = 0; int i; - numservs = readServices(&servs); + numservs = readServices(&servs, root_path); if (numservs < 0) return 1; /* In the full service list, replace the target script's current @@ -313,21 +313,21 @@ static int frobDependencies(struct service *s) { for (i = 0; i < numservs; i++) { if ((servs + i)->isLSB) nResolved += - frobOneDependencies(servs + i, servs, numservs, 0, 0); + frobOneDependencies(servs + i, servs, numservs, 0, 0, root_path); } } while (nResolved); /* Resolve our target */ - if (frobOneDependencies(s, servs, numservs, 1, LSB) == -1) + if (frobOneDependencies(s, servs, numservs, 1, LSB, root_path) == -1) return 1; return 0; } -static int addService(char *name, int type) { +static int addService(char *name, int type, char *root_path) { int i, rc; struct service s; - if ((rc = readServiceInfo(name, type, &s, 0))) { + if ((rc = readServiceInfo(name, type, &s, 0, root_path))) { readServiceError(rc, name); return 1; } @@ -344,21 +344,21 @@ static int addService(char *name, int type) { if (i == 7) { s.currentLevels = s.levels; } - rc = frobDependencies(&s); + rc = frobDependencies(&s, root_path); } else for (i = 0; i < 7; i++) { if (!isConfigured(name, i, NULL, NULL)) { if ((1 << i) & s.levels) - doSetService(s, i, 1); + doSetService(s, i, 1, root_path); else - doSetService(s, i, 0); + doSetService(s, i, 0, root_path); } } return rc; } -static int overrideService(char *name, int srvtype) { +static int overrideService(char *name, int srvtype, char *root_path) { /* Apply overrides if available; no available overrides is no error */ int level, i, rc; glob_t globres; @@ -370,7 +370,7 @@ static int overrideService(char *name, int srvtype) { int configured = 0; int thisLevelAdded, thisLevelOn; - if ((rc = readServiceDifferences(name, srvtype, &s, &o, 0))) { + if ((rc = readServiceDifferences(name, srvtype, &s, &o, 0, root_path))) { return 0; } @@ -386,9 +386,9 @@ static int overrideService(char *name, int srvtype) { } if (s.isLSB && (s.sPriority <= -1) && (s.kPriority >= 100)) - frobDependencies(&s); + frobDependencies(&s, root_path); if ((s.isLSB || o.isLSB) && (o.sPriority <= -1) && (o.kPriority >= 100)) - frobDependencies(&o); + frobDependencies(&o, root_path); /* Apply overrides only if the service has not been changed since * being added, and not if the service has never been configured @@ -422,9 +422,9 @@ static int overrideService(char *name, int srvtype) { if (globres.gl_pathc) globfree(&globres); if ((1 << level) & o.levels) - doSetService(o, level, 1); + doSetService(o, level, 1, root_path); else - doSetService(o, level, 0); + doSetService(o, level, 0, root_path); } } } @@ -466,7 +466,7 @@ static int showServiceInfo(struct service s, int forgiving) { return 0; } -static int showServiceInfoByName(char *name, int type, int forgiving) { +static int showServiceInfoByName(char *name, int type, int forgiving, char *root_path) { int rc; struct service s; @@ -475,7 +475,7 @@ static int showServiceInfoByName(char *name, int type, int forgiving) { return forgiving ? 0 : 1; } - rc = readServiceInfo(name, type, &s, 0); + rc = readServiceInfo(name, type, &s, 0, root_path); if (rc) { if (!forgiving) @@ -486,13 +486,13 @@ static int showServiceInfoByName(char *name, int type, int forgiving) { return showServiceInfo(s, forgiving); } -static int isXinetdEnabled() { +static int isXinetdEnabled(char *root_path) { struct service s; if (isOverriddenBySystemd("xinetd") && isEnabledInSystemd("xinetd")) return 1; - if (readServiceInfo("xinetd", TYPE_INIT_D, &s, 0)) { + if (readServiceInfo("xinetd", TYPE_INIT_D, &s, 0, root_path)) { return 0; } if (s.currentLevels) @@ -511,7 +511,7 @@ static int xinetdNameCmp(const void *a, const void *b) { return strcmp(first->name, second->name); } -static int listService(char *item, int type) { +static int listService(char *item, int type, char *root_path) { DIR *dir; struct dirent *ent; struct service *services; @@ -522,10 +522,10 @@ static int listService(char *item, int type) { int systemd = systemdActive(); if (item) - return showServiceInfoByName(item, type, 0); + return showServiceInfoByName(item, type, 0, root_path); if (type & TYPE_INIT_D) { - numServices = readServices(&services); + numServices = readServices(&services, root_path); if (numServices < 0) return 1; @@ -540,13 +540,19 @@ static int listService(char *item, int type) { } } - if (isXinetdEnabled() && type & TYPE_XINETD) { + if (isXinetdEnabled(root_path) && type & TYPE_XINETD) { struct service *s, *t; + char *filename = NULL; printf("\n"); printf(_("xinetd based services:\n")); + if(root_path) { + sprintf(filename, "%s", root_path); + } else { + sprintf(filename, "%s", XINETDDIR); + } if (!(dir = opendir(XINETDDIR))) { - fprintf(stderr, _("failed to open directory %s: %s\n"), XINETDDIR, + fprintf(stderr, _("failed to open directory %s: %s\n"), filename, strerror(err)); return 1; } @@ -575,7 +581,7 @@ static int listService(char *item, int type) { numServicesAlloced += 10; s = realloc(s, numServicesAlloced * sizeof(*s)); } - if (readXinetdServiceInfo(ent->d_name, s + numServices) != -1) + if (readXinetdServiceInfo(ent->d_name, s + numServices, root_path) != -1) numServices++; } @@ -592,7 +598,7 @@ static int listService(char *item, int type) { return 0; } -int setService(char *name, int type, int where, int state) { +int setService(char *name, int type, int where, int state, char *root_path) { int i, rc; int what; struct service s; @@ -605,7 +611,7 @@ int setService(char *name, int type, int where, int state) { (1 << 5) | (1 << 6); } - if ((rc = readServiceInfo(name, type, &s, 0))) { + if ((rc = readServiceInfo(name, type, &s, 0, root_path))) { readServiceError(rc, name); return 1; } @@ -631,7 +637,7 @@ int setService(char *name, int type, int where, int state) { } } if (s.isLSB) - frobDependencies(&s); + frobDependencies(&s, root_path); for (i = 0; i < 7; i++) { if (!((1 << i) & where)) @@ -645,14 +651,14 @@ int setService(char *name, int type, int where, int state) { what = 1; else what = 0; - rc |= doSetService(s, i, what); + rc |= doSetService(s, i, what, root_path); } reloadSystemd(); return rc; } else if (s.type == TYPE_XINETD) { - if (setXinetdService(s, state)) { + if (setXinetdService(s, state, root_path)) { return 1; } system("/sbin/service xinetd reload >/dev/null 2>&1"); @@ -661,14 +667,19 @@ int setService(char *name, int type, int where, int state) { return 0; } -void forwardSystemd(const char *name, int type, const char *verb) { +void forwardSystemd(const char *name, int type, const char *verb, char *root_path) { int socket = 0; + char *root; if (type == TYPE_XINETD) return; if (!systemdIsInit()) return; + if(root_path) { + asprintf(&root, "--root=%s", root_path); + } + if (isOverriddenBySystemd(name) || (socket = isSocketActivatedBySystemd(name))) { char *p; @@ -681,7 +692,7 @@ void forwardSystemd(const char *name, int type, const char *verb) { fprintf(stderr, _("Note: Forwarding request to 'systemctl %s %s'.\n"), verb, p); - execlp("systemctl", "systemctl", verb, p, NULL); + execlp("systemctl", "systemctl", verb, p, root, NULL); free(p); fprintf(stderr, _("Failed to forward service request to systemctl: %m\n")); @@ -695,6 +706,7 @@ int main(int argc, const char **argv) { int type = TYPE_ANY; int rc, i, x; char *levels = NULL; + char *root_path = NULL; char *typeString = NULL; int help = 0, version = 0; struct service s; @@ -707,6 +719,7 @@ int main(int argc, const char **argv) { {"list", '\0', 0, &listItem, 0}, {"level", '\0', POPT_ARG_STRING, &levels, 0}, {"levels", '\0', POPT_ARG_STRING, &levels, 0}, + {"root", '\0', POPT_ARG_STRING, &root_path, 0}, {"type", '\0', POPT_ARG_STRING, &typeString, 0}, {"help", 'h', POPT_ARG_NONE, &help, 0}, {"version", 'v', POPT_ARG_NONE, &version, 0}, @@ -768,6 +781,12 @@ int main(int argc, const char **argv) { noRedirectItem = 1; } + if(root_path) { + if (*root_path != '/') { + usage(progname); + } + } + if (addItem) { char *name = (char *)poptGetArg(optCon); int r; @@ -776,7 +795,7 @@ int main(int argc, const char **argv) { usage(progname); name = basename(name); - r = addService(name, type); + r = addService(name, type, root_path); reloadSystemd(); return r; @@ -788,7 +807,7 @@ int main(int argc, const char **argv) { usage(progname); name = basename(name); - r = delService(name, type, -1); + r = delService(name, type, -1, root_path); reloadSystemd(); return r; @@ -800,7 +819,7 @@ int main(int argc, const char **argv) { usage(progname); name = basename(name); - r = overrideService(name, type); + r = overrideService(name, type, root_path); reloadSystemd(); return r; @@ -812,10 +831,10 @@ int main(int argc, const char **argv) { display_list_systemd_note(); - return listService(item, type); + return listService(item, type, root_path); } else if (argc == 1 && strcmp(progname, "systemd-sysv-install")) { display_list_systemd_note(); - return listService(NULL, type); + return listService(NULL, type, root_path); } else { char *name = (char *)poptGetArg(optCon); char *state = (char *)poptGetArg(optCon); @@ -854,7 +873,7 @@ int main(int argc, const char **argv) { if (!state) { if (!noRedirectItem && !levels) { - forwardSystemd(name, type, "is-enabled"); + forwardSystemd(name, type, "is-enabled", root_path); } if (where) { @@ -875,11 +894,11 @@ int main(int argc, const char **argv) { exit(1); } } - rc = readServiceInfo(name, type, &s, 0); + rc = readServiceInfo(name, type, &s, 0, root_path); if (rc) return 1; if (s.type == TYPE_XINETD) { - if (isXinetdEnabled()) + if (isXinetdEnabled(root_path)) return !s.levels; else return 1; @@ -890,18 +909,18 @@ int main(int argc, const char **argv) { } } else if (!strcmp(state, "on")) { if (!noRedirectItem) { - forwardSystemd(name, type, "enable"); + forwardSystemd(name, type, "enable", root_path); } - return setService(name, type, where, 1); + return setService(name, type, where, 1, root_path); } else if (!strcmp(state, "off")) { if (!noRedirectItem) { - forwardSystemd(name, type, "disable"); + forwardSystemd(name, type, "disable", root_path); } - return setService(name, type, where, 0); + return setService(name, type, where, 0, root_path); } else if (!strcmp(state, "reset")) - return setService(name, type, where, -1); + return setService(name, type, where, -1, root_path); else if (!strcmp(state, "resetpriorities")) - return setService(name, type, where, -2); + return setService(name, type, where, -2, root_path); } usage(progname); diff --git a/leveldb.c b/leveldb.c index 7b8c1bdd..aef03dc6 100644 --- a/leveldb.c +++ b/leveldb.c @@ -201,7 +201,7 @@ int readDescription(char *start, char *bufstop, char **english_desc, return 0; } -int readXinetdServiceInfo(char *name, struct service *service) { +int readXinetdServiceInfo(char *name, struct service *service, char *root_path) { char *filename; int fd; struct service serv = { @@ -223,7 +223,11 @@ int readXinetdServiceInfo(char *name, struct service *service) { char *buf = NULL, *ptr; char *eng_desc = NULL, *start; - asprintf(&filename, XINETDDIR "/%s", name); + if(root_path) { + asprintf(&filename, "%s/%s", root_path, name); + } else { + asprintf(&filename, XINETDDIR "/%s", name); + } if ((fd = open(filename, O_RDONLY)) < 0) goto out_err; @@ -309,16 +313,23 @@ int readXinetdServiceInfo(char *name, struct service *service) { return -1; } -int readServices(struct service **services) { +int readServices(struct service **services, char *root_path) { DIR *dir; struct dirent *ent; struct stat sb; struct service *servs = NULL; int numservs = 0; char fn[1024]; + char *filename = NULL; + + if(root_path) { + asprintf(&filename, "%s", root_path); + } else { + asprintf(&filename, "%s", RUNLEVELS "/init.d"); + } - if (!(dir = opendir(RUNLEVELS "/init.d"))) { - fprintf(stderr, _("failed to open %s/init.d: %s\n"), RUNLEVELS, + if (!(dir = opendir(filename))) { + fprintf(stderr, _("failed to open %s: %s\n"), filename, strerror(errno)); return -1; } @@ -340,14 +351,19 @@ int readServices(struct service **services) { if (*dn == '~' || *dn == ',') continue; - sprintf(fn, RUNLEVELS "/init.d/%s", ent->d_name); + if(root_path) { + sprintf(fn, "%s/%s", root_path, ent->d_name); + } else { + sprintf(fn, RUNLEVELS "/init.d/%s", ent->d_name); + } + if (stat(fn, &sb)) { continue; } if (!S_ISREG(sb.st_mode)) continue; servs = realloc(servs, (numservs + 1) * sizeof(struct service)); - if (!readServiceInfo(ent->d_name, TYPE_INIT_D, servs + numservs, 0)) + if (!readServiceInfo(ent->d_name, TYPE_INIT_D, servs + numservs, 0, root_path)) numservs++; } *services = servs; @@ -355,7 +371,7 @@ int readServices(struct service **services) { } int readServiceInfo(char *name, int type, struct service *service, - int honorHide) { + int honorHide, char *root_path) { char *filename = NULL; int fd; struct service serv, serv_overrides; @@ -364,7 +380,11 @@ int readServiceInfo(char *name, int type, struct service *service, if (!(type & TYPE_INIT_D)) goto try_xinetd; - asprintf(&filename, RUNLEVELS "/init.d/%s", name); + if(root_path) { + asprintf(&filename, "%s/%s", root_path, name); + } else { + asprintf(&filename, RUNLEVELS "/init.d/%s", name); + } if ((fd = open(filename, O_RDONLY)) < 0) goto try_xinetd; @@ -375,6 +395,7 @@ int readServiceInfo(char *name, int type, struct service *service, return parseret; asprintf(&filename, RUNLEVELS "/chkconfig.d/%s", name); + if ((fd = open(filename, O_RDONLY)) >= 0) { parseret = parseServiceInfo(fd, name, &serv_overrides, honorHide, 1); if (parseret >= 0) { @@ -412,11 +433,11 @@ int readServiceInfo(char *name, int type, struct service *service, free(filename); if (!(type & TYPE_XINETD)) return -1; - return readXinetdServiceInfo(name, service); + return readXinetdServiceInfo(name, service, root_path); } int readServiceDifferences(char *name, int type, struct service *service, - struct service *service_overrides, int honorHide) { + struct service *service_overrides, int honorHide, char *root_path) { char *filename = NULL; int fd; struct service serv, serv_overrides; @@ -425,7 +446,11 @@ int readServiceDifferences(char *name, int type, struct service *service, if (!(type & TYPE_INIT_D)) goto try_xinetd; - asprintf(&filename, RUNLEVELS "/init.d/%s", name); + if(root_path) { + asprintf(&filename, "%s/%s", root_path, name); + } else { + asprintf(&filename, RUNLEVELS "/init.d/%s", name); + } if ((fd = open(filename, O_RDONLY)) < 0) { goto try_xinetd; @@ -457,7 +482,7 @@ int readServiceDifferences(char *name, int type, struct service *service, free(filename); if (!(type & TYPE_XINETD)) return -1; - return readXinetdServiceInfo(name, service); + return readXinetdServiceInfo(name, service, root_path); } static struct dep *parseDeps(char *pos, char *end) { @@ -841,7 +866,7 @@ int whatLevels(char *name) { return ret; } -int setXinetdService(struct service s, int on) { +int setXinetdService(struct service s, int on, char *root_path) { int oldfd, newfd; char oldfname[100], newfname[100]; char tmpstr[50]; @@ -853,7 +878,11 @@ int setXinetdService(struct service s, int on) { if (on == -1) { on = s.enabled ? 1 : 0; } - snprintf(oldfname, 100, "%s/%s", XINETDDIR, s.name); + if(root_path) { + snprintf(oldfname, 100, "%s/%s", root_path, s.name); + } else { + snprintf(oldfname, 100, "%s/%s", XINETDDIR, s.name); + } if ((oldfd = open(oldfname, O_RDONLY)) == -1) { return -1; } @@ -866,7 +895,11 @@ int setXinetdService(struct service s, int on) { } close(oldfd); buf[sb.st_size] = '\0'; - snprintf(newfname, 100, "%s/%s.XXXXXX", XINETDDIR, s.name); + if(root_path) { + snprintf(newfname, 100, "%s/%s.XXXXXX", root_path, s.name); + } else { + snprintf(newfname, 100, "%s/%s.XXXXXX", XINETDDIR, s.name); + } mode = umask(S_IRWXG | S_IRWXO); newfd = mkstemp(newfname); umask(mode); @@ -903,7 +936,7 @@ int setXinetdService(struct service s, int on) { return (r); } -int doSetService(struct service s, int level, int on) { +int doSetService(struct service s, int level, int on, char *root_path) { int priority = on ? s.sPriority : s.kPriority; char linkname[200]; char linkto[200]; @@ -919,7 +952,11 @@ int doSetService(struct service s, int level, int on) { sprintf(linkname, "%s/rc%d.d/%c%02d%s", RUNLEVELS, level, on ? 'S' : 'K', priority, s.name); - sprintf(linkto, "../init.d/%s", s.name); + if(root_path) { + sprintf(linkto, "%s/%s", root_path, s.name); + } else { + sprintf(linkto, "../init.d/%s", s.name); + } unlink(linkname); /* just in case */ if (symlink(linkto, linkname)) { diff --git a/leveldb.h b/leveldb.h index e308d86e..15a968d6 100644 --- a/leveldb.h +++ b/leveldb.h @@ -59,20 +59,20 @@ int parseLevels(char *str, int emptyOk); /* returns 0 on success, 1 if the service is not chkconfig-able, -1 if an I/O error occurs (in which case errno can be checked) */ int readServiceInfo(char *name, int type, struct service *service, - int honorHide); -int readServices(struct service **services); + int honorHide, char *root_path); +int readServices(struct service **services, char *root_path); int readServiceDifferences(char *name, int type, struct service *service, - struct service *service_overrides, int honorHide); + struct service *service_overrides, int honorHide, char *root_path); int parseServiceInfo(int fd, char *name, struct service *service, int honorHide, int partialOk); int currentRunlevel(void); int isOn(char *name, int where); int isConfigured(char *name, int level, int *priority, char *type); int whatLevels(char *name); -int doSetService(struct service s, int level, int on); +int doSetService(struct service s, int level, int on, char *root_path); int findServiceEntries(char *name, int level, glob_t *globresptr); -int readXinetdServiceInfo(char *name, struct service *service); -int setXinetdService(struct service s, int on); +int readXinetdServiceInfo(char *name, struct service *service, char *root_path); +int setXinetdService(struct service s, int on, char *root_path); int systemdIsInit(); int systemdActive(); int isOverriddenBySystemd(const char *service); diff --git a/ntsysv.8 b/ntsysv.8 index 11192f94..7b9215c8 100644 --- a/ntsysv.8 +++ b/ntsysv.8 @@ -3,7 +3,7 @@ .SH NAME ntsysv \- simple interface for configuring runlevels .SH SYNOPSIS -\fBntsysv\fR [--back] [--level ] +\fBntsysv\fR [\fB--root\fR \fIpath\fR] [--back] [--level ] .SH DESCRIPTION \fBntsysv\fR is a simple interface for configuring runlevel services which are also configurable through \fBchkconfig\fR. By default, it configures @@ -18,6 +18,9 @@ in any of the runlevels which are being edited. The \fBntsysv\fR window normally contains a \fBCancel\fR button. If \fB--back\fR is specified, a \fBBack\fR button appears instead. +\fB-\-root \fIpath\fR is given, uses alternative root path when looking +for unit files same as by \fBsystemctl\fR. + .PD .SH "RETURN CODES" \fBntsysv\fR returns 0 on success, 2 on error, and 1 if the user cancelled diff --git a/ntsysv.c b/ntsysv.c index 3ab9c57a..a773f071 100644 --- a/ntsysv.c +++ b/ntsysv.c @@ -34,7 +34,7 @@ /* return 1 on cancel, 2 on error, 0 on success */ static int servicesWindow(struct service *services, int numServices, int levels, - int backButton) { + int backButton, char *root_path) { newtComponent label, subform, ok, cancel; newtComponent *checkboxes, form, curr, blank; newtComponent sb = NULL; @@ -153,7 +153,7 @@ static int servicesWindow(struct service *services, int numServices, int levels, if (services[i].type == TYPE_XINETD) { if ((services[i].enabled && states[i] != '*') || (!services[i].enabled && states[i] == '*')) - setXinetdService(services[i], states[i] == '*'); + setXinetdService(services[i], states[i] == '*', root_path); } else if (services[i].type == TYPE_SYSTEMD) { char *cmd = NULL; int en = 0; @@ -163,8 +163,14 @@ static int servicesWindow(struct service *services, int numServices, int levels, en = 1; else continue; - asprintf(&cmd, "/usr/bin/systemctl %s %s >/dev/null 2>&1", - en ? "enable" : "disable", services[i].name); + if(root_path) { + asprintf(&cmd, "/usr/bin/systemctl --root=%s %s %s >/dev/null 2>&1", + root_path, en ? "enable" : "disable", services[i].name); + } else { + asprintf(&cmd, "/usr/bin/systemctl %s %s >/dev/null 2>&1", + en ? "enable" : "disable", services[i].name); + } + if (cmd == NULL) return 1; system(cmd); @@ -172,7 +178,7 @@ static int servicesWindow(struct service *services, int numServices, int levels, } else { for (j = 0; j < 7; j++) { if (levels & (1 << j)) - doSetService(services[i], j, states[i] == '*'); + doSetService(services[i], j, states[i] == '*', root_path); } } } @@ -191,12 +197,13 @@ static int serviceNameCmp(const void *a, const void *b) { return strcmp(first->name, second->name); } -int getSystemdServices(struct service **servicesPtr, int *numServicesPtr) { +int getSystemdServices(struct service **servicesPtr, int *numServicesPtr, char *root_path) { FILE *sys = NULL; char service[UNIT_FILE_MAX + 1]; int i; int r = 0; int c = ' '; + char *cmd = NULL; struct service *services = NULL; struct service *p = NULL; int numServices = 0; @@ -207,7 +214,12 @@ int getSystemdServices(struct service **servicesPtr, int *numServicesPtr) { if (services == NULL) return -ENOMEM; - sys = popen("systemctl list-unit-files --no-legend --no-pager", "r"); + if(root_path) { + asprintf(&cmd, "systemctl --root=%s list-unit-files --no-legend --no-pager", root_path); + } else { + asprintf(&cmd, "systemctl list-unit-files --no-legend --no-pager"); + } + sys = popen(cmd, "r"); if (!sys) { r = -1; goto finish; @@ -301,11 +313,12 @@ int getSystemdServices(struct service **servicesPtr, int *numServicesPtr) { } static int getServices(struct service **servicesPtr, int *numServicesPtr, - int backButton, int honorHide) { + int backButton, int honorHide, char *root_path) { DIR *dir; struct dirent *ent; struct stat sb; char fn[1024]; + char *filename = NULL; struct service *services; int numServices = 0; int numServicesAlloced, rc; @@ -315,8 +328,14 @@ static int getServices(struct service **servicesPtr, int *numServicesPtr, numServicesAlloced = 10; services = malloc(sizeof(*services) * numServicesAlloced); - if (!(dir = opendir(RUNLEVELS "/init.d"))) { - fprintf(stderr, "failed to open " RUNLEVELS "/init.d: %s\n", + if(root_path) { + asprintf(&filename, "%s", root_path); + } else { + asprintf(&filename, RUNLEVELS "/init.d"); + } + + if (!(dir = opendir(filename))) { + fprintf(stderr, "failed to open %s: %s\n", filename, strerror(errno)); return 2; } @@ -328,7 +347,13 @@ static int getServices(struct service **servicesPtr, int *numServicesPtr, if (systemd && isOverriddenBySystemd(ent->d_name)) continue; - sprintf(fn, RUNLEVELS "/init.d/%s", ent->d_name); + + if(root_path) { + sprintf(fn, "%s/%s", root_path, ent->d_name); + } else { + sprintf(fn, RUNLEVELS "/init.d/%s", ent->d_name); + } + if (stat(fn, &sb)) { fprintf(stderr, _("error reading info for service %s: %s\n"), ent->d_name, strerror(errno)); @@ -344,7 +369,7 @@ static int getServices(struct service **servicesPtr, int *numServicesPtr, } rc = readServiceInfo(ent->d_name, TYPE_INIT_D, services + numServices, - honorHide); + honorHide, root_path); if (!rc) { int i; @@ -368,10 +393,16 @@ static int getServices(struct service **servicesPtr, int *numServicesPtr, closedir(dir); - if (!stat("/usr/sbin/xinetd", &sb)) { + if(root_path) { + asprintf(&filename, "%s", root_path); + } else { + asprintf(&filename, "/usr/sbin/xinetd"); + } + + if (!stat(filename, &sb)) { if (!(dir = opendir(XINETDDIR))) { - fprintf(stderr, "failed to open " XINETDDIR ": %s\n", - strerror(errno)); + fprintf(stderr, "failed to open %s: %s\n", + filename, strerror(errno)); return 2; } @@ -380,7 +411,7 @@ static int getServices(struct service **servicesPtr, int *numServicesPtr, strchr(ent->d_name, '.')) continue; - sprintf(fn, "%s/%s", XINETDDIR, ent->d_name); + sprintf(fn, "%s/%s", (root_path) ? root_path : XINETDDIR, ent->d_name); if (stat(fn, &sb)) { err = errno; continue; @@ -394,7 +425,7 @@ static int getServices(struct service **servicesPtr, int *numServicesPtr, realloc(services, numServicesAlloced * sizeof(*services)); } - rc = readXinetdServiceInfo(ent->d_name, services + numServices); + rc = readXinetdServiceInfo(ent->d_name, services + numServices, root_path); if (rc == -1) { fprintf(stderr, _("error reading info for service %s: %s\n"), @@ -407,12 +438,12 @@ static int getServices(struct service **servicesPtr, int *numServicesPtr, if (err) { fprintf(stderr, _("error reading from directory %s: %s\n"), - XINETDDIR, strerror(err)); + (root_path) ? root_path : XINETDDIR, strerror(err)); return 1; } } - getSystemdServices(&services, &numServices); + getSystemdServices(&services, &numServices, root_path); qsort(services, numServices, sizeof(*services), serviceNameCmp); @@ -427,12 +458,14 @@ int main(int argc, const char **argv) { int numServices; int levels = -1; char *levelsStr = NULL; + char *root_path = NULL; char *progName; poptContext optCon; int rc, backButton = 0, hide = 0; struct poptOption optionsTable[] = { {"back", '\0', 0, &backButton, 0}, {"level", '\0', POPT_ARG_STRING, &levelsStr, 0}, + {"root", '\0', POPT_ARG_STRING, &root_path, 0}, {"hide", '\0', 0, &hide, 0}, {0, 0, 0, 0, 0}}; @@ -457,6 +490,13 @@ int main(int argc, const char **argv) { exit(1); } + if(root_path) { + if (*root_path != '/') { + fprintf(stderr, _("bad argument to --root\n")); + exit(2); + } + } + if (levelsStr) { levels = parseLevels(levelsStr, 0); if (levels == -1) { @@ -465,7 +505,7 @@ int main(int argc, const char **argv) { } } - if (getServices(&services, &numServices, backButton, hide)) + if (getServices(&services, &numServices, backButton, hide, root_path)) return 1; if (!numServices) { fprintf(stderr, _("No services may be managed by ntsysv!\n")); @@ -481,7 +521,7 @@ int main(int argc, const char **argv) { if (levels == -1) levels = parseLevels("2345", 0); - rc = servicesWindow(services, numServices, levels, backButton); + rc = servicesWindow(services, numServices, levels, backButton, root_path); newtFinished();