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
53extern char	*basename();
54
55static void	get_tsdptbl(), set_tsdptbl();
56
57static char usage[] =
58"usage:	dispadmin -l\n\
59	dispadmin -c TS -g [-r res]\n\
60	dispadmin -c TS -s infile\n";
61
62static char	basenm[BASENMSZ];
63static char	cmdpath[256];
64
65
66int
67main(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 */
149static void
150get_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 \
163call 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 \
171call 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 \
182call 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  \
187PRIORITY 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 \
196resolution\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 */
216static void
217set_tsdptbl(infile)
218char	*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 \
237call 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 \
245call 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, \
275line %d of input file\n", basenm, linenum);
276		if (tokp[4] == '-')
277			fatalerr("%s: Bad RES specification, \
278line %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, \
283line %d of input file\n", basenm, linenum);
284		if ((tokp = strtok(NULL, " \t")) == NULL)
285			fatalerr("%s: Bad RES specification, \
286line %d of input file\n", basenm, linenum);
287		if (tokp[0] == '-')
288			fatalerr("%s: Bad RES specification, \
289line %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, \
294line %d of input file\n", basenm, linenum);
295		if ((tokp = strtok(NULL, " \t")) == NULL)
296			fatalerr("%s: Bad RES specification, \
297line %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, \
301line %d of input file\n", basenm, linenum);
302			if (tokp[1] == '-')
303				fatalerr("%s: Bad RES specification, \
304line %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, \
309line %d of input file\n", basenm, linenum);
310			if (tokp[0] == '-')
311				fatalerr("%s: Bad RES specification, \
312line %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 \
425failed with errno %d\n", basenm, errno);
426}
427