| /* vi: set sw=4 ts=4: */ | 
 | /* | 
 |  * renice implementation for busybox | 
 |  * | 
 |  * Copyright (C) 2005  Manuel Novoa III  <mjn3@codepoet.org> | 
 |  * | 
 |  * Licensed under GPLv2 or later, see file LICENSE in this source tree. | 
 |  */ | 
 |  | 
 | /* Notes: | 
 |  *   Setting an absolute priority was obsoleted in SUSv2 and removed | 
 |  *   in SUSv3.  However, the common linux version of renice does | 
 |  *   absolute and not relative.  So we'll continue supporting absolute, | 
 |  *   although the stdout logging has been removed since both SUSv2 and | 
 |  *   SUSv3 specify that stdout isn't used. | 
 |  * | 
 |  *   This version is lenient in that it doesn't require any IDs.  The | 
 |  *   options -p, -g, and -u are treated as mode switches for the | 
 |  *   following IDs (if any).  Multiple switches are allowed. | 
 |  */ | 
 |  | 
 | //usage:#define renice_trivial_usage | 
 | //usage:       "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]" | 
 | //usage:#define renice_full_usage "\n\n" | 
 | //usage:       "Change scheduling priority for a running process\n" | 
 | //usage:     "\n	-n	Adjust current nice value (smaller is faster)" | 
 | //usage:     "\n	-p	Process id(s) (default)" | 
 | //usage:     "\n	-g	Process group id(s)" | 
 | //usage:     "\n	-u	Process user name(s) and/or id(s)" | 
 |  | 
 | #include "libbb.h" | 
 | #include <sys/resource.h> | 
 |  | 
 | void BUG_bad_PRIO_PROCESS(void); | 
 | void BUG_bad_PRIO_PGRP(void); | 
 | void BUG_bad_PRIO_USER(void); | 
 |  | 
 | int renice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 
 | int renice_main(int argc UNUSED_PARAM, char **argv) | 
 | { | 
 | 	static const char Xetpriority_msg[] ALIGN1 = "%cetpriority"; | 
 |  | 
 | 	int retval = EXIT_SUCCESS; | 
 | 	int which = PRIO_PROCESS;  /* Default 'which' value. */ | 
 | 	int use_relative = 0; | 
 | 	int adjustment, new_priority; | 
 | 	unsigned who; | 
 | 	char *arg; | 
 |  | 
 | 	/* Yes, they are not #defines in glibc 2.4! #if won't work */ | 
 | 	if (PRIO_PROCESS < CHAR_MIN || PRIO_PROCESS > CHAR_MAX) | 
 | 		BUG_bad_PRIO_PROCESS(); | 
 | 	if (PRIO_PGRP < CHAR_MIN || PRIO_PGRP > CHAR_MAX) | 
 | 		BUG_bad_PRIO_PGRP(); | 
 | 	if (PRIO_USER < CHAR_MIN || PRIO_USER > CHAR_MAX) | 
 | 		BUG_bad_PRIO_USER(); | 
 |  | 
 | 	arg = *++argv; | 
 |  | 
 | 	/* Check if we are using a relative adjustment. */ | 
 | 	if (arg && arg[0] == '-' && arg[1] == 'n') { | 
 | 		use_relative = 1; | 
 | 		if (!arg[2]) | 
 | 			arg = *++argv; | 
 | 		else | 
 | 			arg += 2; | 
 | 	} | 
 |  | 
 | 	if (!arg) {  /* No args?  Then show usage. */ | 
 | 		bb_show_usage(); | 
 | 	} | 
 |  | 
 | 	/* Get the priority adjustment (absolute or relative). */ | 
 | 	adjustment = xatoi_range(arg, INT_MIN/2, INT_MAX/2); | 
 |  | 
 | 	while ((arg = *++argv) != NULL) { | 
 | 		/* Check for a mode switch. */ | 
 | 		if (arg[0] == '-' && arg[1]) { | 
 | 			static const char opts[] ALIGN1 = { | 
 | 				'p', 'g', 'u', 0, PRIO_PROCESS, PRIO_PGRP, PRIO_USER | 
 | 			}; | 
 | 			const char *p = strchr(opts, arg[1]); | 
 | 			if (p) { | 
 | 				which = p[4]; | 
 | 				if (!arg[2]) | 
 | 					continue; | 
 | 				arg += 2; | 
 | 			} | 
 | 		} | 
 |  | 
 | 		/* Process an ID arg. */ | 
 | 		if (which == PRIO_USER) { | 
 | 			struct passwd *p; | 
 | 			p = getpwnam(arg); | 
 | 			if (!p) { | 
 | 				bb_error_msg("unknown user %s", arg); | 
 | 				goto HAD_ERROR; | 
 | 			} | 
 | 			who = p->pw_uid; | 
 | 		} else { | 
 | 			who = bb_strtou(arg, NULL, 10); | 
 | 			if (errno) { | 
 | 				bb_error_msg("invalid number '%s'", arg); | 
 | 				goto HAD_ERROR; | 
 | 			} | 
 | 		} | 
 |  | 
 | 		/* Get priority to use, and set it. */ | 
 | 		if (use_relative) { | 
 | 			int old_priority; | 
 |  | 
 | 			errno = 0;  /* Needed for getpriority error detection. */ | 
 | 			old_priority = getpriority(which, who); | 
 | 			if (errno) { | 
 | 				bb_perror_msg(Xetpriority_msg, 'g'); | 
 | 				goto HAD_ERROR; | 
 | 			} | 
 |  | 
 | 			new_priority = old_priority + adjustment; | 
 | 		} else { | 
 | 			new_priority = adjustment; | 
 | 		} | 
 |  | 
 | 		if (setpriority(which, who, new_priority) == 0) { | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		bb_perror_msg(Xetpriority_msg, 's'); | 
 |  HAD_ERROR: | 
 | 		retval = EXIT_FAILURE; | 
 | 	} | 
 |  | 
 | 	/* No need to check for errors outputing to stderr since, if it | 
 | 	 * was used, the HAD_ERROR label was reached and retval was set. */ | 
 |  | 
 | 	return retval; | 
 | } |