Esempio n. 1
0
int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
{
	unsigned opt;
	char *signame;
	char *startas;
	char *chuid;
#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
//	char *retry_arg = NULL;
//	int retries = -1;
	char *opt_N;
#endif

	INIT_G();

	opt = GETOPT32(argv, "^"
		"KSbqtma:n:s:u:c:x:p:"
		IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:")
			/* -K or -S is required; they are mutually exclusive */
			/* -p is required if -m is given */
			/* -xpun (at least one) is required if -K is given */
			/* -xa (at least one) is required if -S is given */
			/* -q turns off -v */
			"\0"
			"K:S:K--S:S--K:m?p:K?xpun:S?xa"
			IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"),
		LONGOPTS
		&startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile
		IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N)
		/* We accept and ignore -R <param> / --retry <param> */
		IF_FEATURE_START_STOP_DAEMON_FANCY(,NULL)
	);

	if (opt & OPT_s) {
		signal_nr = get_signum(signame);
		if (signal_nr < 0) bb_show_usage();
	}

	if (!(opt & OPT_a))
		startas = execname;
	if (!execname) /* in case -a is given and -x is not */
		execname = startas;
	if (execname) {
		G.execname_sizeof = strlen(execname) + 1;
		G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1);
	}

//	IF_FEATURE_START_STOP_DAEMON_FANCY(
//		if (retry_arg)
//			retries = xatoi_positive(retry_arg);
//	)
	//argc -= optind;
	argv += optind;

	if (userspec) {
		user_id = bb_strtou(userspec, NULL, 10);
		if (errno)
			user_id = xuname2uid(userspec);
	}
	/* Both start and stop need to know current processes */
	do_procinit();

	if (opt & CTX_STOP) {
		int i = do_stop();
		return (opt & OPT_OKNODO) ? 0 : (i <= 0);
	}

	if (G.found_procs) {
		if (!QUIET)
			printf("%s is already running\n%u\n", execname, (unsigned)G.found_procs->pid);
		return !(opt & OPT_OKNODO);
	}

#ifdef OLDER_VERSION_OF_X
	if (execname)
		xstat(execname, &G.execstat);
#endif

	*--argv = startas;
	if (opt & OPT_BACKGROUND) {
#if BB_MMU
		bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK);
		/* DAEMON_DEVNULL_STDIO is superfluous -
		 * it's always done by bb_daemonize() */
#else
		/* Daemons usually call bb_daemonize_or_rexec(), but SSD can do
		 * without: SSD is not itself a daemon, it _execs_ a daemon.
		 * The usual NOMMU problem of "child can't run indefinitely,
		 * it must exec" does not bite us: we exec anyway.
		 */
		pid_t pid = xvfork();
		if (pid != 0) {
			/* parent */
			/* why _exit? the child may have changed the stack,
			 * so "return 0" may do bad things */
			_exit(EXIT_SUCCESS);
		}
		/* Child */
		setsid(); /* detach from controlling tty */
		/* Redirect stdio to /dev/null, close extra FDs */
		bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS);
#endif
	}
	if (opt & OPT_MAKEPID) {
		/* User wants _us_ to make the pidfile */
		write_pidfile(pidfile);
	}
	if (opt & OPT_c) {
		struct bb_uidgid_t ugid;
		parse_chown_usergroup_or_die(&ugid, chuid);
		if (ugid.uid != (uid_t) -1L) {
			struct passwd *pw = xgetpwuid(ugid.uid);
			if (ugid.gid != (gid_t) -1L)
				pw->pw_gid = ugid.gid;
			/* initgroups, setgid, setuid: */
			change_identity(pw);
		} else if (ugid.gid != (gid_t) -1L) {
			xsetgid(ugid.gid);
			setgroups(1, &ugid.gid);
		}
	}
#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY
	if (opt & OPT_NICELEVEL) {
		/* Set process priority */
		int prio = getpriority(PRIO_PROCESS, 0) + xatoi_range(opt_N, INT_MIN/2, INT_MAX/2);
		if (setpriority(PRIO_PROCESS, 0, prio) < 0) {
			bb_perror_msg_and_die("setpriority(%d)", prio);
		}
	}
