aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--init/Config.in15
-rw-r--r--init/init.c189
2 files changed, 96 insertions, 108 deletions
diff --git a/init/Config.in b/init/Config.in
index 4c5610246..f525abc8a 100644
--- a/init/Config.in
+++ b/init/Config.in
@@ -47,15 +47,18 @@ config FEATURE_KILL_DELAY
wrong process!)
config FEATURE_INIT_SCTTY
- bool "Support running commands with a controlling-tty"
+ bool "Run commands with leading dash with controlling tty"
default n
depends on INIT
help
- If this option is enabled a command starting with hyphen (-)
- is run in its own session (setsid(2)) and possibly with a
- controlling tty (TIOCSCTTY). This is not the traditional init
- behavour, but is often what you want in an embedded system where
- the console is only accessed during development or for maintenance.
+ If this option is enabled, init will try to give a controlling
+ tty to any command which has leading hyphen (often it's "-/bin/sh").
+ More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)".
+ If device attached to STDIN_FILENO can be a ctty but is not yet
+ a ctty for other session, it will become this process' ctty.
+ This is not the traditional init behavour, but is often what you want
+ in an embedded system where the console is only accessed during
+ development or for maintenance.
NB: using cttyhack applet may work better.
config FEATURE_INIT_SYSLOG
diff --git a/init/init.c b/init/init.c
index 080c5b3af..8d706fe1f 100644
--- a/init/init.c
+++ b/init/init.c
@@ -14,7 +14,7 @@
#include <paths.h>
#include <sys/reboot.h>
-#define INIT_BUFFS_SIZE 256
+#define COMMAND_SIZE 256
#define CONSOLE_NAME_SIZE 32
#define MAXENV 16 /* Number of env. vars */
@@ -55,9 +55,9 @@
struct init_action {
struct init_action *next;
pid_t pid;
- uint8_t action;
+ uint8_t action_type;
char terminal[CONSOLE_NAME_SIZE];
- char command[INIT_BUFFS_SIZE];
+ char command[COMMAND_SIZE];
};
/* Static variables */
@@ -294,14 +294,57 @@ static void open_stdio_to_tty(const char* tty_name, int exit_on_failure)
set_sane_term();
}
+/* wrapper around exec:
+ * takes string (max COMMAND_SIZE chars)
+ * runs [-]/bin/sh -c "exec ......." if '>' etc detected.
+ * otherwise splits words on whitespace and deals with leading dash.
+ */
+static void init_exec(const char *command)
+{
+ char *cmd[COMMAND_SIZE / 2];
+ char buf[COMMAND_SIZE + 6]; /* COMMAND_SIZE+strlen("exec ")+1 */
+ int dash = (command[0] == '-');
+
+ /* See if any special /bin/sh requiring characters are present */
+ if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
+ strcpy(buf, "exec ");
+ strcpy(buf + 5, command + dash); /* excluding "-" */
+ /* LIBBB_DEFAULT_LOGIN_SHELL has leading dash */
+ cmd[0] = (char*)(LIBBB_DEFAULT_LOGIN_SHELL + !dash);
+ cmd[1] = (char*)"-c";
+ cmd[2] = buf;
+ cmd[3] = NULL;
+ } else {
+ /* Convert command (char*) into cmd (char**, one word per string) */
+ char *word, *next;
+ int i = 0;
+ next = strcpy(buf, command); /* including "-" */
+ while ((word = strsep(&next, " \t")) != NULL) {
+ if (*word != '\0') { /* not two spaces/tabs together? */
+ cmd[i] = word;
+ i++;
+ }
+ }
+ cmd[i] = NULL;
+ }
+ /* If we saw leading "-", it is interactive shell.
+ * Try harder to give it a controlling tty.
+ * And skip "-" in actual exec call. */
+ if (dash) {
+ /* _Attempt_ to make stdin a controlling tty. */
+ if (ENABLE_FEATURE_INIT_SCTTY)
+ ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/);
+ }
+ BB_EXECVP(cmd[0] + dash, cmd);
+ message(L_LOG | L_CONSOLE, "Cannot run '%s': %s",
+ cmd[0], strerror(errno));
+ /* returns if execvp fails */
+}
+
/* Used only by run_actions */
static pid_t run(const struct init_action *a)
{
- int i;
pid_t pid;
- char *s, *tmpCmd, *cmdpath;
- char *cmd[INIT_BUFFS_SIZE];
- char buf[INIT_BUFFS_SIZE + 6]; /* INIT_BUFFS_SIZE+strlen("exec ")+1 */
sigset_t nmask, omask;
/* Block sigchild while forking (why?) */
@@ -341,7 +384,7 @@ static pid_t run(const struct init_action *a)
#ifdef BUT_RUN_ACTIONS_ALREADY_DOES_WAITING
/* If the init Action requires us to wait, then force the
* supplied terminal to be the controlling tty. */
- if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
+ if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
/* Now fork off another process to just hang around */
pid = fork();
if (pid < 0) {
@@ -381,58 +424,7 @@ static pid_t run(const struct init_action *a)
/* Child - fall though to actually execute things */
}
#endif
-
- /* See if any special /bin/sh requiring characters are present */
- if (strpbrk(a->command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
- cmd[0] = (char*)DEFAULT_SHELL;
- cmd[1] = (char*)"-c";
- cmd[2] = strcat(strcpy(buf, "exec "), a->command);
- cmd[3] = NULL;
- } else {
- /* Convert command (char*) into cmd (char**, one word per string) */
- strcpy(buf, a->command);
- s = buf;
- for (tmpCmd = buf, i = 0; (tmpCmd = strsep(&s, " \t")) != NULL;) {
- if (*tmpCmd != '\0') {
- cmd[i] = tmpCmd;
- i++;
- }
- }
- cmd[i] = NULL;
- }
-
- cmdpath = cmd[0];
-
- /*
- * Interactive shells want to see a dash in argv[0]. This
- * typically is handled by login, argv will be setup this
- * way if a dash appears at the front of the command path
- * (like "-/bin/sh").
- */
- if (*cmdpath == '-') {
- /* skip over the dash */
- ++cmdpath;
-
-#ifdef WHY_WE_DO_THIS_SHELL_MUST_HANDLE_THIS_ITSELF
- /* find the last component in the command pathname */
- s = bb_get_last_path_component_nostrip(cmdpath);
- /* make a new argv[0] */
- cmd[0] = malloc(strlen(s) + 2);
- if (cmd[0] == NULL) {
- message(L_LOG | L_CONSOLE, bb_msg_memory_exhausted);
- cmd[0] = cmdpath;
- } else {
- cmd[0][0] = '-';
- strcpy(cmd[0] + 1, s);
- }
-#endif
-
- /* _Attempt_ to make stdin a controlling tty. */
- if (ENABLE_FEATURE_INIT_SCTTY)
- ioctl(0, TIOCSCTTY, 0 /*only try, don't steal*/);
- }
-
- if (a->action & ASKFIRST) {
+ if (a->action_type & ASKFIRST) {
static const char press_enter[] ALIGN1 =
#ifdef CUSTOMIZED_BANNER
#include CUSTOMIZED_BANNER
@@ -449,58 +441,54 @@ static pid_t run(const struct init_action *a)
*/
messageD(L_LOG, "waiting for enter to start '%s'"
"(pid %d, tty '%s')\n",
- cmdpath, getpid(), a->terminal);
+ a->command, getpid(), a->terminal);
full_write(1, press_enter, sizeof(press_enter) - 1);
while (safe_read(0, &c, 1) == 1 && c != '\n')
continue;
}
- /* Log the process name and args */
- message(L_LOG, "starting pid %d, tty '%s': '%s'",
- getpid(), a->terminal, cmdpath);
-
if (ENABLE_FEATURE_INIT_COREDUMPS) {
struct stat sb;
if (stat(CORE_ENABLE_FLAG_FILE, &sb) == 0) {
struct rlimit limit;
-
limit.rlim_cur = RLIM_INFINITY;
limit.rlim_max = RLIM_INFINITY;
setrlimit(RLIMIT_CORE, &limit);
}
}
+ /* Log the process name and args */
+ message(L_LOG, "starting pid %d, tty '%s': '%s'",
+ getpid(), a->terminal, a->command);
+
/* Now run it. The new program will take over this PID,
* so nothing further in init.c should be run. */
- BB_EXECVP(cmdpath, cmd);
-
+ init_exec(a->command);
/* We're still here? Some error happened. */
- message(L_LOG | L_CONSOLE, "Cannot run '%s': %s",
- cmdpath, strerror(errno));
_exit(-1);
}
/* Run all commands of a particular type */
-static void run_actions(int action)
+static void run_actions(int action_type)
{
struct init_action *a, *tmp;
for (a = init_action_list; a; a = tmp) {
tmp = a->next;
- if (a->action == action) {
+ if (a->action_type == action_type) {
// Pointless: run() will error out if open of device fails.
///* a->terminal of "" means "init's console" */
//if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) {
// //message(L_LOG | L_CONSOLE, "Device %s cannot be opened in RW mode", a->terminal /*, strerror(errno)*/);
// delete_init_action(a);
//} else
- if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
+ if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
waitfor(run(a));
delete_init_action(a);
- } else if (a->action & ONCE) {
+ } else if (a->action_type & ONCE) {
run(a);
delete_init_action(a);
- } else if (a->action & (RESPAWN | ASKFIRST)) {
+ } else if (a->action_type & (RESPAWN | ASKFIRST)) {
/* Only run stuff with pid==0. If they have
* a pid, that means it is still running */
if (a->pid == 0) {
@@ -593,12 +581,11 @@ static void halt_reboot_pwoff(int sig)
* else (no such action defined) do nothing */
static void exec_restart_action(int sig ATTRIBUTE_UNUSED)
{
- struct init_action *a, *tmp;
+ struct init_action *a;
sigset_t unblock_signals;
- for (a = init_action_list; a; a = tmp) {
- tmp = a->next;
- if (a->action & RESTART) {
+ for (a = init_action_list; a; a = a->next) {
+ if (a->action_type & RESTART) {
kill_all_processes();
/* unblock all signals (blocked in kill_all_processes()) */
@@ -620,10 +607,7 @@ static void exec_restart_action(int sig ATTRIBUTE_UNUSED)
open_stdio_to_tty(a->terminal, 0 /* - halt if open fails */);
messageD(L_CONSOLE | L_LOG, "Trying to re-exec %s", a->command);
- BB_EXECLP(a->command, a->command, NULL);
-
- message(L_CONSOLE | L_LOG, "Cannot run '%s': %s",
- a->command, strerror(errno));
+ init_exec(a->command);
sleep(2);
init_reboot(RB_HALT_SYSTEM);
loop_forever();
@@ -654,12 +638,13 @@ static void cont_handler(int sig ATTRIBUTE_UNUSED)
got_cont = 1;
}
-static void new_init_action(uint8_t action, const char *command, const char *cons)
+static void new_init_action(uint8_t action_type, const char *command, const char *cons)
{
- struct init_action *new_action, *a, *last;
+ struct init_action *a, *last;
- if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST))
- return;
+// Why?
+// if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST))
+// return;
/* Append to the end of the list */
for (a = last = init_action_list; a; a = a->next) {
@@ -668,23 +653,23 @@ static void new_init_action(uint8_t action, const char *command, const char *con
if ((strcmp(a->command, command) == 0)
&& (strcmp(a->terminal, cons) == 0)
) {
- a->action = action;
+ a->action_type = action_type;
return;
}
last = a;
}
- new_action = xzalloc(sizeof(struct init_action));
+ a = xzalloc(sizeof(*a));
if (last) {
- last->next = new_action;
+ last->next = a;
} else {
- init_action_list = new_action;
+ init_action_list = a;
}
- strcpy(new_action->command, command);
- new_action->action = action;
- strcpy(new_action->terminal, cons);
+ a->action_type = action_type;
+ safe_strncpy(a->command, command, sizeof(a->command));
+ safe_strncpy(a->terminal, cons, sizeof(a->terminal));
messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",
- new_action->command, new_action->action, new_action->terminal);
+ a->command, a->action_type, a->terminal);
}
static void delete_init_action(struct init_action *action)
@@ -714,7 +699,7 @@ static void delete_init_action(struct init_action *action)
static void parse_inittab(void)
{
FILE *file;
- char buf[INIT_BUFFS_SIZE];
+ char buf[COMMAND_SIZE];
if (ENABLE_FEATURE_USE_INITTAB)
file = fopen(INITTAB, "r");
@@ -743,7 +728,7 @@ static void parse_inittab(void)
return;
}
- while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) {
+ while (fgets(buf, COMMAND_SIZE, file) != NULL) {
static const char actions[] =
STR_SYSINIT "sysinit\0"
STR_RESPAWN "respawn\0"
@@ -810,7 +795,7 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED)
/* disable old entrys */
for (a = init_action_list; a; a = a->next) {
- a->action = ONCE;
+ a->action_type = ONCE;
}
parse_inittab();
@@ -819,7 +804,7 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED)
/* Be nice and send SIGTERM first */
for (a = init_action_list; a; a = a->next) {
pid_t pid = a->pid;
- if ((a->action & ONCE) && pid != 0) {
+ if ((a->action_type & ONCE) && pid != 0) {
kill(pid, SIGTERM);
}
}
@@ -828,7 +813,7 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED)
sleep(CONFIG_FEATURE_KILL_DELAY);
for (a = init_action_list; a; a = a->next) {
pid_t pid = a->pid;
- if ((a->action & ONCE) && pid != 0) {
+ if ((a->action_type & ONCE) && pid != 0) {
kill(pid, SIGKILL);
}
}
@@ -840,7 +825,7 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED)
/* remove unused entrys */
for (a = init_action_list; a; a = tmp) {
tmp = a->next;
- if ((a->action & (ONCE | SYSINIT | WAIT)) && a->pid == 0) {
+ if ((a->action_type & (ONCE | SYSINIT | WAIT)) && a->pid == 0) {
delete_init_action(a);
}
}
@@ -998,7 +983,7 @@ int init_main(int argc, char **argv)
* restarted by run_actions() */
a->pid = 0;
message(L_LOG, "process '%s' (pid %d) exited. "
- "Scheduling it for restart.",
+ "Scheduling for restart.",
a->command, wpid);
}
}