function old new delta hwclock_main 329 428 +99 rtc_adjtime_is_utc 138 134 -4 edir 365 354 -11 read_rtc 39 23 -16 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/3 up/down: 99/-31) Total: 68 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
		
			
				
	
	
		
			388 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			388 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
Copyright (c) 2001-2006, Gerrit Pape
 | 
						|
All rights reserved.
 | 
						|
 | 
						|
Redistribution and use in source and binary forms, with or without
 | 
						|
modification, are permitted provided that the following conditions are met:
 | 
						|
 | 
						|
   1. Redistributions of source code must retain the above copyright notice,
 | 
						|
      this list of conditions and the following disclaimer.
 | 
						|
   2. Redistributions in binary form must reproduce the above copyright
 | 
						|
      notice, this list of conditions and the following disclaimer in the
 | 
						|
      documentation and/or other materials provided with the distribution.
 | 
						|
   3. The name of the author may not be used to endorse or promote products
 | 
						|
      derived from this software without specific prior written permission.
 | 
						|
 | 
						|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
						|
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
						|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 | 
						|
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
						|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
						|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 | 
						|
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
						|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 | 
						|
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | 
						|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
*/
 | 
						|
 | 
						|
/* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
 | 
						|
/* Dependencies on runit_lib.c removed */
 | 
						|
 | 
						|
#include "libbb.h"
 | 
						|
#include <dirent.h>
 | 
						|
 | 
						|
/*
 | 
						|
Five applets here: chpst, envdir, envuidgid, setuidgid, softlimit.
 | 
						|
 | 
						|
Only softlimit and chpst are taking options:
 | 
						|
 | 
						|
# common
 | 
						|
-o N            Limit number of open files per process
 | 
						|
-p N            Limit number of processes per uid
 | 
						|
-m BYTES        Same as -d BYTES -s BYTES -l BYTES [-a BYTES]
 | 
						|
-d BYTES        Limit data segment
 | 
						|
-f BYTES        Limit output file sizes
 | 
						|
-c BYTES        Limit core file size
 | 
						|
# softlimit
 | 
						|
-a BYTES        Limit total size of all segments
 | 
						|
-s BYTES        Limit stack segment
 | 
						|
-l BYTES        Limit locked memory size
 | 
						|
-r BYTES        Limit resident set size
 | 
						|
-t N            Limit CPU time
 | 
						|
# chpst
 | 
						|
-u USER[:GRP]   Set uid and gid
 | 
						|
-U USER[:GRP]   Set $UID and $GID in environment
 | 
						|
-e DIR          Set environment variables as specified by files in DIR
 | 
						|
-/ DIR          Chroot to DIR
 | 
						|
-n NICE         Add NICE to nice value
 | 
						|
-v              Verbose
 | 
						|
-P              Create new process group
 | 
						|
-0 -1 -2        Close fd 0,1,2
 | 
						|
 | 
						|
Even though we accept all these options for both softlimit and chpst,
 | 
						|
they are not to be advertised on their help texts.
 | 
						|
We have enough problems with feature creep in other people's
 | 
						|
software, don't want to add our own.
 | 
						|
 | 
						|
envdir, envuidgid, setuidgid take no options, but they reuse code which
 | 
						|
handles -e, -U and -u.
 | 
						|
*/
 | 
						|
 | 
						|
enum {
 | 
						|
	OPT_a = (1 << 0) * ENABLE_SOFTLIMIT,
 | 
						|
	OPT_c = (1 << 1) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
 | 
						|
	OPT_d = (1 << 2) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
 | 
						|
	OPT_f = (1 << 3) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
 | 
						|
	OPT_l = (1 << 4) * ENABLE_SOFTLIMIT,
 | 
						|
	OPT_m = (1 << 5) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
 | 
						|
	OPT_o = (1 << 6) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
 | 
						|
	OPT_p = (1 << 7) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
 | 
						|
	OPT_r = (1 << 8) * ENABLE_SOFTLIMIT,
 | 
						|
	OPT_s = (1 << 9) * ENABLE_SOFTLIMIT,
 | 
						|
	OPT_t = (1 << 10) * ENABLE_SOFTLIMIT,
 | 
						|
	OPT_u = (1 << 11) * (ENABLE_CHPST || ENABLE_SETUIDGID),
 | 
						|
	OPT_U = (1 << 12) * (ENABLE_CHPST || ENABLE_ENVUIDGID),
 | 
						|
	OPT_e = (1 << 13) * (ENABLE_CHPST || ENABLE_ENVDIR),
 | 
						|
	OPT_root = (1 << 14) * ENABLE_CHPST,
 | 
						|
	OPT_n = (1 << 15) * ENABLE_CHPST,
 | 
						|
	OPT_v = (1 << 16) * ENABLE_CHPST,
 | 
						|
	OPT_P = (1 << 17) * ENABLE_CHPST,
 | 
						|
	OPT_0 = (1 << 18) * ENABLE_CHPST,
 | 
						|
	OPT_1 = (1 << 19) * ENABLE_CHPST,
 | 
						|
	OPT_2 = (1 << 20) * ENABLE_CHPST,
 | 
						|
};
 | 
						|
 | 
						|
