1 /*
2 * priocntl - process scheduler control
3 *
4 * Gunnar Ritter, Freiburg i. Br., Germany, March 2003.
5 */
6 /*
7 * Copyright (c) 2003 Gunnar Ritter
8 *
9 * This software is provided 'as-is', without any express or implied
10 * warranty. In no event will the authors be held liable for any damages
11 * arising from the use of this software.
12 *
13 * Permission is granted to anyone to use this software for any purpose,
14 * including commercial applications, and to alter it and redistribute
15 * it freely, subject to the following restrictions:
16 *
17 * 1. The origin of this software must not be misrepresented; you must not
18 * claim that you wrote the original software. If you use this software
19 * in a product, an acknowledgment in the product documentation would be
20 * appreciated but is not required.
21 *
22 * 2. Altered source versions must be plainly marked as such, and must not be
23 * misrepresented as being the original software.
24 *
25 * 3. This notice may not be removed or altered from any source distribution.
26 */
27 #if defined (__linux__) || defined (__FreeBSD__)
28
29 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
30 #define USED __attribute__ ((used))
31 #elif defined __GNUC__
32 #define USED __attribute__ ((unused))
33 #else
34 #define USED
35 #endif
36 #if defined (S42)
37 static const char sccsid[] USED = "@(#)priocntl_s42.sl 1.19 (gritter) 7/23/06";
38 #else
39 static const char sccsid[] USED = "@(#)priocntl.sl 1.19 (gritter) 7/23/06";
40 #endif
41
42 #include <sys/time.h>
43 #include <sys/resource.h>
44 #include <unistd.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <errno.h>
49 #include <sched.h>
50 #include <libgen.h>
51 #include <dirent.h>
52 #include <ctype.h>
53
54 #ifndef SCHED_BATCH
55 #define SCHED_BATCH 3
56 #endif
57 #ifndef SCHED_ISO
58 #define SCHED_ISO 4
59 #endif
60
61 #define eq(p, q) (strcmp(p, q) == 0)
62
63 struct idnode {
64 struct idnode *id_nxt;
65 int id_val;
66 int id_upri;
67 int id_class;
68 unsigned long id_tqntm;
69 };
70
71 struct proc {
72 int p_pid;
73 int p_ppid;
74 int p_pgid;
75 int p_sid;
76 int p_class;
77 int p_uid;
78 int p_gid;
79 int p_upri;
80 unsigned long p_tqntm;
81 };
82
83 static enum {
84 ID_PID,
85 ID_PPID,
86 ID_PGID,
87 ID_SID,
88 ID_CLASS,
89 ID_UID,
90 ID_GID,
91 ID_ALL
92 } idtype = ID_PID;
93
94 enum valtype {
95 VT_CHAR,
96 VT_INT,
97 VT_UINT,
98 VT_LONG,
99 VT_ULONG
100 };
101
102 union value {
103 char v_char;
104 int v_int;
105 unsigned int v_uint;
106 long v_long;
107 unsigned long v_ulong;
108 };
109
110 static unsigned errcnt; /* count of errors */
111 static int action; /* one of l, d, s, e */
112 static int cflag = -1; /* selected class */
113 static int iflag; /* an id was specified */
114 static int pflag = -1; /* numeric argument to -p option */
115 static char *progname; /* argv[0] to main() */
116 static struct idnode *idlist; /* list of id criteria */
117 static struct idnode *proclist; /* list of processes */
118
119 static union value *
getval(char ** listp,enum valtype type,int separator,int sep2)120 getval(char **listp, enum valtype type, int separator, int sep2)
121 {
122 char *buf;
123 static union value v;
124 const char *cp, *op;
125 char *cq, *x;
126
127 if (**listp == '\0')
128 return NULL;
129 op = *listp;
130 while (**listp != '\0') {
131 if ((separator == ' ' ? isspace(**listp) :
132 **listp == separator) ||
133 **listp == sep2)
134 break;
135 (*listp)++;
136 }
137 buf = alloca(*listp - op + 1);
138 for (cp = op, cq = buf; cp < *listp; cp++, cq++)
139 *cq = *cp;
140 *cq = '\0';
141 if (**listp) {
142 while ((separator == ' ' ?
143 isspace(**listp) : **listp == separator) ||
144 **listp == sep2)
145 (*listp)++;
146 }
147 switch (type) {
148 case VT_CHAR:
149 if (buf[1] != '\0')
150 return NULL;
151 v.v_char = buf[0];
152 break;
153 case VT_INT:
154 v.v_int = strtol(buf, &x, 10);
155 if (*x != '\0')
156 return NULL;
157 break;
158 case VT_UINT:
159 v.v_uint = strtoul(buf, &x, 10);
160 if (*x != '\0')
161 return NULL;
162 break;
163 case VT_LONG:
164 v.v_long = strtol(buf, &x, 10);
165 if (*x != '\0')
166 return NULL;
167 break;
168 case VT_ULONG:
169 v.v_ulong = strtoul(buf, &x, 10);
170 if (*x != '\0')
171 return NULL;
172 break;
173 }
174 return &v;
175 }
176
177 static void *
srealloc(char * op,size_t size)178 srealloc(char *op, size_t size)
179 {
180 char *np;
181
182 if ((np = realloc(op, size)) == NULL) {
183 write(2, "Out of memory\n", 14);
184 exit(077);
185 }
186 return np;
187 }
188
189 static void *
scalloc(size_t nmemb,size_t size)190 scalloc(size_t nmemb, size_t size)
191 {
192 void *p;
193
194 if ((p = calloc(nmemb, size)) == NULL) {
195 write(2, "Out of memory\n", 14);
196 exit(077);
197 }
198 return p;
199 }
200
201 static void
usage(void)202 usage(void)
203 {
204 fprintf(stderr, "usage:\t%s -l\n\
205 \t%s -d [-i idtype] [idlist]\n\
206 \t%s -s [-c class] [c.s.o.] [-i idtype] [idlist]\n\
207 \t%s -e [-c class] [c.s.o.] command [argument(s)]\n",
208 progname, progname, progname, progname);
209 exit(2);
210 }
211
212 static void
addproc(struct proc * sp)213 addproc(struct proc *sp)
214 {
215 struct idnode *id, *iq;
216
217 id = calloc(1, sizeof *id);
218 id->id_val = sp->p_pid;
219 id->id_upri = sp->p_upri;
220 id->id_class = sp->p_class;
221 id->id_tqntm = sp->p_tqntm;
222 if (proclist) {
223 for (iq = proclist; iq->id_nxt; iq = iq->id_nxt);
224 iq->id_nxt = id;
225 } else
226 proclist = id;
227 }
228
229 static void
tryproc(int val,struct proc * sp)230 tryproc(int val, struct proc *sp)
231 {
232 struct idnode *id;
233
234 if (sp->p_pid == 1 && action == 's' && idtype != ID_PID)
235 return;
236 for (id = idlist; id; id = id->id_nxt) {
237 if (id->id_val == val) {
238 addproc(sp);
239 return;
240 }
241 }
242 }
243
244 #define GETVAL(a) if ((v = getval(&cp, (a), ' ', 0)) == NULL) { \
245 free(sp); \
246 return NULL; \
247 }
248
249 #define GETVAL_COMMA(a) if ((v = getval(&cp, (a), ' ', ',')) == NULL) { \
250 free(sp); \
251 return NULL; \
252 }
253
254 #if defined (__linux__)
255 static struct proc *
getproc(int pid)256 getproc(int pid)
257 {
258 struct proc *sp;
259 static char *buf;
260 static size_t buflen;
261 char fn[256];
262 char line[2049];
263 FILE *fp;
264 union value *v;
265 char *cp, *cq, *ce;
266 size_t sz, sc;
267 int c;
268
269 sp = scalloc(1, sizeof *sp);
270 snprintf(fn, sizeof fn, "/proc/%d/stat", pid);
271 if ((fp = fopen(fn, "r")) == NULL) {
272 free(sp);
273 return NULL;
274 }
275 for (cp = buf; ; ) {
276 const unsigned chunk = 32;
277
278 if (buflen < (sz = cp - buf + chunk)) {
279 sc = cp - buf;
280 buf = srealloc(buf, buflen = sz);
281 cp = &buf[sc];
282 }
283 if ((sz = fread(cp, 1, chunk, fp)) < chunk) {
284 ce = &cp[sz - 1];
285 break;
286 }
287 cp += chunk;
288 }
289 fclose(fp);
290 if (*ce != '\n') {
291 free(sp);
292 return NULL;
293 }
294 *ce-- = '\0';
295 cp = buf;
296 GETVAL(VT_INT);
297 sp->p_pid = v->v_int;
298 if (*cp++ != '(') {
299 free(sp);
300 return NULL;
301 }
302 for (cq = ce; cq >= cp && *cq != ')'; cq--);
303 if (cq < cp) {
304 free(sp);
305 return NULL;
306 }
307 *cq = '\0';
308 cp = &cq[1];
309 while (isspace(*cp))
310 cp++;
311 GETVAL(VT_CHAR); /* state */
312 if (v->v_char == 'Z') {
313 free(sp);
314 return NULL;
315 }
316 GETVAL(VT_INT);
317 sp->p_ppid = v->v_int;
318 GETVAL(VT_INT);
319 sp->p_pgid = v->v_int;
320 GETVAL(VT_INT);
321 sp->p_sid = v->v_int;
322 sp->p_class = sched_getscheduler(pid);
323 if (sp->p_class == SCHED_OTHER || sp->p_class == SCHED_BATCH ||
324 sp->p_class == SCHED_ISO) {
325 GETVAL(VT_INT); /* device */
326 GETVAL(VT_INT); /* tty_pgrp */
327 GETVAL(VT_ULONG); /* flags */
328 GETVAL(VT_ULONG); /* min_flt */
329 GETVAL(VT_ULONG); /* cmin_flt */
330 GETVAL(VT_ULONG); /* maj_flt */
331 GETVAL(VT_ULONG); /* cmaj_flt */
332 GETVAL(VT_ULONG); /* utime */
333 GETVAL(VT_ULONG); /* stime */
334 GETVAL(VT_ULONG); /* cutime */
335 GETVAL(VT_ULONG); /* cstime */
336 GETVAL(VT_LONG); /* internal priority */
337 GETVAL(VT_LONG); /* nice */
338 sp->p_upri = 0 - v->v_long;
339 } else {
340 struct sched_param scp;
341 sched_getparam(pid, &scp);
342 sp->p_upri = scp.sched_priority;
343 if (sp->p_class == SCHED_RR) {
344 struct timespec ts;
345 if (sched_rr_get_interval(pid, &ts) == 0) {
346 sp->p_tqntm = ts.tv_sec * 1000;
347 sp->p_tqntm += ts.tv_nsec / 1000000;
348 } else
349 sp->p_tqntm = 150;
350 }
351 }
352 snprintf(fn, sizeof fn, "/proc/%d/status", pid);
353 if ((fp = fopen(fn, "r")) == NULL) {
354 free(sp);
355 return NULL;
356 }
357 c = 0;
358 while (fgets(line, sizeof line, fp) != NULL) {
359 if (strncmp(line, "Uid:", 4) == 0) {
360 cp = &line[4];
361 while (isspace(*cp))
362 cp++;
363 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
364 fclose(fp);
365 free(sp);
366 return NULL;
367 }
368 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
369 fclose(fp);
370 free(sp);
371 return NULL;
372 }
373 sp->p_uid = v->v_int;
374 c++;
375 }
376 if (strncmp(line, "Gid:", 4) == 0) {
377 cp = &line[4];
378 while (isspace(*cp))
379 cp++;
380 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
381 fclose(fp);
382 free(sp);
383 return NULL;
384 }
385 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) {
386 fclose(fp);
387 free(sp);
388 return NULL;
389 }
390 sp->p_gid = v->v_int;
391 c++;
392 }
393 }
394 fclose(fp);
395 if (c != 2) {
396 free(sp);
397 return NULL;
398 }
399 return sp;
400 }
401
402 #elif defined (__FreeBSD__)
403
404 #define SKIPFIELD while (*cp != ' ') cp++; while (*cp == ' ') cp++;
405
406 static struct proc *
getproc(int pid)407 getproc(int pid)
408 {
409 struct proc *sp;
410 static char *buf;
411 static size_t buflen;
412 struct sched_param s;
413 struct timespec ts;
414 char fn[256];
415 FILE *fp;
416 union value *v;
417 char *cp, *ce;
418 size_t sz, sc;
419
420 sp = scalloc(1, sizeof *sp);
421 snprintf(fn, sizeof fn, "/proc/%d/status", pid);
422 if ((fp = fopen(fn, "r")) == NULL) {
423 free(sp);
424 return NULL;
425 }
426 for (cp = buf; ; ) {
427 const unsigned chunk = 32;
428
429 if (buflen < (sz = cp - buf + chunk)) {
430 sc = cp - buf;
431 buf = srealloc(buf, buflen = sz);
432 cp = &buf[sc];
433 }
434 if ((sz = fread(cp, 1, chunk, fp)) < chunk) {
435 ce = &cp[sz - 1];
436 break;
437 }
438 cp += chunk;
439 }
440 fclose(fp);
441 if (*ce != '\n') {
442 free(sp);
443 return NULL;
444 }
445 *ce-- = '\0';
446 cp = buf;
447 SKIPFIELD; /* name */
448 GETVAL(VT_INT);
449 sp->p_pid = v->v_int;
450 GETVAL(VT_INT);
451 sp->p_ppid = v->v_int;
452 GETVAL(VT_INT);
453 sp->p_pgid = v->v_int;
454 GETVAL(VT_INT);
455 sp->p_sid = v->v_int;
456 SKIPFIELD; /* flags */
457 SKIPFIELD; /* start */
458 SKIPFIELD; /* user time */
459 SKIPFIELD; /* system time */
460 SKIPFIELD; /* wchan */
461 SKIPFIELD; /* euid */
462 GETVAL(VT_INT);
463 sp->p_uid = v->v_int;
464 GETVAL_COMMA(VT_INT);
465 sp->p_gid = v->v_int;
466 switch (sp->p_class = sched_getscheduler(sp->p_pid)) {
467 case SCHED_OTHER:
468 sp->p_upri = 0 - getpriority(PRIO_PROCESS, sp->p_pid);
469 break;
470 case SCHED_RR:
471 if (sched_rr_get_interval(pid, &ts) == 0) {
472 sp->p_tqntm = ts.tv_sec * 1000;
473 sp->p_tqntm += ts.tv_nsec / 1000000;
474 } else
475 sp->p_tqntm = 150;
476 /*FALLTHRU*/
477 case SCHED_FIFO:
478 if (sched_getparam(sp->p_pid, &s) == 0) {
479 sp->p_upri = s.sched_priority;
480 break;
481 }
482 /*FALLTHRU*/
483 default:
484 free(sp);
485 return NULL;
486 }
487 return sp;
488 }
489 #endif /* __FreeBSD__ */
490
491 static void
evalproc(int pid)492 evalproc(int pid)
493 {
494 struct proc *sp;
495
496 if ((sp = getproc(pid)) == NULL)
497 return;
498 switch (idtype) {
499 case ID_PID:
500 tryproc(sp->p_pid, sp);
501 break;
502 case ID_PPID:
503 tryproc(sp->p_ppid, sp);
504 break;
505 case ID_PGID:
506 tryproc(sp->p_pgid, sp);
507 break;
508 case ID_SID:
509 tryproc(sp->p_sid, sp);
510 break;
511 case ID_CLASS:
512 tryproc(sp->p_class, sp);
513 break;
514 case ID_UID:
515 tryproc(sp->p_uid, sp);
516 break;
517 case ID_GID:
518 tryproc(sp->p_gid, sp);
519 break;
520 case ID_ALL:
521 addproc(sp);
522 }
523 free(sp);
524 }
525
526 static void
getprocs(void)527 getprocs(void)
528 {
529 DIR *Dp;
530 struct dirent *dp;
531
532 if ((Dp = opendir("/proc")) == NULL) {
533 fprintf(stderr, "%s: cannot open /proc, errno %d\n",
534 progname, errno);
535 exit(1);
536 }
537 while ((dp = readdir(Dp)) != NULL) {
538 char *x;
539 int pid;
540
541 if ((pid = strtol(dp->d_name, &x, 10)) >= 0 && *x == '\0')
542 evalproc(pid);
543 }
544 closedir(Dp);
545 }
546
547 static void
getidlist(char ** args)548 getidlist(char **args)
549 {
550 if (idtype == ID_ALL)
551 return;
552 if (args == NULL || *args == NULL) {
553 if (iflag) {
554 idlist = scalloc(1, sizeof *idlist);
555 switch (idtype) {
556 case ID_PID:
557 idlist->id_val = getpid();
558 break;
559 case ID_PPID:
560 idlist->id_val = getppid();
561 break;
562 case ID_PGID:
563 idlist->id_val = getpgid(0);
564 break;
565 case ID_SID:
566 idlist->id_val = getsid(0);
567 break;
568 case ID_CLASS:
569 idlist->id_val = sched_getscheduler(0);
570 break;
571 case ID_UID:
572 idlist->id_val = geteuid();
573 break;
574 case ID_GID:
575 idlist->id_val = getegid();
576 break;
577 }
578 return;
579 } else
580 usage();
581 }
582 do {
583 struct idnode *id;
584
585 id = scalloc(1, sizeof *id);
586 if (idtype == ID_CLASS) {
587 if (eq(args[0], "TS"))
588 id->id_val = SCHED_OTHER;
589 else if (eq(args[0], "B"))
590 id->id_val = SCHED_BATCH;
591 else if (eq(args[0], "BA")) /* old */
592 id->id_val = SCHED_BATCH;
593 else if (eq(args[0], "ISO"))
594 id->id_val = SCHED_ISO;
595 else if (eq(args[0], "IS")) /* old */
596 id->id_val = SCHED_ISO;
597 else if (eq(args[0], "FF"))
598 id->id_val = SCHED_FIFO;
599 else if (eq(args[0], "FI")) /* old */
600 id->id_val = SCHED_FIFO;
601 else if (eq(args[0], "RT") || eq(args[0], "FP"))
602 id->id_val = SCHED_RR;
603 else {
604 fprintf(stderr, "%s: Invalid or unconfigured "
605 "class %s in idlist - "
606 "ignored\n",
607 progname, args[0]);
608 free(id);
609 continue;
610 }
611 } else
612 id->id_val = atoi(args[0]);
613 id->id_nxt = idlist;
614 idlist = id;
615 } while (*++args != NULL);
616 }
617
618 static void
noprocs(void)619 noprocs(void)
620 {
621 fprintf(stderr, "%s: Process(es) not found.\n", progname);
622 exit(1);
623 }
624
625 static void
getproclist(char ** args)626 getproclist(char **args)
627 {
628 getidlist(args);
629 getprocs();
630 if (proclist == NULL)
631 noprocs();
632 }
633
634 static void
listclasses(void)635 listclasses(void)
636 {
637 const char *batchclass;
638 const char *isoclass;
639
640 batchclass = sched_get_priority_max(SCHED_BATCH) < 0 ? "" : "\
641 B (Batch)\n\
642 \tConfigured BA User Priority Range: -19 through 20\n\
643 \n";
644 isoclass = sched_get_priority_max(SCHED_ISO) < 0 ? "" : "\
645 ISO (Isochronous)\n\
646 \tConfigured IS User Priority Range: -19 through 20\n\
647 \n";
648 fprintf(stderr, "\
649 CONFIGURED CLASSES\n\
650 ==================\n\
651 \n\
652 TS (Time Sharing)\n\
653 \tConfigured TS User Priority Range: -19 through 20\n\
654 \n"
655 "%s%s"
656 #ifndef S42
657 "\
658 RT (Real Time Round Robin)\n\
659 \tMaximum Configured RT Priority: 99\n\
660 \n"
661 #else /* S42 */
662 "\
663 FP (Real Time Round Robin)\n\
664 \tMaximum Configured FP Priority: 99\n\
665 \n"
666 #endif /* S42 */
667 "FF (Real Time First In-First Out)\n\
668 \tMaximum Configured FI Priority: 99\n\
669 ", batchclass, isoclass);
670 }
671
672 static void
disp_this(int class,const char * title,const char * head)673 disp_this(int class, const char *title, const char *head)
674 {
675 struct idnode *id;
676
677 for (id = proclist; id; id = id->id_nxt)
678 if (id->id_class == class)
679 break;
680 if (id == NULL)
681 return;
682 printf("%s\n PID %s", title, head);
683 if (class == SCHED_RR)
684 printf(" TQNTM");
685 putchar('\n');
686 for (id = proclist; id; id = id->id_nxt) {
687 if (id->id_class == class) {
688 printf("%7d %7d", id->id_val, id->id_upri);
689 if (class == SCHED_RR)
690 printf(" %11lu", id->id_tqntm);
691 putchar('\n');
692 }
693 }
694 }
695
696 static void
display(void)697 display(void)
698 {
699 disp_this(SCHED_OTHER, "TIME SHARING PROCESSES", "TSUPRI");
700 if (sched_get_priority_max(SCHED_BATCH) >= 0)
701 disp_this(SCHED_BATCH, "BATCH PROCESSES", "BAUPRI");
702 if (sched_get_priority_max(SCHED_ISO) >= 0)
703 disp_this(SCHED_ISO, "ISOCHRONOUS PROCESSES", "ISUPRI");
704 #ifndef S42
705 disp_this(SCHED_RR, "REAL TIME PROCESSES", "RTPRI");
706 #else /* S42 */
707 disp_this(SCHED_RR, "FIXED PRIORITY PROCESSES", "FPPRI");
708 #endif /* S42 */
709 disp_this(SCHED_FIFO, "FIFO CLASS PROCESSES", "FIPRI");
710 }
711
712 static int
set_this(int pid,int defclass)713 set_this(int pid, int defclass)
714 {
715 struct sched_param scp;
716 int class, upri;
717
718 memset(&scp, 0, sizeof scp);
719 if (cflag != -1)
720 class = cflag;
721 else
722 class = defclass;
723 if (pflag != -1) {
724 if (class != SCHED_BATCH)
725 scp.sched_priority = pflag;
726 else
727 scp.sched_priority = 0;
728 upri = pflag;
729 } else {
730 sched_getparam(pid, &scp);
731 if (scp.sched_priority == 0 && class != SCHED_BATCH &&
732 class != SCHED_ISO)
733 scp.sched_priority = 1;
734 upri = 0 - getpriority(PRIO_PROCESS, pid);
735 }
736 errno = 0;
737 if ((class == SCHED_RR || class == SCHED_FIFO ||
738 class == SCHED_ISO ||
739 class == SCHED_BATCH) &&
740 sched_setscheduler(pid, class, &scp) < 0)
741 return 1;
742 if ((class == SCHED_OTHER || class == SCHED_BATCH ||
743 class == SCHED_ISO) &&
744 setpriority(PRIO_PROCESS, pid, 0 - upri) < 0)
745 return 2;
746 return 0;
747 }
748
749 static void
set(void)750 set(void)
751 {
752 struct idnode *id;
753 int cnt = 0;
754
755 if (cflag == -1) {
756 for (id = proclist; id; id = id->id_nxt) {
757 if (id->id_class != proclist->id_class) {
758 fprintf(stderr, "%s: Specified processes from "
759 "different classes.\n",
760 progname);
761 exit(1);
762 }
763 }
764 }
765 for (id = proclist; id; id = id->id_nxt) {
766 if (set_this(id->id_val, id->id_class) != 0) {
767 switch (errno) {
768 case EPERM:
769 errcnt |= 1;
770 cnt++;
771 fprintf(stderr, "Permissions error encountered "
772 "on pid %d.\n", id->id_val);
773 break;
774 case ESRCH:
775 /*
776 * Do nothing as this just means that the
777 * process has terminated after we read its
778 * data before.
779 */
780 break;
781 case EINVAL:
782 errcnt |= 1;
783 cnt++;
784 fprintf(stderr, "%s: Invalid argument on "
785 "pid %d.\n",
786 progname, id->id_val);
787 break;
788 default:
789 errcnt |= 1;
790 cnt++;
791 fprintf(stderr, "%s: pid %d: errno %d\n",
792 progname, id->id_val, errno);
793 }
794 } else
795 cnt++;
796 }
797 if (cnt == 0)
798 noprocs();
799 }
800
801 static void
execute(char ** args)802 execute(char **args)
803 {
804 struct proc *sp;
805 int defclass;
806 const char *fcall = NULL;
807
808 if (args == NULL || *args == NULL)
809 usage();
810 if ((sp = getproc(getpid())) != NULL)
811 defclass = sp->p_class;
812 else
813 defclass = SCHED_OTHER;
814 switch (set_this(0, defclass)) {
815 case 0:
816 break;
817 case 1:
818 if (fcall == NULL)
819 fcall = "sched_setparam";
820 /*FALLTHRU*/
821 case 2:
822 if (fcall == NULL)
823 fcall = "setpriority";
824 /*FALLTHRU*/
825 default:
826 if (fcall == NULL)
827 fcall = "unknown";
828 fprintf(stderr, "%s: Can't set scheduling parameters\n"
829 "%s system call failed with errno %d\n",
830 progname, fcall, errno);
831 exit(1);
832 }
833 execvp(args[0], args);
834 fprintf(stderr, "%s: Can't execute %s, exec failed with errno %d\n",
835 progname, args[0], errno);
836 exit(1);
837 }
838
839 static void
selclass(const char * s)840 selclass(const char *s)
841 {
842 if (eq(s, "TS"))
843 cflag = SCHED_OTHER;
844 else if (eq(s, "B"))
845 cflag = SCHED_BATCH;
846 else if (eq(s, "BA")) /* old */
847 cflag = SCHED_BATCH;
848 else if (eq(s, "ISO"))
849 cflag = SCHED_ISO;
850 else if (eq(s, "IS")) /* old */
851 cflag = SCHED_ISO;
852 else if (eq(s, "FF"))
853 cflag = SCHED_FIFO;
854 else if (eq(s, "FI")) /* old */
855 cflag = SCHED_FIFO;
856 else if (eq(s, "RT") || eq(s, "FP"))
857 cflag = SCHED_RR;
858 else {
859 fprintf(stderr, "%s: Invalid or unconfigured class %s\n",
860 progname, s);
861 exit(2);
862 }
863 }
864
865 static void
selid(const char * s)866 selid(const char *s)
867 {
868 if (eq(s, "pid"))
869 idtype = ID_PID;
870 else if (eq(s, "ppid"))
871 idtype = ID_PPID;
872 else if (eq(s, "pgid"))
873 idtype = ID_PGID;
874 else if (eq(s, "sid"))
875 idtype = ID_SID;
876 else if (eq(s, "class"))
877 idtype = ID_CLASS;
878 else if (eq(s, "uid"))
879 idtype = ID_UID;
880 else if (eq(s, "gid"))
881 idtype = ID_GID;
882 else if (eq(s, "all"))
883 idtype = ID_ALL;
884 else {
885 fprintf(stderr, "%s: bad idtype %s\n", progname, s);
886 exit(2);
887 }
888 }
889
890 int
main(int argc,char ** argv)891 main(int argc, char **argv)
892 {
893 const char optstring[] = "ldi:sc:ep:";
894 int i;
895
896 #ifdef __GLIBC__
897 putenv("POSIXLY_CORRECT=1");
898 #endif
899 progname = basename(argv[0]);
900 while ((i = getopt(argc, argv, optstring)) != EOF) {
901 switch (i) {
902 case 'l':
903 case 'd':
904 case 's':
905 case 'e':
906 if (action)
907 usage();
908 action = i;
909 break;
910 case 'c':
911 selclass(optarg);
912 break;
913 case 'p':
914 pflag = atoi(optarg);
915 break;
916 case 'i':
917 iflag = 1;
918 selid(optarg);
919 break;
920 default:
921 usage();
922 }
923 }
924 switch (action) {
925 case 'l':
926 if (iflag || cflag != -1 || pflag != -1)
927 usage();
928 listclasses();
929 break;
930 case 'd':
931 if (cflag != -1)
932 usage();
933 getproclist(&argv[optind]);
934 display();
935 break;
936 case 's':
937 getproclist(&argv[optind]);
938 set();
939 break;
940 case 'e':
941 if (iflag)
942 usage();
943 execute(&argv[optind]);
944 break;
945 default:
946 usage();
947 }
948 return errcnt;
949 }
950
951 #else /* !__linux__, !__FreeBSD__ */
952
953 #include <unistd.h>
954
955 int
main(int argc,char ** argv)956 main(int argc, char **argv)
957 {
958 execv("/usr/bin/priocntl", argv);
959 write(2, "priocntl not available\n", 23);
960 _exit(0177);
961 }
962
963 #endif /* !__linux__, !__FreeBSD__ */
964