Punt the rc_strcatpaths function and use snprintf instead to save on expensive malloc calls.
This commit is contained in:
@@ -79,7 +79,7 @@ void rc_plugin_load(void)
|
||||
DIR *dp;
|
||||
struct dirent *d;
|
||||
PLUGIN *plugin;
|
||||
char *p;
|
||||
char file[PATH_MAX];
|
||||
void *h;
|
||||
int (*fptr)(RC_HOOK, const char *);
|
||||
|
||||
@@ -96,9 +96,8 @@ void rc_plugin_load(void)
|
||||
if (d->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
p = rc_strcatpaths(RC_PLUGINDIR, d->d_name, NULL);
|
||||
h = dlopen(p, RTLD_LAZY);
|
||||
free(p);
|
||||
snprintf(file, sizeof(file), RC_PLUGINDIR "/%s", d->d_name);
|
||||
h = dlopen(file, RTLD_LAZY);
|
||||
if (! h) {
|
||||
eerror("dlopen: %s", dlerror());
|
||||
continue;
|
||||
|
524
src/rc/rc.c
524
src/rc/rc.c
@@ -633,6 +633,116 @@ static void do_coldplug(void)
|
||||
printf ("%s\n", ecolor(ECOLOR_NORMAL));
|
||||
}
|
||||
|
||||
static void do_newlevel(const char *newlevel)
|
||||
{
|
||||
struct utsname uts;
|
||||
const char *sys;
|
||||
#ifdef __linux__
|
||||
char *cmd;
|
||||
#endif
|
||||
|
||||
if (strcmp(newlevel, RC_LEVEL_SYSINIT) == 0
|
||||
#ifndef PREFIX
|
||||
&& RUNLEVEL &&
|
||||
(strcmp(RUNLEVEL, "S") == 0 ||
|
||||
strcmp(RUNLEVEL, "1") == 0)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* OK, we're either in runlevel 1 or single user mode */
|
||||
|
||||
/* exec init-early.sh if it exists
|
||||
* This should just setup the console to use the correct
|
||||
* font. Maybe it should setup the keyboard too? */
|
||||
if (exists(INITEARLYSH))
|
||||
run_script(INITEARLYSH);
|
||||
|
||||
uname(&uts);
|
||||
printf("\n %sOpenRC %s" VERSION "%s is starting up %s",
|
||||
ecolor(ECOLOR_GOOD), ecolor(ECOLOR_HILITE),
|
||||
ecolor(ECOLOR_NORMAL), ecolor(ECOLOR_BRACKET));
|
||||
#ifdef BRANDING
|
||||
printf(BRANDING " (%s)", uts.machine);
|
||||
#else
|
||||
printf("%s %s (%s)",
|
||||
uts.sysname,
|
||||
uts.release,
|
||||
uts.machine);
|
||||
#endif
|
||||
|
||||
if ((sys = rc_sys()))
|
||||
printf(" [%s]", sys);
|
||||
|
||||
printf("%s\n\n", ecolor(ECOLOR_NORMAL));
|
||||
|
||||
if (! rc_yesno(getenv ("EINFO_QUIET")) &&
|
||||
rc_conf_yesno("rc_interactive"))
|
||||
printf("Press %sI%s to enter interactive boot mode\n\n",
|
||||
ecolor(ECOLOR_GOOD), ecolor(ECOLOR_NORMAL));
|
||||
|
||||
setenv("RC_SOFTLEVEL", newlevel, 1);
|
||||
rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, newlevel);
|
||||
hook_out = RC_HOOK_RUNLEVEL_START_OUT;
|
||||
run_script(INITSH);
|
||||
|
||||
#ifdef __linux__
|
||||
/* If we requested a softlevel, save it now */
|
||||
set_ksoftlevel(NULL);
|
||||
if ((cmd = proc_getent("softlevel"))) {
|
||||
set_ksoftlevel(cmd);
|
||||
free(cmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setup our coldplugged services now */
|
||||
do_coldplug();
|
||||
|
||||
rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, newlevel);
|
||||
hook_out = 0;
|
||||
|
||||
if (want_interactive())
|
||||
mark_interactive();
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (strcmp(newlevel, RC_LEVEL_SINGLE) == 0) {
|
||||
#ifndef PREFIX
|
||||
if (! RUNLEVEL ||
|
||||
(strcmp(RUNLEVEL, "S") != 0 &&
|
||||
strcmp(RUNLEVEL, "1") != 0))
|
||||
{
|
||||
/* Remember the current runlevel for when we come back */
|
||||
set_ksoftlevel(runlevel);
|
||||
single_user();
|
||||
}
|
||||
#endif
|
||||
} else if (strcmp(newlevel, RC_LEVEL_REBOOT) == 0) {
|
||||
if (! RUNLEVEL ||
|
||||
strcmp(RUNLEVEL, "6") != 0)
|
||||
{
|
||||
rc_logger_close();
|
||||
execl(SHUTDOWN, SHUTDOWN, "-r", "now", (char *) NULL);
|
||||
eerrorx("%s: unable to exec `" SHUTDOWN "': %s",
|
||||
applet, strerror(errno));
|
||||
}
|
||||
} else if (strcmp(newlevel, RC_LEVEL_SHUTDOWN) == 0) {
|
||||
if (! RUNLEVEL ||
|
||||
strcmp(RUNLEVEL, "0") != 0)
|
||||
{
|
||||
rc_logger_close();
|
||||
execl(SHUTDOWN, SHUTDOWN,
|
||||
#ifdef __linux__
|
||||
"-h",
|
||||
#else
|
||||
"-p",
|
||||
#endif
|
||||
"now", (char *) NULL);
|
||||
eerrorx("%s: unable to exec `" SHUTDOWN "': %s",
|
||||
applet, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool runlevel_config(const char *service, const char *level)
|
||||
{
|
||||
char *init = rc_service_resolve(service);
|
||||
@@ -651,6 +761,140 @@ static bool runlevel_config(const char *service, const char *level)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void do_stop_services(const char *newlevel, bool going_down, bool parallel)
|
||||
{
|
||||
pid_t pid;
|
||||
RC_STRING *service, *svc1, *svc2;
|
||||
RC_STRINGLIST *deporder, *tmplist;
|
||||
|
||||
if (! types_n) {
|
||||
types_n = rc_stringlist_new();
|
||||
rc_stringlist_add(types_n, "needsme");
|
||||
}
|
||||
|
||||
TAILQ_FOREACH_REVERSE(service, stop_services, rc_stringlist, entries)
|
||||
{
|
||||
if (rc_service_state(service->value) & RC_SERVICE_STOPPED)
|
||||
continue;
|
||||
|
||||
/* We always stop the service when in these runlevels */
|
||||
if (going_down) {
|
||||
pid = rc_service_stop(service->value);
|
||||
if (pid > 0 && ! parallel)
|
||||
rc_waitpid(pid);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we're in the start list then don't bother stopping us */
|
||||
TAILQ_FOREACH(svc1, start_services, entries)
|
||||
if (strcmp (svc1->value, service->value) == 0)
|
||||
break;
|
||||
|
||||
if (svc1) {
|
||||
if (newlevel && strcmp(runlevel, newlevel) != 0) {
|
||||
/* So we're in the start list. But we should
|
||||
* be stopped if we have a runlevel
|
||||
* configuration file for either the current
|
||||
* or next so we use the correct one. */
|
||||
if (! runlevel_config(service->value, runlevel) &&
|
||||
! runlevel_config(service->value, newlevel))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We got this far! Or last check is to see if any any service
|
||||
* that going to be started depends on us */
|
||||
if (! svc1) {
|
||||
tmplist = rc_stringlist_new();
|
||||
rc_stringlist_add(tmplist, service->value);
|
||||
deporder = rc_deptree_depends(deptree, types_n, tmplist,
|
||||
runlevel, RC_DEP_STRICT);
|
||||
rc_stringlist_free(tmplist);
|
||||
svc2 = NULL;
|
||||
TAILQ_FOREACH (svc1, deporder, entries) {
|
||||
TAILQ_FOREACH(svc2, start_services, entries)
|
||||
if (strcmp (svc1->value, svc2->value) == 0)
|
||||
break;
|
||||
if (svc2)
|
||||
break;
|
||||
}
|
||||
rc_stringlist_free(deporder);
|
||||
|
||||
if (svc2)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* After all that we can finally stop the blighter! */
|
||||
pid = rc_service_stop(service->value);
|
||||
if (pid > 0) {
|
||||
add_pid(pid);
|
||||
if (! parallel) {
|
||||
rc_waitpid(pid);
|
||||
remove_pid(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_start_services(bool parallel)
|
||||
{
|
||||
RC_STRING *service;
|
||||
pid_t pid;
|
||||
bool interactive = false;
|
||||
|
||||
if (! rc_yesno(getenv("EINFO_QUIET")))
|
||||
interactive = exists(INTERACTIVE);
|
||||
|
||||
TAILQ_FOREACH(service, start_services, entries) {
|
||||
if (rc_service_state(service->value) & RC_SERVICE_STOPPED) {
|
||||
if (! interactive)
|
||||
interactive = want_interactive();
|
||||
|
||||
if (interactive) {
|
||||
interactive_retry:
|
||||
printf("\n");
|
||||
einfo("About to start the service %s",
|
||||
service->value);
|
||||
eindent();
|
||||
einfo("1) Start the service\t\t2) Skip the service");
|
||||
einfo("3) Continue boot process\t\t4) Exit to shell");
|
||||
eoutdent();
|
||||
interactive_option:
|
||||
switch (read_key(true)) {
|
||||
case '1': break;
|
||||
case '2': continue;
|
||||
case '3': interactive = false; break;
|
||||
case '4': sulogin(true); goto interactive_retry;
|
||||
default: goto interactive_option;
|
||||
}
|
||||
}
|
||||
|
||||
pid = rc_service_start(service->value);
|
||||
|
||||
/* Remember the pid if we're running in parallel */
|
||||
if (pid > 0) {
|
||||
add_pid(pid);
|
||||
|
||||
if (! parallel) {
|
||||
rc_waitpid(pid);
|
||||
remove_pid(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Store our interactive status for boot */
|
||||
if (interactive && strcmp(runlevel, getenv("RC_BOOTLEVEL")) == 0)
|
||||
mark_interactive();
|
||||
else {
|
||||
if (exists(INTERACTIVE))
|
||||
unlink(INTERACTIVE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "_usage.h"
|
||||
#define getoptstring "o:" getoptstring_COMMON
|
||||
static const struct option longopts[] = {
|
||||
@@ -666,25 +910,18 @@ static const char * const longopts_help[] = {
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bootlevel = NULL;
|
||||
const char *sys = rc_sys();
|
||||
char *newlevel = NULL;
|
||||
RC_STRINGLIST *deporder = NULL;
|
||||
RC_STRINGLIST *tmplist;
|
||||
RC_STRING *service;
|
||||
bool going_down = false;
|
||||
bool interactive = false;
|
||||
int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
|
||||
char ksoftbuffer [PATH_MAX];
|
||||
char pidstr[6];
|
||||
int opt;
|
||||
bool parallel;
|
||||
int regen = 0;
|
||||
pid_t pid;
|
||||
RC_STRING *svc1;
|
||||
RC_STRING *svc2 = NULL;
|
||||
struct utsname uts;
|
||||
#ifdef __linux__
|
||||
char *cmd;
|
||||
char *proc;
|
||||
char *p;
|
||||
char *token;
|
||||
@@ -698,8 +935,8 @@ int main(int argc, char **argv)
|
||||
|
||||
if (argc > 1 && (strcmp(argv[1], "--version") == 0)) {
|
||||
printf("%s (OpenRC", applet);
|
||||
if (sys)
|
||||
printf(" [%s]", sys);
|
||||
if ((bootlevel = rc_sys()))
|
||||
printf(" [%s]", bootlevel);
|
||||
printf(") " VERSION
|
||||
#ifdef BRANDING
|
||||
" (" BRANDING ")"
|
||||
@@ -765,8 +1002,6 @@ int main(int argc, char **argv)
|
||||
signal_setup(SIGUSR1, handle_signal);
|
||||
signal_setup(SIGWINCH, handle_signal);
|
||||
|
||||
if (! rc_yesno(getenv("EINFO_QUIET")))
|
||||
interactive = exists(INTERACTIVE);
|
||||
rc_plugin_load();
|
||||
|
||||
/* Check we're in the runlevel requested, ie from
|
||||
@@ -774,107 +1009,8 @@ int main(int argc, char **argv)
|
||||
* rc shutdown
|
||||
* rc reboot
|
||||
*/
|
||||
if (newlevel) {
|
||||
if (strcmp(newlevel, RC_LEVEL_SYSINIT) == 0
|
||||
#ifndef PREFIX
|
||||
&& RUNLEVEL &&
|
||||
(strcmp(RUNLEVEL, "S") == 0 ||
|
||||
strcmp(RUNLEVEL, "1") == 0)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* OK, we're either in runlevel 1 or single user mode */
|
||||
|
||||
/* exec init-early.sh if it exists
|
||||
* This should just setup the console to use the correct
|
||||
* font. Maybe it should setup the keyboard too? */
|
||||
if (exists(INITEARLYSH))
|
||||
run_script(INITEARLYSH);
|
||||
|
||||
uname(&uts);
|
||||
printf("\n %sOpenRC %s" VERSION "%s is starting up %s",
|
||||
ecolor(ECOLOR_GOOD), ecolor(ECOLOR_HILITE),
|
||||
ecolor(ECOLOR_NORMAL), ecolor(ECOLOR_BRACKET));
|
||||
#ifdef BRANDING
|
||||
printf(BRANDING " (%s)", uts.machine);
|
||||
#else
|
||||
printf("%s %s (%s)",
|
||||
uts.sysname,
|
||||
uts.release,
|
||||
uts.machine);
|
||||
#endif
|
||||
|
||||
if (sys)
|
||||
printf(" [%s]", sys);
|
||||
|
||||
printf("%s\n\n", ecolor(ECOLOR_NORMAL));
|
||||
|
||||
if (! rc_yesno(getenv ("EINFO_QUIET")) &&
|
||||
rc_conf_yesno("rc_interactive"))
|
||||
printf("Press %sI%s to enter interactive boot mode\n\n",
|
||||
ecolor(ECOLOR_GOOD), ecolor(ECOLOR_NORMAL));
|
||||
|
||||
setenv("RC_SOFTLEVEL", newlevel, 1);
|
||||
rc_plugin_run(RC_HOOK_RUNLEVEL_START_IN, newlevel);
|
||||
hook_out = RC_HOOK_RUNLEVEL_START_OUT;
|
||||
run_script(INITSH);
|
||||
|
||||
#ifdef __linux__
|
||||
/* If we requested a softlevel, save it now */
|
||||
set_ksoftlevel(NULL);
|
||||
if ((cmd = proc_getent("softlevel"))) {
|
||||
set_ksoftlevel(cmd);
|
||||
free(cmd);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setup our coldplugged services now */
|
||||
do_coldplug();
|
||||
|
||||
rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, newlevel);
|
||||
hook_out = 0;
|
||||
|
||||
if (want_interactive())
|
||||
mark_interactive();
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (strcmp(newlevel, RC_LEVEL_SINGLE) == 0) {
|
||||
#ifndef PREFIX
|
||||
if (! RUNLEVEL ||
|
||||
(strcmp(RUNLEVEL, "S") != 0 &&
|
||||
strcmp(RUNLEVEL, "1") != 0))
|
||||
{
|
||||
/* Remember the current runlevel for when we come back */
|
||||
set_ksoftlevel(runlevel);
|
||||
single_user();
|
||||
}
|
||||
#endif
|
||||
} else if (strcmp(newlevel, RC_LEVEL_REBOOT) == 0) {
|
||||
if (! RUNLEVEL ||
|
||||
strcmp(RUNLEVEL, "6") != 0)
|
||||
{
|
||||
rc_logger_close();
|
||||
execl(SHUTDOWN, SHUTDOWN, "-r", "now", (char *) NULL);
|
||||
eerrorx("%s: unable to exec `" SHUTDOWN "': %s",
|
||||
applet, strerror(errno));
|
||||
}
|
||||
} else if (strcmp(newlevel, RC_LEVEL_SHUTDOWN) == 0) {
|
||||
if (! RUNLEVEL ||
|
||||
strcmp(RUNLEVEL, "0") != 0)
|
||||
{
|
||||
rc_logger_close();
|
||||
execl(SHUTDOWN, SHUTDOWN,
|
||||
#ifdef __linux__
|
||||
"-h",
|
||||
#else
|
||||
"-p",
|
||||
#endif
|
||||
"now", (char *) NULL);
|
||||
eerrorx("%s: unable to exec `" SHUTDOWN "': %s",
|
||||
applet, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newlevel)
|
||||
do_newlevel(newlevel);
|
||||
|
||||
/* Now we start handling our children */
|
||||
signal_setup(SIGCHLD, handle_signal);
|
||||
@@ -946,15 +1082,23 @@ int main(int argc, char **argv)
|
||||
* correct order for stopping them */
|
||||
stop_services = rc_services_in_state(RC_SERVICE_STARTED);
|
||||
tmplist = rc_services_in_state(RC_SERVICE_INACTIVE);
|
||||
TAILQ_CONCAT(stop_services, tmplist, entries);
|
||||
free(tmplist);
|
||||
if (tmplist) {
|
||||
if (stop_services) {
|
||||
TAILQ_CONCAT(stop_services, tmplist, entries);
|
||||
free(tmplist);
|
||||
} else
|
||||
stop_services = tmplist;
|
||||
}
|
||||
tmplist = rc_services_in_state(RC_SERVICE_STARTING);
|
||||
TAILQ_CONCAT(stop_services, tmplist, entries);
|
||||
free(tmplist);
|
||||
if (tmplist) {
|
||||
if (stop_services) {
|
||||
TAILQ_CONCAT(stop_services, tmplist, entries);
|
||||
free(tmplist);
|
||||
} else
|
||||
stop_services = tmplist;
|
||||
}
|
||||
rc_stringlist_sort(&stop_services);
|
||||
|
||||
types_n = rc_stringlist_new();
|
||||
rc_stringlist_add(types_n, "needsme");
|
||||
|
||||
types_nua = rc_stringlist_new();
|
||||
rc_stringlist_add(types_nua, "ineed");
|
||||
@@ -976,12 +1120,18 @@ int main(int argc, char **argv)
|
||||
start_services = rc_services_in_runlevel(bootlevel);
|
||||
if (strcmp (newlevel ? newlevel : runlevel, bootlevel) != 0) {
|
||||
tmplist = rc_services_in_runlevel(newlevel ? newlevel : runlevel);
|
||||
TAILQ_CONCAT(start_services, tmplist, entries);
|
||||
free(tmplist);
|
||||
if (tmplist) {
|
||||
if (start_services) {
|
||||
TAILQ_CONCAT(start_services, tmplist, entries);
|
||||
free(tmplist);
|
||||
} else
|
||||
start_services = tmplist;
|
||||
}
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(service, coldplugged_services, entries)
|
||||
rc_stringlist_addu(start_services, service->value);
|
||||
if (coldplugged_services)
|
||||
TAILQ_FOREACH(service, coldplugged_services, entries)
|
||||
rc_stringlist_addu(start_services, service->value);
|
||||
}
|
||||
|
||||
/* Save our softlevel now */
|
||||
@@ -991,69 +1141,8 @@ int main(int argc, char **argv)
|
||||
parallel = rc_conf_yesno("rc_parallel");
|
||||
|
||||
/* Now stop the services that shouldn't be running */
|
||||
TAILQ_FOREACH_REVERSE(service, stop_services, rc_stringlist, entries) {
|
||||
if (rc_service_state(service->value) & RC_SERVICE_STOPPED)
|
||||
continue;
|
||||
|
||||
/* We always stop the service when in these runlevels */
|
||||
if (going_down) {
|
||||
pid = rc_service_stop(service->value);
|
||||
if (pid > 0 && ! parallel)
|
||||
rc_waitpid(pid);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we're in the start list then don't bother stopping us */
|
||||
TAILQ_FOREACH(svc1, start_services, entries)
|
||||
if (strcmp (svc1->value, service->value) == 0)
|
||||
break;
|
||||
|
||||
if (svc1) {
|
||||
if (newlevel && strcmp(runlevel, newlevel) != 0) {
|
||||
/* So we're in the start list. But we should
|
||||
* be stopped if we have a runlevel
|
||||
* configuration file for either the current
|
||||
* or next so we use the correct one. */
|
||||
if (! runlevel_config(service->value, runlevel) &&
|
||||
! runlevel_config(service->value, newlevel))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We got this far! Or last check is to see if any any service
|
||||
* that going to be started depends on us */
|
||||
if (! svc1) {
|
||||
tmplist = rc_stringlist_new();
|
||||
rc_stringlist_add(tmplist, service->value);
|
||||
deporder = rc_deptree_depends(deptree, types_n, tmplist,
|
||||
runlevel, RC_DEP_STRICT);
|
||||
rc_stringlist_free(tmplist);
|
||||
svc2 = NULL;
|
||||
TAILQ_FOREACH (svc1, deporder, entries) {
|
||||
TAILQ_FOREACH(svc2, start_services, entries)
|
||||
if (strcmp (svc1->value, svc2->value) == 0)
|
||||
break;
|
||||
if (svc2)
|
||||
break;
|
||||
}
|
||||
rc_stringlist_free(deporder);
|
||||
|
||||
if (svc2)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* After all that we can finally stop the blighter! */
|
||||
pid = rc_service_stop(service->value);
|
||||
if (pid > 0) {
|
||||
add_pid(pid);
|
||||
if (! parallel) {
|
||||
rc_waitpid(pid);
|
||||
remove_pid(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stop_services)
|
||||
do_stop_services(newlevel, parallel, going_down);
|
||||
|
||||
/* Wait for our services to finish */
|
||||
wait_for_services();
|
||||
@@ -1094,15 +1183,18 @@ int main(int argc, char **argv)
|
||||
hook_out = RC_HOOK_RUNLEVEL_START_OUT;
|
||||
|
||||
/* Re-add our coldplugged services if they stopped */
|
||||
TAILQ_FOREACH(service, coldplugged_services, entries)
|
||||
rc_service_mark(service->value, RC_SERVICE_COLDPLUGGED);
|
||||
if (coldplugged_services)
|
||||
TAILQ_FOREACH(service, coldplugged_services, entries)
|
||||
rc_service_mark(service->value, RC_SERVICE_COLDPLUGGED);
|
||||
|
||||
/* Order the services to start */
|
||||
rc_stringlist_sort(&start_services);
|
||||
deporder = rc_deptree_depends(deptree, types_nua, start_services,
|
||||
if (start_services) {
|
||||
rc_stringlist_sort(&start_services);
|
||||
deporder = rc_deptree_depends(deptree, types_nua, start_services,
|
||||
runlevel, depoptions | RC_DEP_START);
|
||||
rc_stringlist_free(start_services);
|
||||
start_services = deporder;
|
||||
rc_stringlist_free(start_services);
|
||||
start_services = deporder;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
/* mark any services skipped as started */
|
||||
@@ -1116,47 +1208,13 @@ int main(int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
TAILQ_FOREACH(service, start_services, entries) {
|
||||
if (rc_service_state(service->value) & RC_SERVICE_STOPPED) {
|
||||
if (! interactive)
|
||||
interactive = want_interactive();
|
||||
if (start_services) {
|
||||
do_start_services(parallel);
|
||||
|
||||
if (interactive) {
|
||||
interactive_retry:
|
||||
printf("\n");
|
||||
einfo("About to start the service %s",
|
||||
service->value);
|
||||
eindent();
|
||||
einfo("1) Start the service\t\t2) Skip the service");
|
||||
einfo("3) Continue boot process\t\t4) Exit to shell");
|
||||
eoutdent();
|
||||
interactive_option:
|
||||
switch (read_key(true)) {
|
||||
case '1': break;
|
||||
case '2': continue;
|
||||
case '3': interactive = false; break;
|
||||
case '4': sulogin(true); goto interactive_retry;
|
||||
default: goto interactive_option;
|
||||
}
|
||||
}
|
||||
|
||||
pid = rc_service_start(service->value);
|
||||
|
||||
/* Remember the pid if we're running in parallel */
|
||||
if (pid > 0) {
|
||||
add_pid(pid);
|
||||
|
||||
if (! parallel) {
|
||||
rc_waitpid(pid);
|
||||
remove_pid(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Wait for our services to finish */
|
||||
wait_for_services();
|
||||
}
|
||||
|
||||
/* Wait for our services to finish */
|
||||
wait_for_services();
|
||||
|
||||
rc_plugin_run(RC_HOOK_RUNLEVEL_START_OUT, runlevel);
|
||||
hook_out = 0;
|
||||
|
||||
@@ -1172,14 +1230,6 @@ interactive_option:
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Store our interactive status for boot */
|
||||
if (interactive && strcmp(runlevel, bootlevel) == 0)
|
||||
mark_interactive();
|
||||
else {
|
||||
if (exists(INTERACTIVE))
|
||||
unlink(INTERACTIVE);
|
||||
}
|
||||
|
||||
/* If we're in the boot runlevel and we regenerated our dependencies
|
||||
* we need to delete them so that they are regenerated again in the
|
||||
* default runlevel as they may depend on things that are now available */
|
||||
|
@@ -82,8 +82,8 @@ static RC_STRINGLIST *use_services = NULL;
|
||||
static RC_STRINGLIST *services = NULL;
|
||||
static RC_STRINGLIST *tmplist = NULL;
|
||||
static char *service = NULL;
|
||||
static char *exclusive = NULL;
|
||||
static char *mtime_test = NULL;
|
||||
static char exclusive[PATH_MAX] = { '\0' };
|
||||
static char mtime_test[PATH_MAX] = { '\0' };
|
||||
static RC_DEPTREE *deptree = NULL;
|
||||
static char *runlevel = NULL;
|
||||
static bool sighup = false;
|
||||
@@ -212,7 +212,7 @@ static const char *const tests[] = {
|
||||
};
|
||||
static bool in_control()
|
||||
{
|
||||
char *path;
|
||||
char file[PATH_MAX];
|
||||
time_t m;
|
||||
time_t mtime;
|
||||
int i = 0;
|
||||
@@ -230,15 +230,12 @@ static bool in_control()
|
||||
return false;
|
||||
|
||||
while (tests[i]) {
|
||||
path = rc_strcatpaths(RC_SVCDIR, tests[i], applet, (char *) NULL);
|
||||
if (exists(path)) {
|
||||
m = get_mtime(path, false);
|
||||
if (mtime < m && m != 0) {
|
||||
free(path);
|
||||
snprintf(file, sizeof(file), RC_SVCDIR "/%s/%s", tests[i], applet);
|
||||
if (exists(file)) {
|
||||
m = get_mtime(file, false);
|
||||
if (mtime < m && m != 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
free(path);
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -247,10 +244,11 @@ static bool in_control()
|
||||
|
||||
static void uncoldplug()
|
||||
{
|
||||
char *cold = rc_strcatpaths(RC_SVCDIR, "coldplugged", applet, (char *) NULL);
|
||||
if (exists(cold) && unlink(cold) != 0)
|
||||
eerror("%s: unlink `%s': %s", applet, cold, strerror(errno));
|
||||
free(cold);
|
||||
char file[PATH_MAX];
|
||||
|
||||
snprintf(file, sizeof(file), RC_SVCDIR "/coldplugged/%s", applet);
|
||||
if (exists(file) && unlink(file) != 0)
|
||||
eerror("%s: unlink `%s': %s", applet, file, strerror(errno));
|
||||
}
|
||||
|
||||
static void start_services(RC_STRINGLIST *list) {
|
||||
@@ -305,10 +303,10 @@ static void restore_state(void)
|
||||
rc_service_mark(applet, RC_SERVICE_FAILED);
|
||||
}
|
||||
|
||||
if (exclusive)
|
||||
if (*exclusive) {
|
||||
unlink(exclusive);
|
||||
free(exclusive);
|
||||
exclusive = NULL;
|
||||
*exclusive = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanup(void)
|
||||
@@ -347,17 +345,12 @@ static void cleanup(void)
|
||||
rc_stringlist_free(applet_list);
|
||||
rc_stringlist_free(tmplist);
|
||||
free (ibsave);
|
||||
|
||||
if (mtime_test)
|
||||
{
|
||||
if (! rc_in_plugin)
|
||||
unlink(mtime_test);
|
||||
free(mtime_test);
|
||||
}
|
||||
free(exclusive);
|
||||
free(service);
|
||||
free(prefix);
|
||||
free(runlevel);
|
||||
|
||||
if (*mtime_test && ! rc_in_plugin)
|
||||
unlink(mtime_test);
|
||||
}
|
||||
|
||||
static int write_prefix(const char *buffer, size_t bytes, bool *prefixed) {
|
||||
@@ -580,37 +573,29 @@ static RC_SERVICE svc_status(void)
|
||||
|
||||
static void make_exclusive(void)
|
||||
{
|
||||
char *path;
|
||||
size_t l;
|
||||
|
||||
/* We create a fifo so that other services can wait until we complete */
|
||||
if (! exclusive)
|
||||
exclusive = rc_strcatpaths(RC_SVCDIR, "exclusive", applet, (char *) NULL);
|
||||
if (! *exclusive)
|
||||
snprintf(exclusive, sizeof(exclusive), RC_SVCDIR "/exclusive/%s",
|
||||
applet);
|
||||
|
||||
if (mkfifo(exclusive, 0600) != 0 && errno != EEXIST &&
|
||||
(errno != EACCES || geteuid () == 0))
|
||||
eerrorx ("%s: unable to create fifo `%s': %s",
|
||||
applet, exclusive, strerror(errno));
|
||||
|
||||
path = rc_strcatpaths(RC_SVCDIR, "exclusive", applet, (char *) NULL);
|
||||
l = strlen (path) + 16;
|
||||
mtime_test = xmalloc(sizeof (char) * l);
|
||||
snprintf(mtime_test, l, "%s.%d", path, getpid());
|
||||
free(path);
|
||||
snprintf(mtime_test, sizeof(mtime_test), RC_SVCDIR "/exclusive/%s.%d", applet, getpid());
|
||||
|
||||
if (exists(mtime_test) && unlink(mtime_test) != 0) {
|
||||
eerror("%s: unlink `%s': %s",
|
||||
applet, mtime_test, strerror(errno));
|
||||
free(mtime_test);
|
||||
mtime_test = NULL;
|
||||
*mtime_test = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
if (symlink(service, mtime_test) != 0) {
|
||||
eerror("%s: symlink `%s' to `%s': %s",
|
||||
applet, service, mtime_test, strerror(errno));
|
||||
free(mtime_test);
|
||||
mtime_test = NULL;
|
||||
*mtime_test = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,8 +603,7 @@ static void unlink_mtime_test(void)
|
||||
{
|
||||
if (unlink(mtime_test) != 0)
|
||||
eerror("%s: unlink `%s': %s", applet, mtime_test, strerror(errno));
|
||||
free(mtime_test);
|
||||
mtime_test = NULL;
|
||||
*mtime_test = '\0';
|
||||
}
|
||||
|
||||
static void get_started_services(void)
|
||||
@@ -627,8 +611,13 @@ static void get_started_services(void)
|
||||
RC_STRINGLIST *tmp = rc_services_in_state(RC_SERVICE_INACTIVE);
|
||||
rc_stringlist_free(restart_services);
|
||||
restart_services = rc_services_in_state(RC_SERVICE_STARTED);
|
||||
TAILQ_CONCAT(restart_services, tmp, entries);
|
||||
free(tmp);
|
||||
if (tmp) {
|
||||
if (restart_services) {
|
||||
TAILQ_CONCAT(restart_services, tmp, entries);
|
||||
free(tmp);
|
||||
} else
|
||||
restart_services = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_types(void)
|
||||
@@ -713,8 +702,8 @@ static void svc_start(bool deps)
|
||||
|
||||
services = rc_deptree_depends(deptree, types_b, applet_list,
|
||||
runlevel, 0);
|
||||
if (TAILQ_FIRST(services)) {
|
||||
eerrorn ("ERROR: `%s' needs ", applet);
|
||||
if (services && TAILQ_FIRST(services)) {
|
||||
eerrorn("ERROR: `%s' needs ", applet);
|
||||
first = true;
|
||||
TAILQ_FOREACH(svc, services, entries) {
|
||||
if (first)
|
||||
@@ -733,7 +722,7 @@ static void svc_start(bool deps)
|
||||
use_services = rc_deptree_depends(deptree, types_nu, applet_list,
|
||||
runlevel, depoptions);
|
||||
|
||||
if (! rc_runlevel_starting())
|
||||
if (! rc_runlevel_starting() && use_services)
|
||||
TAILQ_FOREACH(svc, use_services, entries)
|
||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) {
|
||||
pid_t pid = rc_service_start(svc->value);
|
||||
@@ -746,8 +735,7 @@ static void svc_start(bool deps)
|
||||
runlevel, depoptions);
|
||||
|
||||
/* We use tmplist to hold our scheduled by list */
|
||||
tmplist = rc_stringlist_new();
|
||||
|
||||
tmplist = NULL;
|
||||
TAILQ_FOREACH(svc, services, entries) {
|
||||
RC_SERVICE svcs = rc_service_state(svc->value);
|
||||
if (svcs & RC_SERVICE_STARTED)
|
||||
@@ -768,14 +756,19 @@ static void svc_start(bool deps)
|
||||
if (! svc_wait(svc->value))
|
||||
eerror ("%s: timed out waiting for %s",
|
||||
applet, svc->value);
|
||||
if (! need_services)
|
||||
continue;
|
||||
if ((svcs = rc_service_state(svc->value)) & RC_SERVICE_STARTED)
|
||||
continue;
|
||||
TAILQ_FOREACH(svc2, need_services, entries) {
|
||||
if (strcmp (svc->value, svc2->value) == 0) {
|
||||
if (svcs & RC_SERVICE_INACTIVE ||
|
||||
svcs & RC_SERVICE_WASINACTIVE)
|
||||
rc_stringlist_add(tmplist, svc->value);
|
||||
else
|
||||
{
|
||||
if (! tmplist)
|
||||
tmplist = rc_stringlist_new();
|
||||
rc_stringlist_add(tmplist, svc->value);
|
||||
} else
|
||||
eerrorx("ERROR: cannot start %s as"
|
||||
" %s would not start",
|
||||
applet, svc->value);
|
||||
@@ -783,7 +776,7 @@ static void svc_start(bool deps)
|
||||
}
|
||||
}
|
||||
|
||||
if (TAILQ_FIRST(tmplist)) {
|
||||
if (tmplist && TAILQ_FIRST(tmplist)) {
|
||||
/* Set the state now, then unlink our exclusive so that
|
||||
our scheduled list is preserved */
|
||||
rc_service_mark(service, RC_SERVICE_STOPPED);
|
||||
@@ -813,14 +806,14 @@ static void svc_start(bool deps)
|
||||
p += snprintf(p, len, "%s", svc->value);
|
||||
}
|
||||
free(tmp);
|
||||
rc_stringlist_free(tmplist);
|
||||
tmplist = NULL;
|
||||
ewarnx("WARNING: %s is scheduled to start when %s has started",
|
||||
applet, tmp);
|
||||
applet, tmp);
|
||||
}
|
||||
|
||||
rc_stringlist_free(services);
|
||||
services = NULL;
|
||||
rc_stringlist_free(tmplist);
|
||||
tmplist = NULL;
|
||||
}
|
||||
|
||||
if (ibsave)
|
||||
@@ -928,65 +921,73 @@ static void svc_stop(bool deps)
|
||||
if (! types_m)
|
||||
setup_types();
|
||||
|
||||
tmplist = rc_stringlist_new();
|
||||
tmplist = NULL;
|
||||
services = rc_deptree_depends(deptree, types_m, applet_list,
|
||||
runlevel, depoptions);
|
||||
TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) {
|
||||
RC_SERVICE svcs = rc_service_state(svc->value);
|
||||
if (svcs & RC_SERVICE_STARTED ||
|
||||
svcs & RC_SERVICE_INACTIVE)
|
||||
{
|
||||
svc_wait(svc->value);
|
||||
svcs = rc_service_state(svc->value);
|
||||
if (services) {
|
||||
TAILQ_FOREACH_REVERSE(svc, services, rc_stringlist, entries) {
|
||||
RC_SERVICE svcs = rc_service_state(svc->value);
|
||||
if (svcs & RC_SERVICE_STARTED ||
|
||||
svcs & RC_SERVICE_INACTIVE)
|
||||
svcs & RC_SERVICE_INACTIVE)
|
||||
{
|
||||
pid_t pid = rc_service_stop(svc->value);
|
||||
if (! rc_conf_yesno("rc_parallel"))
|
||||
rc_waitpid(pid);
|
||||
rc_stringlist_add(tmplist, svc->value);
|
||||
svc_wait(svc->value);
|
||||
svcs = rc_service_state(svc->value);
|
||||
if (svcs & RC_SERVICE_STARTED ||
|
||||
svcs & RC_SERVICE_INACTIVE)
|
||||
{
|
||||
pid_t pid = rc_service_stop(svc->value);
|
||||
if (! rc_conf_yesno("rc_parallel"))
|
||||
rc_waitpid(pid);
|
||||
if (! tmplist)
|
||||
tmplist = rc_stringlist_new();
|
||||
rc_stringlist_add(tmplist, svc->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
rc_stringlist_free(services);
|
||||
services = NULL;
|
||||
}
|
||||
rc_stringlist_free(services);
|
||||
services = NULL;
|
||||
|
||||
TAILQ_FOREACH(svc, tmplist, entries) {
|
||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
||||
continue;
|
||||
if (tmplist) {
|
||||
TAILQ_FOREACH(svc, tmplist, entries) {
|
||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
||||
continue;
|
||||
|
||||
/* We used to loop 3 times here - maybe re-do this if needed */
|
||||
svc_wait(svc->value);
|
||||
if (! (rc_service_state(svc->value) & RC_SERVICE_STOPPED)) {
|
||||
if (rc_runlevel_stopping()) {
|
||||
/* If shutting down, we should stop even
|
||||
* if a dependant failed */
|
||||
if (runlevel &&
|
||||
(strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
|
||||
strcmp(runlevel, RC_LEVEL_REBOOT) == 0 ||
|
||||
strcmp(runlevel, RC_LEVEL_SINGLE) == 0))
|
||||
continue;
|
||||
rc_service_mark(service, RC_SERVICE_FAILED);
|
||||
/* We used to loop 3 times here - maybe re-do this if needed */
|
||||
svc_wait(svc->value);
|
||||
if (! (rc_service_state(svc->value) & RC_SERVICE_STOPPED)) {
|
||||
if (rc_runlevel_stopping()) {
|
||||
/* If shutting down, we should stop even
|
||||
* if a dependant failed */
|
||||
if (runlevel &&
|
||||
(strcmp(runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
|
||||
strcmp(runlevel, RC_LEVEL_REBOOT) == 0 ||
|
||||
strcmp(runlevel, RC_LEVEL_SINGLE) == 0))
|
||||
continue;
|
||||
rc_service_mark(service, RC_SERVICE_FAILED);
|
||||
}
|
||||
|
||||
eerrorx("ERROR: cannot stop %s as %s is still up",
|
||||
applet, svc->value);
|
||||
}
|
||||
|
||||
eerrorx("ERROR: cannot stop %s as %s is still up",
|
||||
applet, svc->value);
|
||||
}
|
||||
rc_stringlist_free(tmplist);
|
||||
tmplist = NULL;
|
||||
}
|
||||
rc_stringlist_free(tmplist);
|
||||
tmplist = NULL;
|
||||
|
||||
/* We now wait for other services that may use us and are stopping
|
||||
This is important when a runlevel stops */
|
||||
services = rc_deptree_depends(deptree, types_mua, applet_list,
|
||||
runlevel, depoptions);
|
||||
TAILQ_FOREACH(svc, services, entries) {
|
||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
||||
continue;
|
||||
svc_wait(svc->value);
|
||||
if (services) {
|
||||
TAILQ_FOREACH(svc, services, entries) {
|
||||
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
|
||||
continue;
|
||||
svc_wait(svc->value);
|
||||
}
|
||||
rc_stringlist_free (services);
|
||||
services = NULL;
|
||||
}
|
||||
rc_stringlist_free (services);
|
||||
services = NULL;
|
||||
}
|
||||
|
||||
/* If we're stopping localmount, set LC_ALL=C so that
|
||||
@@ -1114,8 +1115,8 @@ int runscript(int argc, char **argv)
|
||||
eerror("%s: cannot run until sysvinit completes", applet);
|
||||
if (mkdir("/dev/.rcboot", 0755) != 0 && errno != EEXIST)
|
||||
eerrorx("%s: mkdir `/dev/.rcboot': %s", applet, strerror(errno));
|
||||
prefix = rc_strcatpaths("/dev/.rcboot", applet, (char *) NULL);
|
||||
symlink(service, prefix);
|
||||
snprintf(exclusive, sizeof(exclusive), "/dev/.rcboot/%s", applet);
|
||||
symlink(service, exclusive);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
@@ -51,6 +51,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
@@ -590,6 +591,7 @@ int start_stop_daemon(int argc, char **argv)
|
||||
bool setuser = false;
|
||||
char *p;
|
||||
char *tmp;
|
||||
char exec_file[PATH_MAX];
|
||||
struct passwd *pw;
|
||||
struct group *gr;
|
||||
char line[130];
|
||||
@@ -773,14 +775,13 @@ int start_stop_daemon(int argc, char **argv)
|
||||
|
||||
/* Validate that the binary exists if we are starting */
|
||||
if (exec) {
|
||||
if (ch_root)
|
||||
tmp = rc_strcatpaths(ch_root, exec, (char *) NULL);
|
||||
else
|
||||
if (ch_root) {
|
||||
snprintf(exec_file, sizeof(exec_file), "%s/%s", ch_root, exec);
|
||||
tmp = exec_file;
|
||||
} else
|
||||
tmp = exec;
|
||||
if (start && ! exists(tmp)) {
|
||||
eerror("%s: %s does not exist", applet, tmp);
|
||||
if (ch_root)
|
||||
free(tmp);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -807,15 +808,10 @@ int start_stop_daemon(int argc, char **argv)
|
||||
applet, line + 2, exec);
|
||||
eerror("%s: or you should specify a pidfile"
|
||||
" or process name", applet);
|
||||
if (ch_root)
|
||||
free(tmp);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ch_root)
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
/* Add exec to our arguments */
|
||||
|
Reference in New Issue
Block a user