#endif
	execvp(startas, argv);
	bb_perror_msg_and_die("can't execute '%s'", startas);
}
Esempio n. 2
0
int fuser_main(int argc UNUSED_PARAM, char **argv)
{
	// changed for ofgwrite
	applet_name = argv[0];
	char **pp;

	INIT_G();

	/* Handle -SIGNAL. Oh my... */
	pp = argv;
	while (*++pp) {
		int sig;
		char *arg = *pp;

		if (arg[0] != '-')
			continue;
		if (arg[1] == '-' && arg[2] == '\0') /* "--" */
			break;
		if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0')
			continue; /* it's "-4" or "-6" */
		sig = get_signum(&arg[1]);
		if (sig < 0)
			continue;
		/* "-SIGNAL" option found. Remove it and bail out */
		G.killsig = sig;
		do {
			pp[0] = arg = pp[1];
			pp++;
		} while (arg);
		break;
	}

	opt_complementary = "-1"; /* at least one param */
	getopt32(argv, OPTION_STRING);
	argv += optind;

	pp = argv;
	while (*pp) {
		/* parse net arg */
		unsigned port;
		char path[sizeof("/proc/net/TCP6")];

		strcpy(path, "/proc/net/");
		if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2
		 && access(path, R_OK) == 0
		) {
			/* PORT/PROTO */
			scan_proc_net_or_maps(path, port);
		} else {
			/* FILE */
			struct stat statbuf;
			xstat(*pp, &statbuf);
			add_inode(&statbuf);
		}
		pp++;
	}

	if (scan_recursive("/proc")) {
		if (!(option_mask32 & OPT_SILENT))
			bb_putchar('\n');
		return G.kill_failed;
	}

	return EXIT_FAILURE;
}
Esempio n. 3
0
int pgrep_main(int argc UNUSED_PARAM, char **argv)
{
	unsigned pid = getpid();
	int signo = SIGTERM;
	unsigned opt;
	int scan_mask = PSSCAN_COMM;
	char *first_arg;
	int first_arg_idx;
	int matched_pid;
	char *cmd_last;
	procps_status_t *proc;
	/* These are initialized to 0 */
	struct {
		regex_t re_buffer;
		regmatch_t re_match[1];
	} Z;
#define re_buffer (Z.re_buffer)
#define re_match  (Z.re_match )

	memset(&Z, 0, sizeof(Z));

	/* We must avoid interpreting -NUM (signal num) as an option */
	first_arg_idx = 1;
	while (1) {
		first_arg = argv[first_arg_idx];
		if (!first_arg)
			break;
		/* not "-<small_letter>..."? */
		if (first_arg[0] != '-' || first_arg[1] < 'a' || first_arg[1] > 'z') {
			argv[first_arg_idx] = NULL; /* terminate argv here */
			break;
		}
		first_arg_idx++;
	}
	opt = getopt32(argv, "vlfxon");
	argv[first_arg_idx] = first_arg;

	argv += optind;
	//argc -= optind; - unused anyway
	if (OPT_FULL)
		scan_mask |= PSSCAN_ARGVN;

	if (pkill) {
		if (OPT_LIST) { /* -l: print the whole signal list */
			print_signames();
			return 0;
		}
		if (first_arg && first_arg[0] == '-') {
			signo = get_signum(&first_arg[1]);
			if (signo < 0) /* || signo > MAX_SIGNUM ? */
				bb_error_msg_and_die("bad signal name '%s'", &first_arg[1]);
			argv++;
		}
	}

	/* One pattern is required */
	if (!argv[0] || argv[1])
		bb_show_usage();

	xregcomp(&re_buffer, argv[0], 0);
	matched_pid = 0;
	cmd_last = NULL;
	proc = NULL;
	while ((proc = procps_scan(proc, scan_mask)) != NULL) {
		char *cmd;
		if (proc->pid == pid)
			continue;
		cmd = proc->argv0;
		if (!cmd) {
			cmd = proc->comm;
		} else {
			int i = proc->argv_len;
			while (i) {
				if (!cmd[i]) cmd[i] = ' ';
				i--;
			}
		}
		/* NB: OPT_INVERT is always 0 or 1 */
		if ((regexec(&re_buffer, cmd, 1, re_match, 0) == 0 /* match found */
		     && (!OPT_ANCHOR || (re_match[0].rm_so == 0 && re_match[0].rm_eo == (regoff_t)strlen(cmd)))) ^ OPT_INVERT
		) {
			matched_pid = proc->pid;
			if (OPT_LAST) {
				free(cmd_last);
				cmd_last = xstrdup(cmd);
				continue;
			}
			act(proc->pid, cmd, signo, opt);
			if (OPT_FIRST)
				break;
		}
	}
	if (cmd_last) {
		act(matched_pid, cmd_last, signo, opt);
		if (ENABLE_FEATURE_CLEAN_UP)
			free(cmd_last);
	}
	return matched_pid == 0; /* return 1 if no processes listed/signaled */
}
Esempio n. 4
0
int pgrep_main(int argc UNUSED_PARAM, char **argv)
{
	unsigned pid;
	int signo;
	unsigned opt;
	int scan_mask;
	int matched_pid;
	int sid2match, ppid2match;
	char *cmd_last;
	procps_status_t *proc;
	/* These are initialized to 0 */
	struct {
		regex_t re_buffer;
		regmatch_t re_match[1];
	} Z;
#define re_buffer (Z.re_buffer)
#define re_match  (Z.re_match )

	memset(&Z, 0, sizeof(Z));

	/* Parse -SIGNAL for pkill. Must be first option, if present */
	signo = SIGTERM;
	if (pkill && argv[1] && argv[1][0] == '-') {
		int temp = get_signum(argv[1]+1);
		if (temp != -1) {
			signo = temp;
			argv++;
		}
	}

	/* Parse remaining options */
	ppid2match = -1;
	sid2match = -1;
	opt = getopt32(argv, "vlfxons:+P:+", &sid2match, &ppid2match);
	argv += optind;

	if (pkill && OPT_LIST) { /* -l: print the whole signal list */
		print_signames();
		return 0;
	}

	pid = getpid();
	if (sid2match == 0)
		sid2match = getsid(pid);

	scan_mask = PSSCAN_COMM | PSSCAN_ARGV0;
	if (OPT_FULL)
		scan_mask |= PSSCAN_ARGVN;

	/* One pattern is required, if no -s and no -P */
	if ((sid2match & ppid2match) < 0 && (!argv[0] || argv[1]))
		bb_show_usage();

	if (argv[0])
		xregcomp(&re_buffer, argv[0], OPT_ANCHOR ? REG_EXTENDED : (REG_EXTENDED|REG_NOSUB));

	matched_pid = 0;
	cmd_last = NULL;
	proc = NULL;
	while ((proc = procps_scan(proc, scan_mask)) != NULL) {
		char *cmd;

		if (proc->pid == pid)
			continue;

		cmd = proc->argv0;
		if (!cmd) {
			cmd = proc->comm;
		} else {
			int i = proc->argv_len;
			while (--i >= 0) {
				if ((unsigned char)cmd[i] < ' ')
					cmd[i] = ' ';
			}
		}

		if (ppid2match >= 0 && ppid2match != proc->ppid)
			continue;
		if (sid2match >= 0 && sid2match != proc->sid)
			continue;

		/* NB: OPT_INVERT is always 0 or 1 */
		if (!argv[0]
		 || (regexec(&re_buffer, cmd, 1, re_match, 0) == 0 /* match found */
		    && (!OPT_ANCHOR || (re_match[0].rm_so == 0 && re_match[0].rm_eo == (regoff_t)strlen(cmd)))
		    ) ^ OPT_INVERT
		) {
			matched_pid = proc->pid;
			if (OPT_LAST) {
				free(cmd_last);
				cmd_last = xstrdup(cmd);
				continue;
			}
			act(proc->pid, cmd, signo);
			if (OPT_FIRST)
				break;
		}
	}

	if (cmd_last) {
		act(matched_pid, cmd_last, signo);
		if (ENABLE_FEATURE_CLEAN_UP)
			free(cmd_last);
	}
	return matched_pid == 0; /* return 1 if no processes listed/signaled */
}
Esempio n. 5
0
int fuser_main(int argc UNUSED_PARAM, char **argv)
{
	pid_list *plist;
	inode_list *ilist;
	char **pp;
	dev_t dev;
	ino_t inode;
	unsigned port;
	int opt;
	int success;
	int killsig;
/*
fuser [options] FILEs or PORT/PROTOs
Find processes which use FILEs or PORTs
        -m      Find processes which use same fs as FILEs
        -4      Search only IPv4 space
        -6      Search only IPv6 space
        -s      Silent: just exit with 0 if any processes are found
        -k      Kill found processes (otherwise display PIDs)
        -SIGNAL Signal to send (default: TERM)
*/
	/* Handle -SIGNAL. Oh my... */
	killsig = SIGTERM;
	pp = argv;
	while (*++pp) {
		char *arg = *pp;
		if (arg[0] != '-')
			continue;
		if (arg[1] == '-' && arg[2] == '\0') /* "--" */
			break;
		if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0')
			continue; /* it's "-4" or "-6" */
		opt = get_signum(&arg[1]);
		if (opt < 0)
			continue;
		/* "-SIGNAL" option found. Remove it and bail out */
		killsig = opt;
		do {
			pp[0] = arg = pp[1];
			pp++;
		} while (arg);
		break;
	}

	opt = getopt32(argv, OPTION_STRING);
	argv += optind;

	ilist = NULL;
	pp = argv;
	while (*pp) {
		char *proto = parse_net_arg(*pp, &port);
		if (proto) { /* PORT/PROTO */
			ilist = scan_proc_net(proto, port, ilist);
			free(proto);
		} else { /* FILE */
			if (!file_to_dev_inode(*pp, &dev, &inode))
				bb_perror_msg_and_die("can't open %s", *pp);
			ilist = add_inode(ilist, dev, inode);
		}
		pp++;
	}

	plist = scan_proc_pids(ilist); /* changes dir to "/proc" */

	if (!plist)
		return EXIT_FAILURE;
	success = 1;
	if (opt & OPT_KILL) {
		success = kill_pid_list(plist, killsig);
	} else if (!(opt & OPT_SILENT)) {
		success = print_pid_list(plist);
	}
	return (success != 1); /* 0 == success */
}
Esempio n. 6
0
int fuser_main(int argc UNUSED_PARAM, char **argv)
{
	pid_list *plist;
	pid_t mypid;
	char **pp;
	struct stat st;
	unsigned port;
	int opt;
	int exitcode;
	int killsig;
/*
fuser [OPTIONS] FILE or PORT/PROTO
Find processes which use FILEs or PORTs
        -m      Find processes which use same fs as FILEs
        -4      Search only IPv4 space
        -6      Search only IPv6 space
        -s      Don't display PIDs
        -k      Kill found processes
        -SIGNAL Signal to send (default: KILL)
*/
	/* Handle -SIGNAL. Oh my... */
	killsig = SIGKILL; /* yes, the default is not SIGTERM */
	pp = argv;
	while (*++pp) {
		char *arg = *pp;
		if (arg[0] != '-')
			continue;
		if (arg[1] == '-' && arg[2] == '\0') /* "--" */
			break;
		if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0')
			continue; /* it's "-4" or "-6" */
		opt = get_signum(&arg[1]);
		if (opt < 0)
			continue;
		/* "-SIGNAL" option found. Remove it and bail out */
		killsig = opt;
		do {
			pp[0] = arg = pp[1];
			pp++;
		} while (arg);
		break;
	}

	opt_complementary = "-1"; /* at least one param */
	opt = getopt32(argv, OPTION_STRING);
	argv += optind;

	pp = argv;
	while (*pp) {
		/* parse net arg */
		char path[20], tproto[5];
		if (sscanf(*pp, "%u/%4s", &port, tproto) != 2)
			goto file;
		sprintf(path, "/proc/net/%s", tproto);
		if (access(path, R_OK) != 0) { /* PORT/PROTO */
			scan_proc_net(path, port);
		} else { /* FILE */
 file:
			xstat(*pp, &st);
			add_inode(&st);
		}
		pp++;
	}

	scan_proc_pids(); /* changes dir to "/proc" */

	mypid = getpid();
	plist = G.pid_list_head;
	while (1) {
		if (!plist)
			return EXIT_FAILURE;
		if (plist->pid != mypid)
			break;
		plist = plist->next;
	}

	exitcode = EXIT_SUCCESS;
	do {
		if (plist->pid != mypid) {
			if (opt & OPT_KILL) {
				if (kill(plist->pid, killsig) != 0) {
					bb_perror_msg("kill pid %u", (unsigned)plist->pid);
					exitcode = EXIT_FAILURE;
				}
			}
			if (!(opt & OPT_SILENT)) {
				printf("%u ", (unsigned)plist->pid);
			}
		}
		plist = plist->next;
	} while (plist);

	if (!(opt & (OPT_SILENT))) {
		bb_putchar('\n');
	}

	return exitcode;
}
Esempio n. 7
0
int kill_main(int argc, char **argv)
{
	char *arg;
	pid_t pid;
	int signo = SIGTERM, errors = 0, quiet = 0;
#if !ENABLE_KILLALL && !ENABLE_KILLALL5
#define killall 0
#define killall5 0
#else
/* How to determine who we are? find 3rd char from the end:
 * kill, killall, killall5
 *  ^i       ^a        ^l  - it's unique
 * (checking from the start is complicated by /bin/kill... case) */
	const char char3 = argv[0][strlen(argv[0]) - 3];
#define killall (ENABLE_KILLALL && char3 == 'a')
#define killall5 (ENABLE_KILLALL5 && char3 == 'l')
#endif

	/* Parse any options */
	argc--;
	arg = *++argv;

	if (argc < 1 || arg[0] != '-') {
		goto do_it_now;
	}

	/* The -l option, which prints out signal names.
	 * Intended usage in shell:
	 * echo "Died of SIG`kill -l $?`"
	 * We try to mimic what kill from coreutils-6.8 does */
	if (arg[1] == 'l' && arg[2] == '\0') {
		if (argc == 1) {
			/* Print the whole signal list */
			print_signames();
			return 0;
		}
		/* -l <sig list> */
		while ((arg = *++argv)) {
			if (isdigit(arg[0])) {
				signo = bb_strtou(arg, NULL, 10);
				if (errno) {
					bb_error_msg("unknown signal '%s'", arg);
					return EXIT_FAILURE;
				}
				/* Exitcodes >= 0x80 are to be treated
				 * as "killed by signal (exitcode & 0x7f)" */
				puts(get_signame(signo & 0x7f));
				/* TODO: 'bad' signal# - coreutils says:
				 * kill: 127: invalid signal
				 * we just print "127" instead */
			} else {
				signo = get_signum(arg);
				if (signo < 0) {
					bb_error_msg("unknown signal '%s'", arg);
					return EXIT_FAILURE;
				}
				printf("%d\n", signo);
			}
		}
		/* If they specified -l, we are all done */
		return EXIT_SUCCESS;
	}

	/* The -q quiet option */
	if (killall && arg[1] == 'q' && arg[2] == '\0') {
		quiet = 1;
		arg = *++argv;
		argc--;
		if (argc < 1)
			bb_show_usage();
		if (arg[0] != '-')
			goto do_it_now;
	}

	arg++; /* skip '-' */

	/* -o PID? (if present, it always is at the end of command line) */
	if (killall5 && arg[0] == 'o')
		goto do_it_now;

	if (argc > 1 && arg[0] == 's' && arg[1] == '\0') { /* -s SIG? */
		argc--;
		arg = *++argv;
	} /* else it must be -SIG */
	signo = get_signum(arg);
	if (signo < 0) { /* || signo > MAX_SIGNUM ? */
		bb_error_msg("bad signal name '%s'", arg);
		return EXIT_FAILURE;
	}
	arg = *++argv;
	argc--;

 do_it_now:
	pid = getpid();

	if (killall5) {
		pid_t sid;
		procps_status_t* p = NULL;
		int ret = 0;

		/* Find out our session id */
		sid = getsid(pid);
		/* Stop all processes */
		if (signo != SIGSTOP && signo != SIGCONT)
			kill(-1, SIGSTOP);
		/* Signal all processes except those in our session */
		while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID)) != NULL) {
			int i;

			if (p->sid == (unsigned)sid
			 || p->pid == (unsigned)pid
			 || p->pid == 1
			) {
				continue;
			}

			/* All remaining args must be -o PID options.
			 * Check p->pid against them. */
			for (i = 0; i < argc; i++) {
				pid_t omit;

				arg = argv[i];
				if (arg[0] != '-' || arg[1] != 'o') {
					bb_error_msg("bad option '%s'", arg);
					ret = 1;
					goto resume;
				}
				arg += 2;
				if (!arg[0] && argv[++i])
					arg = argv[i];
				omit = bb_strtoi(arg, NULL, 10);
				if (errno) {
					bb_error_msg("invalid number '%s'", arg);
					ret = 1;
					goto resume;
				}
				if (p->pid == omit)
					goto dont_kill;
			}
			kill(p->pid, signo);
 dont_kill: ;
		}
 resume:
		/* And let them continue */
		if (signo != SIGSTOP && signo != SIGCONT)
			kill(-1, SIGCONT);
		return ret;
	}

	/* Pid or name is required for kill/killall */
	if (argc < 1) {
		bb_error_msg("you need to specify whom to kill");
		return EXIT_FAILURE;
	}

	if (killall) {
		/* Looks like they want to do a killall.  Do that */
		while (arg) {
			pid_t* pidList;

			pidList = find_pid_by_name(arg);
			if (*pidList == 0) {
				errors++;
				if (!quiet)
					bb_error_msg("%s: no process killed", arg);
			} else {
				pid_t *pl;

				for (pl = pidList; *pl; pl++) {
					if (*pl == pid)
						continue;
					if (kill(*pl, signo) == 0)
						continue;
					errors++;
					if (!quiet)
						bb_perror_msg("can't kill pid %d", (int)*pl);
				}
			}
			free(pidList);
			arg = *++argv;
		}
		return errors;
	}

	/* Looks like they want to do a kill. Do that */
	while (arg) {
#if ENABLE_ASH || ENABLE_HUSH
		/*
		 * We need to support shell's "hack formats" of
		 * " -PRGP_ID" (yes, with a leading space)
		 * and " PID1 PID2 PID3" (with degenerate case "")
		 */
		while (*arg != '\0') {
			char *end;
			if (*arg == ' ')
				arg++;
			pid = bb_strtoi(arg, &end, 10);
			if (errno && (errno != EINVAL || *end != ' ')) {
				bb_error_msg("invalid number '%s'", arg);
				errors++;
				break;
			}
			if (kill(pid, signo) != 0) {
				bb_perror_msg("can't kill pid %d", (int)pid);
				errors++;
			}
			arg = end; /* can only point to ' ' or '\0' now */
		}
#else
		pid = bb_strtoi(arg, NULL, 10);
		if (errno) {
			bb_error_msg("invalid number '%s'", arg);
			errors++;
		} else if (kill(pid, signo) != 0) {
			bb_perror_msg("can't kill pid %d", (int)pid);
			errors++;
		}
#endif
		arg = *++argv;
	}
	return errors;
}
Esempio n. 8
0
int timeout_main(int argc UNUSED_PARAM, char **argv)
{
	int signo;
	int status;
	int parent = 0;
	int timeout = 10;
	pid_t pid;
#if !BB_MMU
	char *sv1, *sv2;
#endif
	const char *opt_s = "TERM";

	/* -p option is not documented, it is needed to support NOMMU. */

	/* -t SECONDS; -p PARENT_PID */
	opt_complementary = "t+" USE_FOR_NOMMU(":p+");
	/* '+': stop at first non-option */
	getopt32(argv, "+s:t:" USE_FOR_NOMMU("p:"), &opt_s, &timeout, &parent);
	/*argv += optind; - no, wait for bb_daemonize_or_rexec! */
	signo = get_signum(opt_s);
	if (signo < 0)
		bb_error_msg_and_die("unknown signal '%s'", opt_s);

	/* We want to create a grandchild which will watch
	 * and kill the grandparent. Other methods:
	 * making parent watch child disrupts parent<->child link
	 * (example: "tcpsvd 0.0.0.0 1234 timeout service_prog" -
	 * it's better if service_prog is a child of tcpsvd!),
	 * making child watch parent results in programs having
	 * unexpected children. */

	if (parent) /* we were re-execed, already grandchild */
		goto grandchild;
	if (!argv[optind]) /* no PROG? */
		bb_show_usage();

#if !BB_MMU
	sv1 = argv[optind];
	sv2 = argv[optind + 1];
#endif
	pid = xvfork();
	if (pid == 0) {
		/* Child: spawn grandchild and exit */
		parent = getppid();
#if !BB_MMU
		argv[optind] = xasprintf("-p%u", parent);
		argv[optind + 1] = NULL;
#endif
		/* NB: exits with nonzero on error: */
		bb_daemonize_or_rexec(0, argv);
		/* Here we are grandchild. Sleep, then kill grandparent */
 grandchild:
		/* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
		while (1) {
			sleep(1);
			if (--timeout <= 0)
				break;
			if (kill(parent, 0)) {
				/* process is gone */
				return EXIT_SUCCESS;
			}
		}
		kill(parent, signo);
		return EXIT_SUCCESS;
	}

	/* Parent */
	wait(&status); /* wait for child to die */
	/* Did intermediate [v]fork or exec fail? */
	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
		return EXIT_FAILURE;
	/* Ok, exec a program as requested */
	argv += optind;
