Update docs for start_stop_daemon to match reality. Update the reality a bit to better match debian behavior.
No binary (build failed)
—
(log yok)
| @@ -23,21 +23,23 @@ | |
| static int signal_nr = 15; | |
| static int user_id = -1; | |
| + | static int quiet = 0; |
| static char *userspec = NULL; | |
| static char *cmdname = NULL; | |
| static char *execname = NULL; | |
| + | static char *pidfile = NULL; |
| - | typedef struct pid_list { |
| + | struct pid_list { |
| struct pid_list *next; | |
| - | int pid; |
| - | } pid_list; |
| + | pid_t pid; |
| + | }; |
| - | static pid_list *found = NULL; |
| + | static struct pid_list *found = NULL; |
| static inline void | |
| - | push(int pid) |
| + | push(pid_t pid) |
| { | |
| - | pid_list *p; |
| + | struct pid_list *p; |
| p = xmalloc(sizeof(*p)); | |
| p->next = found; | |
| @@ -46,21 +48,19 @@ push(int pid) | |
| } | |
| static int | |
| - | pid_is_exec(int pid, const char *exec) |
| + | pid_is_exec(pid_t pid, const char *name) |
| { | |
| - | char buf[PATH_MAX]; |
| - | FILE *fp; |
| - | |
| - | sprintf(buf, "/proc/%d/cmdline", pid); |
| - | fp = fopen(buf, "r"); |
| - | if (fp && fgets (buf, sizeof (buf), fp) ) { |
| - | fclose(fp); |
| - | if (strncmp (buf, exec, strlen(exec)) == 0) |
| - | return 1; |
| - | } |
| - | return 0; |
| - | } |
| + | char buf[32]; |
| + | struct stat sb, exec_stat; |
| + | if (name && stat(name, &exec_stat)) |
| + | bb_perror_msg_and_die("stat %s", name); |
| + | |
| + | sprintf(buf, "/proc/%d/exe", pid); |
| + | if (stat(buf, &sb) != 0) |
| + | return 0; |
| + | return (sb.st_dev == exec_stat.st_dev && sb.st_ino == exec_stat.st_ino); |
| + | } |
| static int | |
| pid_is_user(int pid, int uid) | |
| @@ -74,9 +74,8 @@ pid_is_user(int pid, int uid) | |
| return (sb.st_uid == uid); | |
| } | |
| - | |
| static int | |
| - | pid_is_cmd(int pid, const char *name) |
| + | pid_is_cmd(pid_t pid, const char *name) |
| { | |
| char buf[32]; | |
| FILE *f; | |
| @@ -116,9 +115,24 @@ check(int pid) | |
| } | |
| + | static void |
| + | do_pidfile(const char *name) |
| + | { |
| + | FILE *f; |
| + | pid_t pid; |
| + | |
| + | f = fopen(name, "r"); |
| + | if (f) { |
| + | if (fscanf(f, "%d", &pid) == 1) |
| + | check(pid); |
| + | fclose(f); |
| + | } else if (errno != ENOENT) |
| + | bb_perror_msg_and_die("open pidfile %s", name); |
| + | |
| + | } |
| static void | |
| - | do_procfs(void) |
| + | do_procinit(void) |
| { | |
| DIR *procdir; | |
| struct dirent *entry; | |
| @@ -145,9 +159,14 @@ static void | |
| do_stop(void) | |
| { | |
| char what[1024]; | |
| - | pid_list *p; |
| + | struct pid_list *p; |
| int killed = 0; | |
| + | if (pidfile) |
| + | do_pidfile(pidfile); |
| + | else |
| + | do_procinit(); |
| + | |
| if (cmdname) | |
| strcpy(what, cmdname); | |
| else if (execname) | |
| @@ -158,7 +177,8 @@ do_stop(void) | |
| bb_error_msg_and_die ("internal error, please report"); | |
| if (!found) { | |
| - | printf("no %s found; none killed.\n", what); |
| + | if (!quiet) |
| + | printf("no %s found; none killed.\n", what); |
| return; | |
| } | |
| for (p = found; p; p = p->next) { | |
| @@ -169,7 +189,7 @@ do_stop(void) | |
| bb_perror_msg("warning: failed to kill %d:", p->pid); | |
| } | |
| } | |
| - | if (killed) { |
| + | if (!quiet && killed) { |
| printf("stopped %s (pid", what); | |
| for (p = found; p; p = p->next) | |
| if(p->pid < 0) | |
| @@ -183,17 +203,20 @@ static const struct option ssd_long_options[] = { | |
| { "stop", 0, NULL, 'K' }, | |
| { "start", 0, NULL, 'S' }, | |
| { "background", 0, NULL, 'b' }, | |
| + | { "quiet", 0, NULL, 'q' }, |
| { "startas", 1, NULL, 'a' }, | |
| { "name", 1, NULL, 'n' }, | |
| { "signal", 1, NULL, 's' }, | |
| { "user", 1, NULL, 'u' }, | |
| { "exec", 1, NULL, 'x' }, | |
| + | { "pidfile", 1, NULL, 'p' }, |
| { 0, 0, 0, 0 } | |
| }; | |
| #define SSD_CTX_STOP 1 | |
| #define SSD_CTX_START 2 | |
| #define SSD_OPT_BACKGROUND 4 | |
| + | #define SSD_OPT_QUIET 8 |
| int | |
| start_stop_daemon_main(int argc, char **argv) | |
| @@ -205,8 +228,8 @@ start_stop_daemon_main(int argc, char **argv) | |
| bb_applet_long_options = ssd_long_options; | |
| bb_opt_complementaly = "K~S:S~K"; | |
| - | opt = bb_getopt_ulflags(argc, argv, "KSba:n:s:u:x:", |
| - | &startas, &cmdname, &signame, &userspec, &execname); |
| + | opt = bb_getopt_ulflags(argc, argv, "KSbqa:n:s:u:x:p:", |
| + | &startas, &cmdname, &signame, &userspec, &execname, &pidfile); |
| /* Check one and only one context option was given */ | |
| if ((opt & 0x80000000UL) || (opt & (SSD_CTX_STOP | SSD_CTX_START)) == 0) { | |
| @@ -232,7 +255,7 @@ start_stop_daemon_main(int argc, char **argv) | |
| if (userspec && sscanf(userspec, "%d", &user_id) != 1) | |
| user_id = my_getpwnam(userspec); | |
| - | do_procfs(); |
| + | do_procinit(); |
| if (opt & SSD_CTX_STOP) { | |
| do_stop(); | |
| @@ -240,7 +263,8 @@ start_stop_daemon_main(int argc, char **argv) | |
| } | |
| if (found) { | |
| - | printf("%s already running.\n%d\n", execname ,found->pid); |
| + | if (!quiet) |
| + | printf("%s already running.\n%d\n", execname ,found->pid); |
| return EXIT_SUCCESS; | |
| } | |
| *--argv = startas; | |
| @@ -501,7 +501,7 @@ | |
| #endif | |
| #ifdef CONFIG_RUN_PARTS | |
| APPLET_ODDNAME("run-parts", run_parts_main, _BB_DIR_BIN, _BB_SUID_NEVER, run_parts) | |
| - | #endif |
| + | #endif |
| #ifdef CONFIG_RX | |
| APPLET(rx, rx_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) | |
| #endif | |
| @@ -1156,7 +1156,7 @@ | |
| "\n" \ | |
| " <id>:<runlevels>:<action>:<process>\n" \ | |
| "\n" \ | |
| - | " <id>: \n" \ |
| + | " <id>:\n" \ |
| "\n" \ | |
| " WARNING: This field has a non-traditional meaning for BusyBox init!\n" \ | |
| " The id field is used by BusyBox init to specify the controlling tty for\n" \ | |
| @@ -1169,13 +1169,13 @@ | |
| " will be run. BusyBox init does nothing with utmp. We don't need no\n" \ | |
| " stinkin' utmp.\n" \ | |
| "\n" \ | |
| - | " <runlevels>: \n" \ |
| + | " <runlevels>:\n" \ |
| "\n" \ | |
| " The runlevels field is completely ignored.\n" \ | |
| "\n" \ | |
| - | " <action>: \n" \ |
| + | " <action>:\n" \ |
| "\n" \ | |
| - | " Valid actions include: sysinit, respawn, askfirst, wait, \n" \ |
| + | " Valid actions include: sysinit, respawn, askfirst, wait,\n" \ |
| " once, restart, ctrlaltdel, and shutdown.\n" \ | |
| "\n" \ | |
| " The available actions can be classified into two groups: actions\n" \ | |
| @@ -1209,13 +1209,13 @@ | |
| " respawn, except that before running the specified process it\n" \ | |
| " displays the line "Please press Enter to activate this console."\n" \ | |
| " and then waits for the user to press enter before starting the\n" \ | |
| - | " specified process. \n" \ |
| + | " specified process.\n" \ |
| "\n" \ | |
| " Unrecognized actions (like initdefault) will cause init to emit an\n" \ | |
| " error message, and then go along with its business. All actions are\n" \ | |
| " run in the order they appear in /etc/inittab.\n" \ | |
| "\n" \ | |
| - | " <process>: \n" \ |
| + | " <process>:\n" \ |
| "\n" \ | |
| " Specifies the process to be executed and it's command line.\n" \ | |
| "\n" \ | |
| @@ -1651,7 +1651,7 @@ | |
| "\tc or u:\tMake a character (un-buffered) device.\n" \ | |
| "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes." | |
| #define mknod_example_usage \ | |
| - | "$ mknod /dev/fd0 b 2 0 \n" \ |
| + | "$ mknod /dev/fd0 b 2 0\n" \ |
| "$ mknod -m 644 /tmp/pipe p\n" | |
| #define mkswap_trivial_usage \ | |
| @@ -2212,18 +2212,20 @@ | |
| "f\n" | |
| #define start_stop_daemon_trivial_usage \ | |
| - | "[OPTIONS]" |
| + | "[OPTIONS] [-S|--start|-K|--stop] ... [-- arguments...]\n" |
| #define start_stop_daemon_full_usage \ | |
| - | "Program to start and stop services.\n"\ |
| - | "Options:\n" \ |
| - | "-S\t\t\tstart\n"\ |
| - | "-K\t\t\tstop\n"\ |
| - | "-b\t\t\tforce process into background (daemonize)\n"\ |
| - | "-x <executable>\t\tprogram to start/check if it is running\n"\ |
| - | "-u <username>|<uid>\tstop this user's processes\n"\ |
| - | "-n <process-name>\tstop processes with this name\n"\ |
| - | "-s <signal>\t\tsignal to send (default 15)\n"\ |
| - | "-a <pathname>\t\tprogram to start (default <executable>)\n" |
| + | "Program to start and stop services."\ |
| + | "\n\nOptions:"\ |
| + | "\n\t-S|--start\t\t\tstart"\ |
| + | "\n\t-K|--stop\t\t\tstop"\ |
| + | "\n\t-a|--startas <pathname>\t\tstart the process specified by pathname"\ |
| + | "\n\t-b|--background\t\t\tforce process into background"\ |
| + | "\n\t-u|--user <username>|<uid>\tstop this user's processes"\ |
| + | "\n\t-x|--exec <executable>\t\tprogram to start/check if it is running"\ |
| + | "\n\t-n|--name <process-name>\tstop processes with this name"\ |
| + | "\n\t-p|--pidfile <pid-file>\t\tsave or load pid using a pid-file"\ |
| + | "\n\t-q|--quiet\t\t\tbe quiet" \ |
| + | "\n\t-s|--signal <signal>\t\tsignal to send (default TERM)\n" |
| #define strings_trivial_usage \ | |
| "[-afo] [-n length] [file ... ]" | |
| @@ -2478,7 +2480,7 @@ | |
| "$ echo $?\n" \ | |
| "1\n" \ | |
| "$ test 1 -eq 1\n" \ | |
| - | "$ echo $? \n" \ |
| + | "$ echo $?\n" \ |
| "0\n" \ | |
| "$ [ -d /etc ]\n" \ | |
| "$ echo $?\n" \ | |
| @@ -2750,12 +2752,12 @@ | |
| "COMMAND [OPTIONS] ..." | |
| #define vconfig_full_usage \ | |
| - | "Usage: add [interface-name] [vlan_id] \n" \ |
| - | " rem [vlan-name] \n" \ |
| - | " set_flag [interface-name] [flag-num] [0 | 1] \n" \ |
| - | " set_egress_map [vlan-name] [skb_priority] [vlan_qos] \n" \ |
| - | " set_ingress_map [vlan-name] [skb_priority] [vlan_qos] \n" \ |
| - | " set_name_type [name-type] \n" |
| + | "Usage: add [interface-name] [vlan_id]\n" \ |
| + | " rem [vlan-name]\n" \ |
| + | " set_flag [interface-name] [flag-num] [0 | 1]\n" \ |
| + | " set_egress_map [vlan-name] [skb_priority] [vlan_qos]\n" \ |
| + | " set_ingress_map [vlan-name] [skb_priority] [vlan_qos]\n" \ |
| + | " set_name_type [name-type]\n" |
| #define vi_trivial_usage \ | |
| "[OPTION] [FILE]..." | |