1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <sys/types.h>
36 #include <sys/priocntl.h>
37 #include <sys/tspriocntl.h>
38 #include <sys/param.h>
39 #include <sys/ts.h>
40
41 #include "dispadmin.h"
42
43 /*
44 * This file contains the class specific code implementing
45 * the time-sharing dispadmin sub-command.
46 */
47
48 #define BASENMSZ 16
49
50 extern char *basename();
51
52 static void get_tsdptbl(), set_tsdptbl();
53
54 static char usage[] =
55 "usage: dispadmin -l\n\
56 dispadmin -c TS -g [-r res]\n\
57 dispadmin -c TS -s infile\n";
58
59 static char basenm[BASENMSZ];
60 static char cmdpath[256];
61
62
63 int
main(int argc,char ** argv)64 main(int argc, char **argv)
65 {
66 extern char *optarg;
67
68 int c;
69 int lflag, gflag, rflag, sflag;
70 ulong_t res;
71 char *infile;
72
73 (void) strcpy(cmdpath, argv[0]);
74 (void) strcpy(basenm, basename(argv[0]));
75 lflag = gflag = rflag = sflag = 0;
76 while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) {
77 switch (c) {
78
79 case 'l':
80 lflag++;
81 break;
82
83 case 'c':
84 if (strcmp(optarg, "TS") != 0)
85 fatalerr("error: %s executed for %s class, \
86 %s is actually sub-command for TS class\n", cmdpath, optarg, cmdpath);
87 break;
88
89 case 'g':
90 gflag++;
91 break;
92
93 case 'r':
94 rflag++;
95 res = strtoul(optarg, (char **)NULL, 10);
96 break;
97
98 case 's':
99 sflag++;
100 infile = optarg;
101 break;
102
103 case '?':
104 fatalerr(usage);
105
106 default:
107 break;
108 }
109 }
110
111 if (lflag) {
112 if (gflag || rflag || sflag)
113 fatalerr(usage);
114
115 (void) printf("TS\t(Time Sharing)\n");
116 return (0);
117
118 } else if (gflag) {
119 if (lflag || sflag)
120 fatalerr(usage);
121
122 if (rflag == 0)
123 res = 1000;
124
125 get_tsdptbl(res);
126 return (0);
127
128 } else if (sflag) {
129 if (lflag || gflag || rflag)
130 fatalerr(usage);
131
132 set_tsdptbl(infile);
133 return (0);
134
135 } else {
136 fatalerr(usage);
137 }
138 return (1);
139 }
140
141
142 /*
143 * Retrieve the current ts_dptbl from memory, convert the time quantum
144 * values to the resolution specified by res and write the table to stdout.
145 */
146 static void
get_tsdptbl(ulong_t res)147 get_tsdptbl(ulong_t res)
148 {
149 int i;
150 int tsdpsz;
151 pcinfo_t pcinfo;
152 pcadmin_t pcadmin;
153 tsadmin_t tsadmin;
154 tsdpent_t *ts_dptbl;
155 hrtimer_t hrtime;
156
157 (void) strcpy(pcinfo.pc_clname, "TS");
158 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
159 fatalerr("%s: Can't get TS class ID, priocntl system \
160 call failed with errno %d\n", basenm, errno);
161
162 pcadmin.pc_cid = pcinfo.pc_cid;
163 pcadmin.pc_cladmin = (char *)&tsadmin;
164 tsadmin.ts_cmd = TS_GETDPSIZE;
165
166 if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
167 fatalerr("%s: Can't get ts_dptbl size, priocntl system \
168 call failed with errno %d\n", basenm, errno);
169
170 tsdpsz = tsadmin.ts_ndpents * sizeof (tsdpent_t);
171 if ((ts_dptbl = (tsdpent_t *)malloc(tsdpsz)) == NULL)
172 fatalerr("%s: Can't allocate memory for ts_dptbl\n", basenm);
173
174 tsadmin.ts_dpents = ts_dptbl;
175
176 tsadmin.ts_cmd = TS_GETDPTBL;
177 if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
178 fatalerr("%s: Can't get ts_dptbl, priocntl system call \
179 call failed with errno %d\n", basenm, errno);
180
181 (void) printf("# Time Sharing Dispatcher Configuration\n");
182 (void) printf("RES=%ld\n\n", res);
183 (void) printf("# ts_quantum ts_tqexp ts_slpret ts_maxwait ts_lwait \
184 PRIORITY LEVEL\n");
185
186 for (i = 0; i < tsadmin.ts_ndpents; i++) {
187 if (res != HZ) {
188 hrtime.hrt_secs = 0;
189 hrtime.hrt_rem = ts_dptbl[i].ts_quantum;
190 hrtime.hrt_res = HZ;
191 if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1)
192 fatalerr("%s: Can't convert to requested \
193 resolution\n", basenm);
194 if ((ts_dptbl[i].ts_quantum = hrtconvert(&hrtime))
195 == -1)
196 fatalerr("%s: Can't express time quantum in "
197 "requested resolution,\n"
198 "try coarser resolution\n", basenm);
199 }
200 (void) printf("%10d%10d%10d%12d%10d # %3d\n",
201 ts_dptbl[i].ts_quantum, ts_dptbl[i].ts_tqexp,
202 ts_dptbl[i].ts_slpret, ts_dptbl[i].ts_maxwait,
203 ts_dptbl[i].ts_lwait, i);
204 }
205 }
206
207
208 /*
209 * Read the ts_dptbl values from infile, convert the time quantum values
210 * to HZ resolution, do a little sanity checking and overwrite the table
211 * in memory with the values from the file.
212 */
213 static void
set_tsdptbl(infile)214 set_tsdptbl(infile)
215 char *infile;
216 {
217 int i;
218 int ntsdpents;
219 char *tokp;
220 pcinfo_t pcinfo;
221 pcadmin_t pcadmin;
222 tsadmin_t tsadmin;
223 tsdpent_t *ts_dptbl;
224 int linenum;
225 ulong_t res;
226 hrtimer_t hrtime;
227 FILE *fp;
228 char buf[512];
229 int wslength;
230
231 (void) strcpy(pcinfo.pc_clname, "TS");
232 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
233 fatalerr("%s: Can't get TS class ID, priocntl system \
234 call failed with errno %d\n", basenm, errno);
235
236 pcadmin.pc_cid = pcinfo.pc_cid;
237 pcadmin.pc_cladmin = (char *)&tsadmin;
238 tsadmin.ts_cmd = TS_GETDPSIZE;
239
240 if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
241 fatalerr("%s: Can't get ts_dptbl size, priocntl system \
242 call failed with errno %d\n", basenm, errno);
243
244 ntsdpents = tsadmin.ts_ndpents;
245 if ((ts_dptbl =
246 (tsdpent_t *)malloc(ntsdpents * sizeof (tsdpent_t))) == NULL)
247 fatalerr("%s: Can't allocate memory for ts_dptbl\n", basenm);
248
249 if ((fp = fopen(infile, "r")) == NULL)
250 fatalerr("%s: Can't open %s for input\n", basenm, infile);
251
252 linenum = 0;
253
254 /*
255 * Find the first non-blank, non-comment line. A comment line
256 * is any line with '#' as the first non-white-space character.
257 */
258 do {
259 if (fgets(buf, sizeof (buf), fp) == NULL)
260 fatalerr("%s: Too few lines in input table\n", basenm);
261 linenum++;
262 } while (buf[0] == '#' || buf[0] == '\0' ||
263 (wslength = strspn(buf, " \t\n")) == strlen(buf) ||
264 strchr(buf, '#') == buf + wslength);
265
266 if ((tokp = strtok(buf, " \t")) == NULL)
267 fatalerr("%s: Bad RES specification, line %d of input file\n",
268 basenm, linenum);
269 if ((int)strlen(tokp) > 4) {
270 if (strncmp(tokp, "RES=", 4) != 0)
271 fatalerr("%s: Bad RES specification, \
272 line %d of input file\n", basenm, linenum);
273 if (tokp[4] == '-')
274 fatalerr("%s: Bad RES specification, \
275 line %d of input file\n", basenm, linenum);
276 res = strtoul(&tokp[4], (char **)NULL, 10);
277 } else if (strlen(tokp) == 4) {
278 if (strcmp(tokp, "RES=") != 0)
279 fatalerr("%s: Bad RES specification, \
280 line %d of input file\n", basenm, linenum);
281 if ((tokp = strtok(NULL, " \t")) == NULL)
282 fatalerr("%s: Bad RES specification, \
283 line %d of input file\n", basenm, linenum);
284 if (tokp[0] == '-')
285 fatalerr("%s: Bad RES specification, \
286 line %d of input file\n", basenm, linenum);
287 res = strtoul(tokp, (char **)NULL, 10);
288 } else if (strlen(tokp) == 3) {
289 if (strcmp(tokp, "RES") != 0)
290 fatalerr("%s: Bad RES specification, \
291 line %d of input file\n", basenm, linenum);
292 if ((tokp = strtok(NULL, " \t")) == NULL)
293 fatalerr("%s: Bad RES specification, \
294 line %d of input file\n", basenm, linenum);
295 if ((int)strlen(tokp) > 1) {
296 if (strncmp(tokp, "=", 1) != 0)
297 fatalerr("%s: Bad RES specification, \
298 line %d of input file\n", basenm, linenum);
299 if (tokp[1] == '-')
300 fatalerr("%s: Bad RES specification, \
301 line %d of input file\n", basenm, linenum);
302 res = strtoul(&tokp[1], (char **)NULL, 10);
303 } else if (strlen(tokp) == 1) {
304 if ((tokp = strtok(NULL, " \t")) == NULL)
305 fatalerr("%s: Bad RES specification, \
306 line %d of input file\n", basenm, linenum);
307 if (tokp[0] == '-')
308 fatalerr("%s: Bad RES specification, \
309 line %d of input file\n", basenm, linenum);
310 res = strtoul(tokp, (char **)NULL, 10);
311 }
312 } else {
313 fatalerr("%s: Bad RES specification, line %d of input file\n",
314 basenm, linenum);
315 }
316
317 /*
318 * The remainder of the input file should contain exactly enough
319 * non-blank, non-comment lines to fill the table (ts_ndpents lines).
320 * We assume that any non-blank, non-comment line is data for the
321 * table and fail if we find more or less than we need.
322 */
323 for (i = 0; i < tsadmin.ts_ndpents; i++) {
324
325 /*
326 * Get the next non-blank, non-comment line.
327 */
328 do {
329 if (fgets(buf, sizeof (buf), fp) == NULL)
330 fatalerr("%s: Too few lines in input table\n",
331 basenm);
332 linenum++;
333 } while (buf[0] == '#' || buf[0] == '\0' ||
334 (wslength = strspn(buf, " \t\n")) == strlen(buf) ||
335 strchr(buf, '#') == buf + wslength);
336
337 if ((tokp = strtok(buf, " \t")) == NULL)
338 fatalerr("%s: Too few values, line %d of input file\n",
339 basenm, linenum);
340
341 if (res != HZ) {
342 hrtime.hrt_secs = 0;
343 hrtime.hrt_rem = atol(tokp);
344 hrtime.hrt_res = res;
345 if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1)
346 fatalerr("%s: Can't convert specified "
347 "resolution to ticks\n", basenm);
348 if ((ts_dptbl[i].ts_quantum = hrtconvert(&hrtime))
349 == -1)
350 fatalerr("%s: ts_quantum value out of "
351 "valid range; line %d of input,\n"
352 "table not overwritten\n",
353 basenm, linenum);
354 } else {
355 ts_dptbl[i].ts_quantum = atol(tokp);
356 }
357 if (ts_dptbl[i].ts_quantum <= 0)
358 fatalerr("%s: ts_quantum value out of valid range; "
359 "line %d of input,\ntable not overwritten\n",
360 basenm, linenum);
361
362 if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#')
363 fatalerr("%s: Too few values, line %d of input file\n",
364 basenm, linenum);
365 ts_dptbl[i].ts_tqexp = (short)atoi(tokp);
366 if (ts_dptbl[i].ts_tqexp < 0 ||
367 ts_dptbl[i].ts_tqexp > tsadmin.ts_ndpents)
368 fatalerr("%s: ts_tqexp value out of valid range; "
369 "line %d of input,\ntable not overwritten\n",
370 basenm, linenum);
371
372 if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#')
373 fatalerr("%s: Too few values, line %d of input file\n",
374 basenm, linenum);
375 ts_dptbl[i].ts_slpret = (short)atoi(tokp);
376 if (ts_dptbl[i].ts_slpret < 0 ||
377 ts_dptbl[i].ts_slpret > tsadmin.ts_ndpents)
378 fatalerr("%s: ts_slpret value out of valid range; "
379 "line %d of input,\ntable not overwritten\n",
380 basenm, linenum);
381
382 if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#')
383 fatalerr("%s: Too few values, line %d of input file\n",
384 basenm, linenum);
385 ts_dptbl[i].ts_maxwait = (short)atoi(tokp);
386 if (ts_dptbl[i].ts_maxwait < 0)
387 fatalerr("%s: ts_maxwait value out of valid range; "
388 "line %d of input,\ntable not overwritten\n",
389 basenm, linenum);
390
391 if ((tokp = strtok(NULL, " \t")) == NULL || tokp[0] == '#')
392 fatalerr("%s: Too few values, line %d of input file\n",
393 basenm, linenum);
394 ts_dptbl[i].ts_lwait = (short)atoi(tokp);
395 if (ts_dptbl[i].ts_lwait < 0 ||
396 ts_dptbl[i].ts_lwait > tsadmin.ts_ndpents)
397 fatalerr("%s: ts_lwait value out of valid range; "
398 "line %d of input,\ntable not overwritten\n",
399 basenm, linenum);
400
401 if ((tokp = strtok(NULL, " \t")) != NULL && tokp[0] != '#')
402 fatalerr("%s: Too many values, line %d of input file\n",
403 basenm, linenum);
404 }
405
406 /*
407 * We've read enough lines to fill the table. We fail
408 * if the input file contains any more.
409 */
410 while (fgets(buf, sizeof (buf), fp) != NULL) {
411 if (buf[0] != '#' && buf[0] != '\0' &&
412 (wslength = strspn(buf, " \t\n")) != strlen(buf) &&
413 strchr(buf, '#') != buf + wslength)
414 fatalerr("%s: Too many lines in input table\n",
415 basenm);
416 }
417
418 tsadmin.ts_dpents = ts_dptbl;
419 tsadmin.ts_cmd = TS_SETDPTBL;
420 if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
421 fatalerr("%s: Can't set ts_dptbl, priocntl system call \
422 failed with errno %d\n", basenm, errno);
423 }
424