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	<sys/types.h>
35 #include	<sys/priocntl.h>
36 #include	<sys/fxpriocntl.h>
37 #include	<sys/param.h>
38 #include	<errno.h>
39 #include	<sys/fx.h>
40 
41 #include	"dispadmin.h"
42 
43 /*
44  * This file contains the class specific code implementing
45  * the fixed-priority dispadmin sub-command.
46  */
47 
48 #define	BASENMSZ	16
49 
50 extern char	*basename();
51 
52 static void	get_fxdptbl(), set_fxdptbl();
53 
54 static char usage[] = "usage:	dispadmin -l\n"
55 			    "dispadmin -c FX -g [-r res]\n"
56 			    "dispadmin -c FX -s infile\n";
57 
58 static char	basenm[BASENMSZ];
59 static char	cmdpath[256];
60 
61 
62 int
63 main(int argc, char **argv)
64 {
65 	int		c;
66 	int		lflag, gflag, rflag, sflag;
67 	ulong_t		res;
68 	char		*infile;
69 	char 		*endp;
70 
71 	(void) strcpy(cmdpath, argv[0]);
72 	(void) strcpy(basenm, basename(argv[0]));
73 	lflag = gflag = rflag = sflag = 0;
74 	while ((c = getopt(argc, argv, "lc:gr:s:")) != -1) {
75 		switch (c) {
76 
77 		case 'l':
78 			lflag++;
79 			break;
80 
81 		case 'c':
82 			if (strcmp(optarg, "FX") != 0)
83 				fatalerr("error: %s executed for %s class, "
84 				    "%s is actually sub-command for FX class\n",
85 				    cmdpath, optarg, cmdpath);
86 			break;
87 
88 		case 'g':
89 			gflag++;
90 			break;
91 
92 		case 'r':
93 			rflag++;
94 			errno = 0;
95 			res = strtoul(optarg, &endp, 10);
96 			if (res == 0 || errno != 0 || *endp != '\0')
97 				fatalerr("%s: Can't convert to requested "
98 				    "resolution\n", basenm);
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 
115 	if (lflag) {
116 		if (gflag || rflag || sflag)
117 			fatalerr(usage);
118 
119 		(void) printf("FX\t(Fixed Priority)\n");
120 		return (0);
121 
122 	} else if (gflag) {
123 		if (sflag)
124 			fatalerr(usage);
125 
126 		if (rflag == 0)
127 			res = 1000;
128 
129 		get_fxdptbl(res);
130 		return (0);
131 
132 	} else if (sflag) {
133 		if (rflag)
134 			fatalerr(usage);
135 
136 		set_fxdptbl(infile);
137 		return (0);
138 
139 	} else {
140 		fatalerr(usage);
141 	}
142 	return (1);
143 }
144 
145 
146 /*
147  * Retrieve the current fx_dptbl from memory, convert the time quantum
148  * values to the resolution specified by res and write the table to stdout.
149  */
150 static void
151 get_fxdptbl(ulong_t res)
152 {
153 	int		i;
154 	int		fxdpsz;
155 	pcinfo_t	pcinfo;
156 	pcadmin_t	pcadmin;
157 	fxadmin_t	fxadmin;
158 	fxdpent_t	*fx_dptbl;
159 	hrtimer_t	hrtime;
160 
161 	(void) strcpy(pcinfo.pc_clname, "FX");
162 	if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
163 		fatalerr("%s: Can't get FX class ID, priocntl system call "
164 		    "failed with errno %d\n", basenm, errno);
165 
166 	pcadmin.pc_cid = pcinfo.pc_cid;
167 	pcadmin.pc_cladmin = (char *)&fxadmin;
168 	fxadmin.fx_cmd = FX_GETDPSIZE;
169 
170 	if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
171 		fatalerr("%s: Can't get fx_dptbl size, priocntl system call "
172 		    "failed with errno %d\n", basenm, errno);
173 
174 	fxdpsz = fxadmin.fx_ndpents * sizeof (fxdpent_t);
175 	if ((fx_dptbl = (fxdpent_t *)malloc(fxdpsz)) == NULL)
176 		fatalerr("%s: Can't allocate memory for fx_dptbl\n", basenm);
177 
178 	fxadmin.fx_dpents = fx_dptbl;
179 
180 	fxadmin.fx_cmd = FX_GETDPTBL;
181 	if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
182 		fatalerr("%s: Can't get fx_dptbl, priocntl system call "
183 		    "failed with errno %d\n", basenm, errno);
184 
185 	(void) printf("# Fixed Priority Dispatcher Configuration\n");
186 	(void) printf("RES=%ld\n\n", res);
187 	(void) printf("# TIME QUANTUM                    PRIORITY\n");
188 	(void) printf("# (fx_quantum)                      LEVEL\n");
189 
190 	for (i = 0; i < fxadmin.fx_ndpents; i++) {
191 		if (res != HZ && fx_dptbl[i].fx_quantum != FX_TQINF) {
192 			hrtime.hrt_secs = 0;
193 			hrtime.hrt_rem = fx_dptbl[i].fx_quantum;
194 			hrtime.hrt_res = HZ;
195 			if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1)
196 				fatalerr("%s: Can't convert to requested "
197 				    "resolution\n", basenm);
198 			if ((fx_dptbl[i].fx_quantum = hrtconvert(&hrtime))
199 									== -1)
200 				fatalerr("%s: Can't express time quantum in "
201 				    "requested resolution,\n"
202 				    "try coarser resolution\n", basenm);
203 		}
204 		(void) printf("%10d                    #      %3d\n",
205 		    fx_dptbl[i].fx_quantum, i);
206 	}
207 }
208 
209 
210 /*
211  * Read the fx_dptbl values from infile, convert the time quantum values
212  * to HZ resolution, do a little sanity checking and overwrite the table
213  * in memory with the values from the file.
214  */
215 static void
216 set_fxdptbl(char *infile)
217 {
218 	int		i;
219 	int		nfxdpents;
220 	char		*tokp;
221 	pcinfo_t	pcinfo;
222 	pcadmin_t	pcadmin;
223 	fxadmin_t	fxadmin;
224 	fxdpent_t	*fx_dptbl;
225 	int		linenum;
226 	ulong_t		res;
227 	hrtimer_t	hrtime;
228 	FILE		*fp;
229 	char		buf[512];
230 	int		wslength;
231 	char 		*endp;
232 	char		name[512], value[512];
233 	int		len;
234 
235 	(void) strcpy(pcinfo.pc_clname, "FX");
236 	if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
237 		fatalerr("%s: Can't get FX class ID, priocntl system call "
238 		    "failed with errno %d\n", basenm, errno);
239 
240 	pcadmin.pc_cid = pcinfo.pc_cid;
241 	pcadmin.pc_cladmin = (char *)&fxadmin;
242 	fxadmin.fx_cmd = FX_GETDPSIZE;
243 
244 	if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
245 		fatalerr("%s: Can't get fx_dptbl size, priocntl system call "
246 		    "failed with errno %d\n", basenm, errno);
247 
248 	nfxdpents = fxadmin.fx_ndpents;
249 	if ((fx_dptbl =
250 	    (fxdpent_t *)malloc(nfxdpents * sizeof (fxdpent_t))) == NULL)
251 		fatalerr("%s: Can't allocate memory for fx_dptbl\n", basenm);
252 
253 	if ((fp = fopen(infile, "r")) == NULL)
254 		fatalerr("%s: Can't open %s for input\n", basenm, infile);
255 
256 	linenum = 0;
257 
258 	/*
259 	 * Find the first non-blank, non-comment line.  A comment line
260 	 * is any line with '#' as the first non-white-space character.
261 	 */
262 	do {
263 		if (fgets(buf, sizeof (buf), fp) == NULL)
264 			fatalerr("%s: Too few lines in input table\n", basenm);
265 		linenum++;
266 	} while (buf[0] == '#' || buf[0] == '\0' ||
267 	    (wslength = strspn(buf, " \t\n")) == strlen(buf) ||
268 	    strchr(buf, '#') == buf + wslength);
269 
270 	/* LINTED - unbounded string specifier */
271 	if (sscanf(buf, " %[^=]=%s \n%n", name, value, &len) == 2 &&
272 	    name[0] != '\0' && value[0] != '\0' && len == strlen(buf)) {
273 
274 		if (strcmp(name, "RES") == 0) {
275 			errno = 0;
276 			i = (int)strtol(value, &endp, 10);
277 			if (errno != 0 || endp == value ||
278 			    i < 0 || *endp != '\0')
279 				fatalerr("%s: Bad RES specification, "
280 				    "line %d of input file\n", basenm, linenum);
281 			else
282 				res = i;
283 		} else {
284 			fatalerr("%s: Bad RES specification, "
285 			    "line %d of input file\n", basenm, linenum);
286 		}
287 	}
288 
289 	/*
290 	 * The remainder of the input file should contain exactly enough
291 	 * non-blank, non-comment lines to fill the table (fx_ndpents lines).
292 	 * We assume that any non-blank, non-comment line is data for the
293 	 * table and fail if we find more or less than we need.
294 	 */
295 	for (i = 0; i < fxadmin.fx_ndpents; i++) {
296 
297 		/*
298 		 * Get the next non-blank, non-comment line.
299 		 */
300 		do {
301 			if (fgets(buf, sizeof (buf), fp) == NULL)
302 				fatalerr("%s: Too few lines in input table\n",
303 				    basenm);
304 			linenum++;
305 		} while (buf[0] == '#' || buf[0] == '\0' ||
306 		    (wslength = strspn(buf, " \t\n")) == strlen(buf) ||
307 		    strchr(buf, '#') == buf + wslength);
308 
309 		if ((tokp = strtok(buf, " \t")) == NULL)
310 			fatalerr("%s: Too few values, line %d of input file\n",
311 			    basenm, linenum);
312 
313 		fx_dptbl[i].fx_quantum = atol(tokp);
314 		if (fx_dptbl[i].fx_quantum <= 0) {
315 				fatalerr("%s: fx_quantum value out of "
316 				    "valid range; line %d of input,\n"
317 				    "table not overwritten\n", basenm, linenum);
318 		} else if (res != HZ) {
319 			hrtime.hrt_secs = 0;
320 			hrtime.hrt_rem = fx_dptbl[i].fx_quantum;
321 			hrtime.hrt_res = res;
322 			if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1)
323 				fatalerr("%s: Can't convert specified "
324 				    "resolution to ticks\n", basenm);
325 			if ((fx_dptbl[i].fx_quantum =
326 			    hrtconvert(&hrtime)) == -1)
327 				fatalerr("%s: fx_quantum value out of "
328 				    "valid range; line %d of input,\n"
329 				    "table not overwritten\n", basenm, linenum);
330 		}
331 
332 		if ((tokp = strtok(NULL, " \t")) != NULL && tokp[0] != '#')
333 			fatalerr("%s: Too many values, line %d of input file\n",
334 			    basenm, linenum);
335 	}
336 
337 	/*
338 	 * We've read enough lines to fill the table.  We fail
339 	 * if the input file contains any more.
340 	 */
341 	while (fgets(buf, sizeof (buf), fp) != NULL) {
342 		if (buf[0] != '#' && buf[0] != '\0' &&
343 		    (wslength = strspn(buf, " \t\n")) != strlen(buf) &&
344 		    strchr(buf, '#') != buf + wslength)
345 			fatalerr("%s: Too many lines in input table\n",
346 				basenm);
347 	}
348 
349 	fxadmin.fx_dpents = fx_dptbl;
350 	fxadmin.fx_cmd = FX_SETDPTBL;
351 	if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1)
352 		fatalerr("%s: Can't set fx_dptbl, priocntl system call failed "
353 		    "with errno %d\n", basenm, errno);
354 }
355