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