/* TODO: use recursive_action? */
 | 
						|
static NOINLINE void edir(const char *directory_name)
 | 
						|
{
 | 
						|
	int wdir;
 | 
						|
	DIR *dir;
 | 
						|
	struct dirent *d;
 | 
						|
	int fd;
 | 
						|
 | 
						|
	wdir = xopen(".", O_RDONLY | O_NDELAY);
 | 
						|
	xchdir(directory_name);
 | 
						|
	dir = xopendir(".");
 | 
						|
	for (;;) {
 | 
						|
		char buf[256];
 | 
						|
		char *tail;
 | 
						|
		int size;
 | 
						|
 | 
						|
		errno = 0;
 | 
						|
		d = readdir(dir);
 | 
						|
		if (!d) {
 | 
						|
			if (errno)
 | 
						|
				bb_perror_msg_and_die("readdir %s",
 | 
						|
						directory_name);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		if (d->d_name[0] == '.')
 | 
						|
			continue;
 | 
						|
		fd = open(d->d_name, O_RDONLY | O_NDELAY);
 | 
						|
		if (fd < 0) {
 | 
						|
			if ((errno == EISDIR) && directory_name) {
 | 
						|
				if (option_mask32 & OPT_v)
 | 
						|
					bb_perror_msg("warning: %s/%s is a directory",
 | 
						|
						directory_name,	d->d_name);
 | 
						|
				continue;
 | 
						|
			} else
 | 
						|
				bb_perror_msg_and_die("open %s/%s",
 | 
						|
						directory_name, d->d_name);
 | 
						|
		}
 | 
						|
		size = full_read(fd, buf, sizeof(buf)-1);
 | 
						|
		close(fd);
 | 
						|
		if (size < 0)
 | 
						|
			bb_perror_msg_and_die("read %s/%s",
 | 
						|
					directory_name, d->d_name);
 | 
						|
		if (size == 0) {
 | 
						|
			unsetenv(d->d_name);
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		buf[size] = '\n';
 | 
						|
		tail = strchr(buf, '\n');
 | 
						|
		/* skip trailing whitespace */
 | 
						|
		while (1) {
 | 
						|
			*tail = '\0';
 | 
						|
			tail--;
 | 
						|
			if (tail < buf || !isspace(*tail))
 | 
						|
				break;
 | 
						|
		}
 | 
						|
		xsetenv(d->d_name, buf);
 | 
						|
	}
 | 
						|
	closedir(dir);
 | 
						|
	if (fchdir(wdir) == -1)
 | 
						|
		bb_perror_msg_and_die("fchdir");
 | 
						|
	close(wdir);
 | 
						|
}
 | 
						|
 | 
						|
static void limit(int what, long l)
 | 
						|
{
 | 
						|
	struct rlimit r;
 | 
						|
 | 
						|
	/* Never fails under Linux (except if you pass it bad arguments) */
 | 
						|
	getrlimit(what, &r);
 | 
						|
	if ((l < 0) || (l > r.rlim_max))
 | 
						|
		r.rlim_cur = r.rlim_max;
 | 
						|
	else
 | 
						|
		r.rlim_cur = l;
 | 
						|
	if (setrlimit(what, &r) == -1)
 | 
						|
		bb_perror_msg_and_die("setrlimit");
 | 
						|
}
 | 
						|
 | 
						|
int chpst_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 | 
						|
int chpst_main(int argc UNUSED_PARAM, char **argv)
 | 
						|
{
 | 
						|
	struct bb_uidgid_t ugid;
 | 
						|
	char *set_user = set_user; /* for compiler */
 | 
						|
	char *env_user = env_user;
 | 
						|
	char *env_dir = env_dir;
 | 
						|
	char *root;
 | 
						|
	char *nicestr;
 | 
						|
	unsigned limita;
 | 
						|
	unsigned limitc;
 | 
						|
	unsigned limitd;
 | 
						|
	unsigned limitf;
 | 
						|
	unsigned limitl;
 | 
						|
	unsigned limitm;
 | 
						|
	unsigned limito;
 | 
						|
	unsigned limitp;
 | 
						|
	unsigned limitr;
 | 
						|
	unsigned limits;
 | 
						|
	unsigned limitt;
 | 
						|
	unsigned opt;
 | 
						|
 | 
						|
	if ((ENABLE_CHPST && applet_name[0] == 'c')
 | 
						|
	 || (ENABLE_SOFTLIMIT && applet_name[1] == 'o')
 | 
						|
	) {
 | 
						|
		// FIXME: can we live with int-sized limits?
 | 
						|
		// can we live with 40000 days?
 | 
						|
		// if yes -> getopt converts strings to numbers for us
 | 
						|
		opt_complementary = "-1:a+:c+:d+:f+:l+:m+:o+:p+:r+:s+:t+";
 | 
						|
		opt = getopt32(argv, "+a:c:d:f:l:m:o:p:r:s:t:u:U:e:"
 | 
						|
			IF_CHPST("/:n:vP012"),
 | 
						|
			&limita, &limitc, &limitd, &limitf, &limitl,
 | 
						|
			&limitm, &limito, &limitp, &limitr, &limits, &limitt,
 | 
						|
			&set_user, &env_user, &env_dir
 | 
						|
			IF_CHPST(, &root, &nicestr));
 | 
						|
		argv += optind;
 | 
						|
		if (opt & OPT_m) { // -m means -asld
 | 
						|
			limita = limits = limitl = limitd = limitm;
 | 
						|
			opt |= (OPT_s | OPT_l | OPT_a | OPT_d);
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		option_mask32 = opt = 0;
 | 
						|
		argv++;
 | 
						|
		if (!*argv)
 | 
						|
			bb_show_usage();
 | 
						|
	}
 | 
						|
 | 
						|
	// envdir?
 | 
						|
	if (ENABLE_ENVDIR && applet_name[3] == 'd') {
 | 
						|
		env_dir = *argv++;
 | 
						|
		opt |= OPT_e;
 | 
						|
	}
 | 
						|
 | 
						|
	// setuidgid?
 | 
						|
	if (ENABLE_SETUIDGID && applet_name[1] == 'e') {
 | 
						|
		set_user = *argv++;
 | 
						|
		opt |= OPT_u;
 | 
						|
	}
 | 
						|
 | 
						|
	// envuidgid?
 | 
						|
	if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') {
 | 
						|
		env_user = *argv++;
 | 
						|
		opt |= OPT_U;
 | 
						|
	}
 | 
						|
 | 
						|
	// we must have PROG [ARGS]
 | 
						|
	if (!*argv)
 | 
						|
		bb_show_usage();
 | 
						|
 | 
						|
	// set limits
 | 
						|
	if (opt & OPT_d) {
 | 
						|
#ifdef RLIMIT_DATA
 | 
						|
		limit(RLIMIT_DATA, limitd);
 | 
						|
#else
 | 
						|
		if (opt & OPT_v)
 | 
						|
			bb_error_msg("system does not support RLIMIT_%s",
 | 
						|
				"DATA");
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	if (opt & OPT_s) {
 | 
						|
#ifdef RLIMIT_STACK
 | 
						|
		limit(RLIMIT_STACK, limits);
 | 
						|
#else
 | 
						|
		if (opt & OPT_v)
 | 
						|
			bb_error_msg("system does not support RLIMIT_%s",
 | 
						|
				"STACK");
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	if (opt & OPT_l) {
 | 
						|
#ifdef RLIMIT_MEMLOCK
 | 
						|
		limit(RLIMIT_MEMLOCK, limitl);
 | 
						|
#else
 | 
						|
		if (opt & OPT_v)
 | 
						|
			bb_error_msg("system does not support RLIMIT_%s",
 | 
						|
				"MEMLOCK");
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	if (opt & OPT_a) {
 | 
						|
#ifdef RLIMIT_VMEM
 | 
						|
		limit(RLIMIT_VMEM, limita);
 | 
						|
#else
 | 
						|
#ifdef RLIMIT_AS
 | 
						|
		limit(RLIMIT_AS, limita);
 | 
						|
#else
 | 
						|
		if (opt & OPT_v)
 | 
						|
			bb_error_msg("system does not support RLIMIT_%s",
 | 
						|
				"VMEM");
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	if (opt & OPT_o) {
 | 
						|
#ifdef RLIMIT_NOFILE
 | 
						|
		limit(RLIMIT_NOFILE, limito);
 | 
						|
#else
 | 
						|
#ifdef RLIMIT_OFILE
 | 
						|
		limit(RLIMIT_OFILE, limito);
 | 
						|
#else
 | 
						|
		if (opt & OPT_v)
 | 
						|
			bb_error_msg("system does not support RLIMIT_%s",
 | 
						|
				"NOFILE");
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	if (opt & OPT_p) {
 | 
						|
#ifdef RLIMIT_NPROC
 | 
						|
		limit(RLIMIT_NPROC, limitp);
 | 
						|
#else
 | 
						|
		if (opt & OPT_v)
 | 
						|
			bb_error_msg("system does not support RLIMIT_%s",
 | 
						|
				"NPROC");
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	if (opt & OPT_f) {
 | 
						|
#ifdef RLIMIT_FSIZE
 | 
						|
		limit(RLIMIT_FSIZE, limitf);
 | 
						|
#else
 | 
						|
		if (opt & OPT_v)
 | 
						|
			bb_error_msg("system does not support RLIMIT_%s",
 | 
						|
				"FSIZE");
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	if (opt & OPT_c) {
 | 
						|
#ifdef RLIMIT_CORE
 | 
						|
		limit(RLIMIT_CORE, limitc);
 | 
						|
#else
 | 
						|
		if (opt & OPT_v)
 | 
						|
			bb_error_msg("system does not support RLIMIT_%s",
 | 
						|
				"CORE");
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	if (opt & OPT_r) {
 | 
						|
#ifdef RLIMIT_RSS
 | 
						|
		limit(RLIMIT_RSS, limitr);
 | 
						|
#else
 | 
						|
		if (opt & OPT_v)
 | 
						|
			bb_error_msg("system does not support RLIMIT_%s",
 | 
						|
				"RSS");
 | 
						|
#endif
 | 
						|
	}
 | 
						|
	if (opt & OPT_t) {
 | 
						|
#ifdef RLIMIT_CPU
 | 
						|
		limit(RLIMIT_CPU, limitt);
 | 
						|
#else
 | 
						|
		if (opt & OPT_v)
 | 
						|
			bb_error_msg("system does not support RLIMIT_%s",
 | 
						|
				"CPU");
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	if (opt & OPT_P)
 | 
						|
		setsid();
 | 
						|
 | 
						|
	if (opt & OPT_e)
 | 
						|
		edir(env_dir);
 | 
						|
 | 
						|
	// FIXME: chrooted jail must have /etc/passwd if we move this after chroot!
 | 
						|
	// OTOH chroot fails for non-roots!
 | 
						|
	// SOLUTION: cache uid/gid before chroot, apply uid/gid after
 | 
						|
	if (opt & OPT_U) {
 | 
						|
		xget_uidgid(&ugid, env_user);
 | 
						|
		xsetenv("GID", utoa(ugid.gid));
 | 
						|
		xsetenv("UID", utoa(ugid.uid));
 | 
						|
	}
 | 
						|
 | 
						|
	if (opt & OPT_u) {
 | 
						|
		xget_uidgid(&ugid, set_user);
 | 
						|
	}
 | 
						|
 | 
						|
	if (opt & OPT_root) {
 | 
						|
		xchdir(root);
 | 
						|
		xchroot(".");
 | 
						|
	}
 | 
						|
 | 
						|
	if (opt & OPT_u) {
 | 
						|
		if (setgroups(1, &ugid.gid) == -1)
 | 
						|
			bb_perror_msg_and_die("setgroups");
 | 
						|
		xsetgid(ugid.gid);
 | 
						|
		xsetuid(ugid.uid);
 | 
						|
	}
 | 
						|
 | 
						|
	if (opt & OPT_n) {
 | 
						|
		errno = 0;
 | 
						|
		if (nice(xatoi(nicestr)) == -1)
 | 
						|
			bb_perror_msg_and_die("nice");
 | 
						|
	}
 | 
						|
 | 
						|
	if (opt & OPT_0)
 | 
						|
		close(STDIN_FILENO);
 | 
						|
	if (opt & OPT_1)
 | 
						|
		close(STDOUT_FILENO);
 | 
						|
	if (opt & OPT_2)
 | 
						|
		close(STDERR_FILENO);
 | 
						|
 | 
						|
	BB_EXECVP(argv[0], argv);
 | 
						|
	bb_perror_msg_and_die("exec %s", argv[0]);
 | 
						|
}
 |