Punt the rc_strcatpaths function and use snprintf instead to save on expensive malloc calls.

This commit is contained in:
Roy Marples
2008-03-17 13:25:56 +00:00
parent 50a7697bf2
commit 4c14666423
14 changed files with 682 additions and 745 deletions

View File

@@ -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 */