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