10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*2712Snn35248 * Common Development and Distribution License (the "License").
6*2712Snn35248 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*2712Snn35248 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
270Sstevel@tonic-gate /* All Rights Reserved */
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
310Sstevel@tonic-gate * The Regents of the University of California
320Sstevel@tonic-gate * All Rights Reserved
330Sstevel@tonic-gate *
340Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
350Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
360Sstevel@tonic-gate * contributors.
370Sstevel@tonic-gate */
380Sstevel@tonic-gate
390Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
400Sstevel@tonic-gate
410Sstevel@tonic-gate #include <sys/types.h>
420Sstevel@tonic-gate #include <sys/time.h>
430Sstevel@tonic-gate #include <sys/resource.h>
440Sstevel@tonic-gate #include <stdio.h>
450Sstevel@tonic-gate #include <pwd.h>
460Sstevel@tonic-gate #include <grp.h>
470Sstevel@tonic-gate #include <project.h>
480Sstevel@tonic-gate #include <nl_types.h>
490Sstevel@tonic-gate #include <locale.h>
500Sstevel@tonic-gate #include <errno.h>
510Sstevel@tonic-gate #include <stdlib.h>
520Sstevel@tonic-gate #include <string.h>
530Sstevel@tonic-gate #include <unistd.h>
540Sstevel@tonic-gate #include <ctype.h>
550Sstevel@tonic-gate #include <zone.h>
560Sstevel@tonic-gate #include <libzonecfg.h>
570Sstevel@tonic-gate
580Sstevel@tonic-gate static void usage(void);
590Sstevel@tonic-gate static int donice(int which, id_t who, int prio, int increment, char *who_s);
600Sstevel@tonic-gate static int parse_obsolete_options(int argc, char **argv);
610Sstevel@tonic-gate static int name2id(char *);
620Sstevel@tonic-gate
630Sstevel@tonic-gate #define PRIO_MAX 19
640Sstevel@tonic-gate #define PRIO_MIN -20
650Sstevel@tonic-gate #define RENICE_DEFAULT_PRIORITY 10
660Sstevel@tonic-gate #define RENICE_PRIO_INCREMENT 1
670Sstevel@tonic-gate #define RENICE_PRIO_ABSOLUTE 0
680Sstevel@tonic-gate
690Sstevel@tonic-gate typedef struct {
700Sstevel@tonic-gate int id;
710Sstevel@tonic-gate char *name;
720Sstevel@tonic-gate } type_t;
730Sstevel@tonic-gate
740Sstevel@tonic-gate static type_t types[] = {
750Sstevel@tonic-gate { PRIO_PROCESS, "pid" },
760Sstevel@tonic-gate { PRIO_PGRP, "pgid" },
770Sstevel@tonic-gate { PRIO_USER, "uid" },
780Sstevel@tonic-gate { PRIO_USER, "user" },
790Sstevel@tonic-gate { PRIO_TASK, "taskid" },
800Sstevel@tonic-gate { PRIO_PROJECT, "projid" },
810Sstevel@tonic-gate { PRIO_PROJECT, "project" },
820Sstevel@tonic-gate { PRIO_GROUP, "gid" },
830Sstevel@tonic-gate { PRIO_GROUP, "group" },
840Sstevel@tonic-gate { PRIO_SESSION, "sid" },
850Sstevel@tonic-gate { PRIO_ZONE, "zone" },
860Sstevel@tonic-gate { PRIO_ZONE, "zoneid" },
870Sstevel@tonic-gate { PRIO_CONTRACT, "ctid" },
880Sstevel@tonic-gate { 0, NULL }
890Sstevel@tonic-gate };
900Sstevel@tonic-gate
910Sstevel@tonic-gate /*
920Sstevel@tonic-gate * Change the priority (nice) of processes
930Sstevel@tonic-gate * or groups of processes which are already
940Sstevel@tonic-gate * running.
950Sstevel@tonic-gate */
960Sstevel@tonic-gate
97212Scf46844 int
main(int argc,char * argv[])980Sstevel@tonic-gate main(int argc, char *argv[])
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate int c;
1010Sstevel@tonic-gate int optflag = 0;
1020Sstevel@tonic-gate int which = PRIO_PROCESS;
1030Sstevel@tonic-gate id_t who = 0;
1040Sstevel@tonic-gate int errs = 0;
1050Sstevel@tonic-gate char *end_ptr;
1060Sstevel@tonic-gate int incr = RENICE_DEFAULT_PRIORITY;
1070Sstevel@tonic-gate int prio_type = RENICE_PRIO_INCREMENT;
1080Sstevel@tonic-gate struct passwd *pwd;
1090Sstevel@tonic-gate struct group *grp;
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
1120Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
1130Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST"
1140Sstevel@tonic-gate #endif
1150Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate if (argc < 2)
1180Sstevel@tonic-gate (void) usage();
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate /*
1210Sstevel@tonic-gate * There is ambiguity in the renice options spec.
1220Sstevel@tonic-gate * If argv[1] is in the valid range of priority values then
1230Sstevel@tonic-gate * treat it as a priority. Otherwise, treat it as a pid.
1240Sstevel@tonic-gate */
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate if (isdigit(argv[1][0])) {
1270Sstevel@tonic-gate if (strtol(argv[1], (char **)NULL, 10) > (PRIO_MAX+1)) {
1280Sstevel@tonic-gate argc--; /* renice pid ... */
1290Sstevel@tonic-gate argv++;
1300Sstevel@tonic-gate prio_type = RENICE_PRIO_INCREMENT;
1310Sstevel@tonic-gate } else { /* renice priority ... */
1320Sstevel@tonic-gate exit(parse_obsolete_options(argc, argv));
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate } else if ((argv[1][0] == '-' || argv[1][0] == '+') &&
1350Sstevel@tonic-gate isdigit(argv[1][1])) { /* renice priority ... */
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate exit(parse_obsolete_options(argc, argv));
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate } else { /* renice [-n increment] [-g|-p|-u] ID ... */
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate while ((c = getopt(argc, argv, "n:gpui:")) != -1) {
1420Sstevel@tonic-gate switch (c) {
1430Sstevel@tonic-gate case 'n':
1440Sstevel@tonic-gate incr = strtol(optarg, &end_ptr, 10);
1450Sstevel@tonic-gate prio_type = RENICE_PRIO_INCREMENT;
1460Sstevel@tonic-gate if (*end_ptr != '\0')
1470Sstevel@tonic-gate usage();
1480Sstevel@tonic-gate break;
1490Sstevel@tonic-gate case 'g':
1500Sstevel@tonic-gate which = PRIO_PGRP;
1510Sstevel@tonic-gate optflag++;
1520Sstevel@tonic-gate break;
1530Sstevel@tonic-gate case 'p':
1540Sstevel@tonic-gate which = PRIO_PROCESS;
1550Sstevel@tonic-gate optflag++;
1560Sstevel@tonic-gate break;
1570Sstevel@tonic-gate case 'u':
1580Sstevel@tonic-gate which = PRIO_USER;
1590Sstevel@tonic-gate optflag++;
1600Sstevel@tonic-gate break;
1610Sstevel@tonic-gate case 'i':
1620Sstevel@tonic-gate which = name2id(optarg);
1630Sstevel@tonic-gate optflag++;
1640Sstevel@tonic-gate break;
1650Sstevel@tonic-gate default:
1660Sstevel@tonic-gate usage();
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate argc -= optind;
1710Sstevel@tonic-gate argv += optind;
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate if (argc == 0 || (optflag > 1))
1740Sstevel@tonic-gate usage();
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate for (; argc > 0; argc--, argv++) {
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate if (isdigit(argv[0][0])) {
1800Sstevel@tonic-gate who = strtol(*argv, &end_ptr, 10);
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate /* if a zone id, make sure it is valid */
1830Sstevel@tonic-gate if (who >= 0 && end_ptr != *argv &&
1840Sstevel@tonic-gate *end_ptr == '\0' && (which != PRIO_ZONE ||
1850Sstevel@tonic-gate getzonenamebyid(who, NULL, 0) != -1) &&
1860Sstevel@tonic-gate (which != PRIO_CONTRACT || who != 0)) {
1870Sstevel@tonic-gate errs += donice(which, who, incr, prio_type,
1880Sstevel@tonic-gate *argv);
1890Sstevel@tonic-gate continue;
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate switch (which) {
1940Sstevel@tonic-gate case PRIO_USER:
1950Sstevel@tonic-gate if ((pwd = getpwnam(*argv)) != NULL) {
1960Sstevel@tonic-gate who = pwd->pw_uid;
1970Sstevel@tonic-gate errs += donice(which, who, incr, prio_type,
1980Sstevel@tonic-gate *argv);
1990Sstevel@tonic-gate } else {
2000Sstevel@tonic-gate (void) fprintf(stderr,
2010Sstevel@tonic-gate gettext("renice: unknown user: %s\n"),
2020Sstevel@tonic-gate *argv);
2030Sstevel@tonic-gate errs++;
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate break;
2060Sstevel@tonic-gate case PRIO_GROUP:
2070Sstevel@tonic-gate if ((grp = getgrnam(*argv)) != NULL) {
2080Sstevel@tonic-gate who = grp->gr_gid;
2090Sstevel@tonic-gate errs += donice(which, who, incr, prio_type,
2100Sstevel@tonic-gate *argv);
2110Sstevel@tonic-gate } else {
2120Sstevel@tonic-gate (void) fprintf(stderr,
2130Sstevel@tonic-gate gettext("renice: unknown group: %s\n"),
2140Sstevel@tonic-gate *argv);
2150Sstevel@tonic-gate errs++;
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate break;
2180Sstevel@tonic-gate case PRIO_PROJECT:
2190Sstevel@tonic-gate if ((who = getprojidbyname(*argv)) != (id_t)-1) {
2200Sstevel@tonic-gate errs += donice(which, who, incr, prio_type,
2210Sstevel@tonic-gate *argv);
2220Sstevel@tonic-gate } else {
2230Sstevel@tonic-gate (void) fprintf(stderr,
2240Sstevel@tonic-gate gettext("renice: unknown project: %s\n"),
2250Sstevel@tonic-gate *argv);
2260Sstevel@tonic-gate errs++;
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate break;
2290Sstevel@tonic-gate case PRIO_ZONE:
2300Sstevel@tonic-gate if (zone_get_id(*argv, &who) != 0) {
2310Sstevel@tonic-gate (void) fprintf(stderr,
2320Sstevel@tonic-gate gettext("renice: unknown zone: %s\n"),
2330Sstevel@tonic-gate *argv);
2340Sstevel@tonic-gate errs++;
2350Sstevel@tonic-gate break;
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate errs += donice(which, who, incr, prio_type, *argv);
2380Sstevel@tonic-gate break;
2390Sstevel@tonic-gate default:
2400Sstevel@tonic-gate /*
2410Sstevel@tonic-gate * In all other cases it is invalid id or name
2420Sstevel@tonic-gate */
2430Sstevel@tonic-gate (void) fprintf(stderr,
2440Sstevel@tonic-gate gettext("renice: bad value: %s\n"), *argv);
2450Sstevel@tonic-gate errs++;
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate return (errs != 0);
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate static int
parse_obsolete_options(int argc,char * argv[])2530Sstevel@tonic-gate parse_obsolete_options(int argc, char *argv[])
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate int which = PRIO_PROCESS;
2560Sstevel@tonic-gate id_t who = 0;
2570Sstevel@tonic-gate int prio;
2580Sstevel@tonic-gate int errs = 0;
2590Sstevel@tonic-gate char *end_ptr;
2600Sstevel@tonic-gate
2610Sstevel@tonic-gate argc--;
2620Sstevel@tonic-gate argv++;
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate if (argc < 2) {
2650Sstevel@tonic-gate usage();
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate prio = strtol(*argv, &end_ptr, 10);
2690Sstevel@tonic-gate if (*end_ptr != '\0') {
2700Sstevel@tonic-gate usage();
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate if (prio == 20) {
2740Sstevel@tonic-gate (void) fprintf(stderr,
2750Sstevel@tonic-gate gettext("renice: nice value 20 rounded down to 19\n"));
2760Sstevel@tonic-gate }
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate argc--;
2790Sstevel@tonic-gate argv++;
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate for (; argc > 0; argc--, argv++) {
2820Sstevel@tonic-gate if (strcmp(*argv, "-g") == 0) {
2830Sstevel@tonic-gate which = PRIO_PGRP;
2840Sstevel@tonic-gate continue;
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate if (strcmp(*argv, "-u") == 0) {
2870Sstevel@tonic-gate which = PRIO_USER;
2880Sstevel@tonic-gate continue;
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate if (strcmp(*argv, "-p") == 0) {
2910Sstevel@tonic-gate which = PRIO_PROCESS;
2920Sstevel@tonic-gate continue;
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate if (which == PRIO_USER && !isdigit(argv[0][0])) {
2950Sstevel@tonic-gate struct passwd *pwd = getpwnam(*argv);
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate if (pwd == NULL) {
2980Sstevel@tonic-gate (void) fprintf(stderr,
2990Sstevel@tonic-gate gettext("renice: unknown user: %s\n"),
3000Sstevel@tonic-gate *argv);
3010Sstevel@tonic-gate errs++;
3020Sstevel@tonic-gate continue;
3030Sstevel@tonic-gate }
3040Sstevel@tonic-gate who = pwd->pw_uid;
3050Sstevel@tonic-gate } else {
3060Sstevel@tonic-gate who = strtol(*argv, &end_ptr, 10);
3070Sstevel@tonic-gate if ((who < 0) || (*end_ptr != '\0')) {
3080Sstevel@tonic-gate (void) fprintf(stderr,
3090Sstevel@tonic-gate gettext("renice: bad value: %s\n"), *argv);
3100Sstevel@tonic-gate errs++;
3110Sstevel@tonic-gate continue;
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate errs += donice(which, who, prio, RENICE_PRIO_ABSOLUTE, *argv);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate return (errs != 0);
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate
3210Sstevel@tonic-gate static int
donice(int which,id_t who,int prio,int increment,char * who_s)3220Sstevel@tonic-gate donice(int which, id_t who, int prio, int increment, char *who_s)
3230Sstevel@tonic-gate {
3240Sstevel@tonic-gate int oldprio;
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate oldprio = getpriority(which, who);
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate if (oldprio == -1 && errno) {
3290Sstevel@tonic-gate (void) fprintf(stderr, gettext("renice: %d:"), who);
3300Sstevel@tonic-gate perror("getpriority");
3310Sstevel@tonic-gate return (1);
3320Sstevel@tonic-gate }
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate if (increment)
3350Sstevel@tonic-gate prio = oldprio + prio;
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate if (setpriority(which, who, prio) < 0) {
3380Sstevel@tonic-gate (void) fprintf(stderr, gettext("renice: %s:"), who_s);
339*2712Snn35248 if (errno == EACCES && prio < oldprio)
3400Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3410Sstevel@tonic-gate " Cannot lower nice value.\n"));
3420Sstevel@tonic-gate else
3430Sstevel@tonic-gate perror("setpriority");
3440Sstevel@tonic-gate return (1);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate return (0);
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate static void
usage()3510Sstevel@tonic-gate usage()
3520Sstevel@tonic-gate {
3530Sstevel@tonic-gate (void) fprintf(stderr,
3540Sstevel@tonic-gate gettext("usage: renice [-n increment] [-i idtype] ID ...\n"));
3550Sstevel@tonic-gate (void) fprintf(stderr,
3560Sstevel@tonic-gate gettext(" renice [-n increment] [-g | -p | -u] ID ...\n"));
3570Sstevel@tonic-gate (void) fprintf(stderr,
3580Sstevel@tonic-gate gettext(" renice priority "
3590Sstevel@tonic-gate "[-p] pid ... [-g pgrp ...] [-p pid ...] [-u user ...]\n"));
3600Sstevel@tonic-gate (void) fprintf(stderr,
3610Sstevel@tonic-gate gettext(" renice priority "
3620Sstevel@tonic-gate " -g pgrp ... [-g pgrp ...] [-p pid ...] [-u user ...]\n"));
3630Sstevel@tonic-gate (void) fprintf(stderr,
3640Sstevel@tonic-gate gettext(" renice priority "
3650Sstevel@tonic-gate " -u user ... [-g pgrp ...] [-p pid ...] [-u user ...]\n"));
3660Sstevel@tonic-gate (void) fprintf(stderr,
3670Sstevel@tonic-gate gettext(" where %d <= priority <= %d\n"), PRIO_MIN, PRIO_MAX);
3680Sstevel@tonic-gate exit(2);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate static int
name2id(char * name)3720Sstevel@tonic-gate name2id(char *name)
3730Sstevel@tonic-gate {
3740Sstevel@tonic-gate type_t *type = types;
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate while (type->name != NULL) {
3770Sstevel@tonic-gate if (strcmp(type->name, name) == 0)
3780Sstevel@tonic-gate return (type->id);
3790Sstevel@tonic-gate type++;
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate (void) fprintf(stderr, gettext("renice: unknown id type: %s\n"), name);
3820Sstevel@tonic-gate exit(1);
3830Sstevel@tonic-gate /*NOTREACHED*/
3840Sstevel@tonic-gate }
385