#if !BB_MMU
	argv[0] = sv1;
	argv[1] = sv2;
#endif
	BB_EXECVP_or_die(argv);
}
int fuser_main(int argc, char **argv)
{
	/*static -- huh???*/ int opt = 0; /* FUSER_OPT_ */

	int port, i, optn;
	int* fni; /* file name indexes of argv */
	int fnic = 0;  /* file name index count */
	const char *proto;
	dev_t dev;
	ino_t inode;
	pid_list *pids;
	inode_list *inodes;
	int killsig = SIGTERM;
	int success = 1;

	if (argc < 2)
		bb_show_usage();

	fni = xmalloc(sizeof(int));
	for (i = 1; i < argc; i++) {
		optn = fuser_option(argv[i]);
		if (optn)
			opt |= optn;
		else if (argv[i][0] == '-') {
			killsig = get_signum(argv[i]+1);
			if (killsig < 0)
				killsig = SIGTERM;
		} else {
			fni = xrealloc(fni, sizeof(int) * (fnic+2));
			fni[fnic++] = i;
		}
	}

	if (!fnic)
		return 1;

	inodes = xmalloc(sizeof(inode_list));
	for (i = 0; i < fnic; i++) {
		if (fuser_parse_net_arg(argv[fni[i]], &proto, &port)) {
			fuser_scan_proc_net(opt, proto, port, inodes);
		} else {
			if (!fuser_file_to_dev_inode(argv[fni[i]], &dev, &inode)) {
				if (ENABLE_FEATURE_CLEAN_UP)
					free(inodes);
				bb_perror_msg_and_die("cannot open '%s'", argv[fni[i]]);
			}
			fuser_add_inode(inodes, dev, inode);
		}
	}
	pids = xmalloc(sizeof(pid_list));
	success = fuser_scan_proc_pids(opt, inodes, pids);
	/* if the first pid in the list is 0, none have been found */
	if (pids->pid == 0)
		success = 0;
	if (success) {
		if (opt & FUSER_OPT_KILL) {
			success = fuser_kill_pid_list(pids, killsig);
		} else if (!(opt & FUSER_OPT_SILENT)) {
			success = fuser_print_pid_list(pids);
		}
	}
	if (ENABLE_FEATURE_CLEAN_UP) {
		free(pids);
		free(inodes);
	}
	/* return 0 on (success == 1) 1 otherwise */
	return (success != 1);
}
Esempio n. 10
0
int kill_main(int argc, char **argv)
{
	char *arg;
	pid_t pid;
	int signo = SIGTERM, errors = 0, quiet = 0;
#if !ENABLE_KILLALL && !ENABLE_KILLALL5
#define killall 0
#define killall5 0
#else
/* How to determine who we are? find 3rd char from the end:
 * kill, killall, killall5
 *  ^i       ^a        ^l  - it's unique
 * (checking from the start is complicated by /bin/kill... case) */
	const char char3 = argv[0][strlen(argv[0]) - 3];
#define killall (ENABLE_KILLALL && char3 == 'a')
#define killall5 (ENABLE_KILLALL5 && char3 == 'l')
#endif

	/* Parse any options */
	argc--;
	arg = *++argv;

	if (argc < 1 || arg[0] != '-') {
		goto do_it_now;
	}

	/* The -l option, which prints out signal names.
	 * Intended usage in shell:
	 * echo "Died of SIG`kill -l $?`"
	 * We try to mimic what kill from coreutils-6.8 does */
	if (arg[1] == 'l' && arg[2] == '\0') {
		if (argc == 1) {
			/* Print the whole signal list */
			print_signames();
			return 0;
		}
		/* -l <sig list> */
		while ((arg = *++argv)) {
			if (isdigit(arg[0])) {
				signo = bb_strtou(arg, NULL, 10);
				if (errno) {
					bb_error_msg("unknown signal '%s'", arg);
					return EXIT_FAILURE;
				}
				/* Exitcodes >= 0x80 are to be treated
				 * as "killed by signal (exitcode & 0x7f)" */
				puts(get_signame(signo & 0x7f));
				/* TODO: 'bad' signal# - coreutils says:
				 * kill: 127: invalid signal
				 * we just print "127" instead */
			} else {
				signo = get_signum(arg);
				if (signo < 0) {
					bb_error_msg("unknown signal '%s'", arg);
					return EXIT_FAILURE;
				}
				printf("%d\n", signo);
			}
		}
		/* If they specified -l, we are all done */
		return EXIT_SUCCESS;
	}

	/* The -q quiet option */
	if (killall && arg[1] == 'q' && arg[2] == '\0') {
		quiet = 1;
		arg = *++argv;
		argc--;
		if (argc < 1) bb_show_usage();
		if (arg[0] != '-') goto do_it_now;
	}

	/* -SIG */
	signo = get_signum(&arg[1]);
	if (signo < 0) { /* || signo > MAX_SIGNUM ? */
		bb_error_msg("bad signal name '%s'", &arg[1]);
		return EXIT_FAILURE;
	}
	arg = *++argv;
	argc--;

do_it_now:
	pid = getpid();

	if (killall5) {
		pid_t sid;
		procps_status_t* p = NULL;

		/* Find out our own session id */
		sid = getsid(pid);
		/* Now stop all processes */
		kill(-1, SIGSTOP);
		/* Now kill all processes except our session */
		while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID))) {
			if (p->sid != (unsigned)sid && p->pid != (unsigned)pid && p->pid != 1)
				kill(p->pid, signo);
		}
		/* And let them continue */
		kill(-1, SIGCONT);
		return 0;
	}

	/* Pid or name is required for kill/killall */
	if (argc < 1) {
		bb_error_msg("you need to specify whom to kill");
		return EXIT_FAILURE;
	}

	if (killall) {
		/* Looks like they want to do a killall.  Do that */
		while (arg) {
			pid_t* pidList;

			pidList = find_pid_by_name(arg);
			if (*pidList == 0) {
				errors++;
				if (!quiet)
					bb_error_msg("%s: no process killed", arg);
			} else {
				pid_t *pl;

				for (pl = pidList; *pl; pl++) {
					if (*pl == pid)
						continue;
					if (kill(*pl, signo) == 0)
						continue;
					errors++;
					if (!quiet)
						bb_perror_msg("cannot kill pid %u", (unsigned)*pl);
				}
			}
			free(pidList);
			arg = *++argv;
		}
		return errors;
	}

	/* Looks like they want to do a kill. Do that */
	while (arg) {
		/* Support shell 'space' trick */
		if (arg[0] == ' ')
			arg++;
		pid = bb_strtoi(arg, NULL, 10);
		if (errno) {
			bb_error_msg("bad pid '%s'", arg);
			errors++;
		} else if (kill(pid, signo) != 0) {
			bb_perror_msg("cannot kill pid %d", (int)pid);
			errors++;
		}
		arg = *++argv;
	}
	return errors;
}