1 /* $OpenBSD: renice.c,v 1.21 2019/01/25 00:19:26 millert Exp $ */ 2 3 /* 4 * Copyright (c) 2009, 2015 Todd C. Miller <millert@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/time.h> 21 #include <sys/resource.h> 22 23 #include <ctype.h> 24 #include <err.h> 25 #include <errno.h> 26 #include <limits.h> 27 #include <pwd.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 33 #define RENICE_NONE 0 34 #define RENICE_ABSOLUTE 1 35 #define RENICE_INCREMENT 2 36 37 struct renice_param { 38 int pri; 39 short pri_type; 40 short id_type; 41 id_t id; 42 }; 43 44 int main(int, char **); 45 static int renice(struct renice_param *, struct renice_param *); 46 __dead void usage(void); 47 48 int 49 main(int argc, char **argv) 50 { 51 struct renice_param *params, *p; 52 struct passwd *pw; 53 int ch, id_type = PRIO_PROCESS; 54 int pri = 0, pri_type = RENICE_NONE; 55 char *ep, *idstr; 56 const char *errstr; 57 58 if (pledge("stdio getpw proc", NULL) == -1) 59 err(1, "pledge"); 60 61 if (argc < 3) 62 usage(); 63 64 /* Allocate enough space for the worst case. */ 65 params = p = reallocarray(NULL, argc - 1, sizeof(*params)); 66 if (params == NULL) 67 err(1, NULL); 68 69 /* Backwards compatibility: first arg may be priority. */ 70 if (isdigit((unsigned char)argv[1][0]) || 71 ((argv[1][0] == '+' || argv[1][0] == '-') && 72 isdigit((unsigned char)argv[1][1]))) { 73 pri = (int)strtol(argv[1], &ep, 10); 74 if (*ep != '\0' || ep == argv[1]) { 75 warnx("invalid priority %s", argv[1]); 76 usage(); 77 } 78 pri_type = RENICE_ABSOLUTE; 79 optind = 2; 80 } 81 82 /* 83 * Slightly tricky getopt() usage since it is legal to have 84 * option flags interleaved with arguments. 85 */ 86 for (;;) { 87 if ((ch = getopt(argc, argv, "g:n:p:u:")) != -1) { 88 switch (ch) { 89 case 'g': 90 id_type = PRIO_PGRP; 91 idstr = optarg; 92 break; 93 case 'n': 94 pri = (int)strtol(optarg, &ep, 10); 95 if (*ep != '\0' || ep == optarg) { 96 warnx("invalid increment %s", optarg); 97 usage(); 98 } 99 100 /* Set priority for previous entries? */ 101 if (pri_type == RENICE_NONE) { 102 struct renice_param *pp; 103 for (pp = params; pp != p; pp++) { 104 pp->pri = pri; 105 pp->pri_type = RENICE_INCREMENT; 106 } 107 } 108 pri_type = RENICE_INCREMENT; 109 continue; 110 case 'p': 111 id_type = PRIO_PROCESS; 112 idstr = optarg; 113 break; 114 case 'u': 115 id_type = PRIO_USER; 116 idstr = optarg; 117 break; 118 default: 119 usage(); 120 break; 121 } 122 } else { 123 idstr = argv[optind++]; 124 if (idstr == NULL) 125 break; 126 } 127 p->id_type = id_type; 128 p->pri = pri; 129 p->pri_type = pri_type; 130 if (id_type == PRIO_USER) { 131 if ((pw = getpwnam(idstr)) == NULL) { 132 uid_t id = strtonum(idstr, 0, UID_MAX, &errstr); 133 if (!errstr) 134 pw = getpwuid(id); 135 } 136 if (pw == NULL) { 137 warnx("unknown user %s", idstr); 138 continue; 139 } 140 p->id = pw->pw_uid; 141 } else { 142 p->id = strtonum(idstr, 0, UINT_MAX, &errstr); 143 if (errstr) { 144 warnx("%s is %s", idstr, errstr); 145 continue; 146 } 147 } 148 p++; 149 } 150 if (pri_type == RENICE_NONE) 151 usage(); 152 return(renice(params, p)); 153 } 154 155 static int 156 renice(struct renice_param *p, struct renice_param *end) 157 { 158 int new, old, errors = 0; 159 160 for (; p < end; p++) { 161 errno = 0; 162 old = getpriority(p->id_type, p->id); 163 if (errno) { 164 warn("getpriority: %d", p->id); 165 errors++; 166 continue; 167 } 168 if (p->pri_type == RENICE_INCREMENT) 169 p->pri += old; 170 new = p->pri > PRIO_MAX ? PRIO_MAX : 171 p->pri < PRIO_MIN ? PRIO_MIN : p->pri; 172 if (setpriority(p->id_type, p->id, new) == -1) { 173 warn("setpriority: %d", p->id); 174 errors++; 175 continue; 176 } 177 printf("%d: old priority %d, new priority %d\n", 178 p->id, old, new); 179 } 180 return (errors); 181 } 182 183 __dead void 184 usage(void) 185 { 186 fprintf(stderr, "usage: renice [-n] increment [-gpu] id\n"); 187 exit(1); 188 } 189