mirror of
https://git.busybox.net/busybox.git
synced 2024-12-12 06:53:26 +08:00
d921b2ecc0
things like xasprintf() into xfuncs.c, remove xprint_file_by_name() (it only had one user), clean up lots of #includes... General cleanup pass. What I've been doing for the last couple days. And it conflicts! I've removed httpd.c from this checkin due to somebody else touching that file. It builds for me. I have to catch a bus. (Now you know why I'm looking forward to Mercurial.)
305 lines
6.4 KiB
C
305 lines
6.4 KiB
C
/* vi: set sw=4 ts=4: */
|
|
/*
|
|
* Mini start-stop-daemon implementation(s) for busybox
|
|
*
|
|
* Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
|
|
* Adapted for busybox David Kimdon <dwhedon@gordian.com>
|
|
*
|
|
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
|
|
*/
|
|
|
|
#include "busybox.h"
|
|
#include <getopt.h>
|
|
|
|
static int signal_nr = 15;
|
|
static int user_id = -1;
|
|
static int quiet;
|
|
static char *userspec;
|
|
static char *chuid;
|
|
static char *cmdname;
|
|
static char *execname;
|
|
static char *pidfile;
|
|
|
|
struct pid_list {
|
|
struct pid_list *next;
|
|
pid_t pid;
|
|
};
|
|
|
|
static struct pid_list *found = NULL;
|
|
|
|
static inline void push(pid_t pid)
|
|
{
|
|
struct pid_list *p;
|
|
|
|
p = xmalloc(sizeof(*p));
|
|
p->next = found;
|
|
p->pid = pid;
|
|
found = p;
|
|
}
|
|
|
|
static int pid_is_exec(pid_t pid, const char *name)
|
|
{
|
|
char buf[32];
|
|
struct stat sb, exec_stat;
|
|
|
|
if (name)
|
|
xstat(name, &exec_stat);
|
|
|
|
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)
|
|
{
|
|
struct stat sb;
|
|
char buf[32];
|
|
|
|
sprintf(buf, "/proc/%d", pid);
|
|
if (stat(buf, &sb) != 0)
|
|
return 0;
|
|
return (sb.st_uid == uid);
|
|
}
|
|
|
|
static int pid_is_cmd(pid_t pid, const char *name)
|
|
{
|
|
char buf[32];
|
|
FILE *f;
|
|
int c;
|
|
|
|
sprintf(buf, "/proc/%d/stat", pid);
|
|
f = fopen(buf, "r");
|
|
if (!f)
|
|
return 0;
|
|
while ((c = getc(f)) != EOF && c != '(')
|
|
;
|
|
if (c != '(') {
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
/* this hopefully handles command names containing ')' */
|
|
while ((c = getc(f)) != EOF && c == *name)
|
|
name++;
|
|
fclose(f);
|
|
return (c == ')' && *name == '\0');
|
|
}
|
|
|
|
|
|
static void check(int pid)
|
|
{
|
|
if (execname && !pid_is_exec(pid, execname)) {
|
|
return;
|
|
}
|
|
if (userspec && !pid_is_user(pid, user_id)) {
|
|
return;
|
|
}
|
|
if (cmdname && !pid_is_cmd(pid, cmdname)) {
|
|
return;
|
|
}
|
|
push(pid);
|
|
}
|
|
|
|
|
|
static void do_pidfile(void)
|
|
{
|
|
FILE *f;
|
|
pid_t pid;
|
|
|
|
f = fopen(pidfile, "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", pidfile);
|
|
|
|
}
|
|
|
|
static void do_procinit(void)
|
|
{
|
|
DIR *procdir;
|
|
struct dirent *entry;
|
|
int foundany, pid;
|
|
|
|
if (pidfile) {
|
|
do_pidfile();
|
|
return;
|
|
}
|
|
|
|
procdir = xopendir("/proc");
|
|
|
|
foundany = 0;
|
|
while ((entry = readdir(procdir)) != NULL) {
|
|
if (sscanf(entry->d_name, "%d", &pid) != 1)
|
|
continue;
|
|
foundany++;
|
|
check(pid);
|
|
}
|
|
closedir(procdir);
|
|
if (!foundany)
|
|
bb_error_msg_and_die ("nothing in /proc - not mounted?");
|
|
}
|
|
|
|
|
|
static int do_stop(void)
|
|
{
|
|
RESERVE_CONFIG_BUFFER(what, 1024);
|
|
struct pid_list *p;
|
|
int killed = 0;
|
|
|
|
do_procinit();
|
|
|
|
if (cmdname)
|
|
strcpy(what, cmdname);
|
|
else if (execname)
|
|
strcpy(what, execname);
|
|
else if (pidfile)
|
|
sprintf(what, "process in pidfile `%.200s'", pidfile);
|
|
else if (userspec)
|
|
sprintf(what, "process(es) owned by `%s'", userspec);
|
|
else
|
|
bb_error_msg_and_die ("internal error, please report");
|
|
|
|
if (!found) {
|
|
if (!quiet)
|
|
printf("no %s found; none killed.\n", what);
|
|
if (ENABLE_FEATURE_CLEAN_UP)
|
|
RELEASE_CONFIG_BUFFER(what);
|
|
return -1;
|
|
}
|
|
for (p = found; p; p = p->next) {
|
|
if (kill(p->pid, signal_nr) == 0) {
|
|
p->pid = -p->pid;
|
|
killed++;
|
|
} else {
|
|
bb_perror_msg("warning: failed to kill %d", p->pid);
|
|
}
|
|
}
|
|
if (!quiet && killed) {
|
|
printf("stopped %s (pid", what);
|
|
for (p = found; p; p = p->next)
|
|
if(p->pid < 0)
|
|
printf(" %d", -p->pid);
|
|
printf(").\n");
|
|
}
|
|
if (ENABLE_FEATURE_CLEAN_UP)
|
|
RELEASE_CONFIG_BUFFER(what);
|
|
return killed;
|
|
}
|
|
|
|
#if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
|
|
static const struct option ssd_long_options[] = {
|
|
{ "stop", 0, NULL, 'K' },
|
|
{ "start", 0, NULL, 'S' },
|
|
{ "background", 0, NULL, 'b' },
|
|
{ "quiet", 0, NULL, 'q' },
|
|
{ "make-pidfile", 0, NULL, 'm' },
|
|
#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
|
|
{ "oknodo", 0, NULL, 'o' },
|
|
{ "verbose", 0, NULL, 'v' },
|
|
#endif
|
|
{ "startas", 1, NULL, 'a' },
|
|
{ "name", 1, NULL, 'n' },
|
|
{ "signal", 1, NULL, 's' },
|
|
{ "user", 1, NULL, 'u' },
|
|
{ "chuid", 1, NULL, 'c' },
|
|
{ "exec", 1, NULL, 'x' },
|
|
{ "pidfile", 1, NULL, 'p' },
|
|
#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
|
|
{ "retry", 1, NULL, 'R' },
|
|
#endif
|
|
{ 0, 0, 0, 0 }
|
|
};
|
|
#endif
|
|
|
|
#define SSD_CTX_STOP 1
|
|
#define SSD_CTX_START 2
|
|
#define SSD_OPT_BACKGROUND 4
|
|
#define SSD_OPT_QUIET 8
|
|
#define SSD_OPT_MAKEPID 16
|
|
#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
|
|
#define SSD_OPT_OKNODO 32
|
|
#define SSD_OPT_VERBOSE 64
|
|
|
|
#endif
|
|
|
|
int start_stop_daemon_main(int argc, char **argv)
|
|
{
|
|
unsigned long opt;
|
|
char *signame = NULL;
|
|
char *startas = NULL;
|
|
#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
|
|
// char *retry_arg = NULL;
|
|
// int retries = -1;
|
|
#endif
|
|
#if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS
|
|
bb_applet_long_options = ssd_long_options;
|
|
#endif
|
|
|
|
/* Check required one context option was given */
|
|
bb_opt_complementally = "K:S:?:K--S:S--K:m?p:K?xpun:S?xa";
|
|
opt = bb_getopt_ulflags(argc, argv, "KSbqm"
|
|
// USE_FEATURE_START_STOP_DAEMON_FANCY("ovR:")
|
|
USE_FEATURE_START_STOP_DAEMON_FANCY("ov")
|
|
"a:n:s:u:c:x:p:"
|
|
// USE_FEATURE_START_STOP_DAEMON_FANCY(,&retry_arg)
|
|
,&startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile);
|
|
|
|
quiet = (opt & SSD_OPT_QUIET)
|
|
USE_FEATURE_START_STOP_DAEMON_FANCY(&& !(opt & SSD_OPT_VERBOSE));
|
|
|
|
if (signame) {
|
|
signal_nr = bb_xgetlarg(signame, 10, 0, NSIG);
|
|
}
|
|
|
|
if (!startas)
|
|
startas = execname;
|
|
|
|
// USE_FEATURE_START_STOP_DAEMON_FANCY(
|
|
// if (retry_arg)
|
|
// retries = bb_xgetlarg(retry_arg, 10, 0, INT_MAX);
|
|
// )
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if (userspec && sscanf(userspec, "%d", &user_id) != 1)
|
|
user_id = bb_xgetpwnam(userspec);
|
|
|
|
if (opt & SSD_CTX_STOP) {
|
|
int i = do_stop();
|
|
return
|
|
USE_FEATURE_START_STOP_DAEMON_FANCY((opt & SSD_OPT_OKNODO)
|
|
? 0 :) !!(i<=0);
|
|
}
|
|
|
|
do_procinit();
|
|
|
|
if (found) {
|
|
if (!quiet)
|
|
printf("%s already running.\n%d\n", execname ,found->pid);
|
|
USE_FEATURE_START_STOP_DAEMON_FANCY(return !(opt & SSD_OPT_OKNODO);)
|
|
SKIP_FEATURE_START_STOP_DAEMON_FANCY(return EXIT_FAILURE;)
|
|
}
|
|
*--argv = startas;
|
|
if (opt & SSD_OPT_BACKGROUND) {
|
|
xdaemon(0, 0);
|
|
setsid();
|
|
}
|
|
if (opt & SSD_OPT_MAKEPID) {
|
|
/* user wants _us_ to make the pidfile */
|
|
FILE *pidf = xfopen(pidfile, "w");
|
|
|
|
pid_t pidt = getpid();
|
|
fprintf(pidf, "%d\n", pidt);
|
|
fclose(pidf);
|
|
}
|
|
if(chuid) {
|
|
if(sscanf(chuid, "%d", &user_id) != 1)
|
|
user_id = bb_xgetpwnam(chuid);
|
|
setuid(user_id);
|
|
}
|
|
execv(startas, argv);
|
|
bb_perror_msg_and_die ("unable to start %s", startas);
|
|
}
|