off-by-one in group_from_gid; from Jeff Forys
[unix-history] / usr / src / usr.sbin / sysctl / sysctl.c
CommitLineData
33a39b1e
KM
1/*
2 * Copyright (c) 1993 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8#ifndef lint
9char copyright[] =
10"@(#) Copyright (c) 1993 The Regents of the University of California.\n\
11 All rights reserved.\n";
12#endif /* not lint */
13
14#ifndef lint
cdbdb4d7 15static char sccsid[] = "@(#)sysctl.c 5.6 (Berkeley) %G%";
33a39b1e
KM
16#endif /* not lint */
17
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <sys/sysctl.h>
21#include <sys/socket.h>
22#include <vm/vm_param.h>
129fa670
KM
23#include <netinet/in.h>
24#include <netinet/in_systm.h>
25#include <netinet/ip.h>
26#include <netinet/ip_icmp.h>
27#include <netinet/icmp_var.h>
33a39b1e
KM
28#include <errno.h>
29#include <stdlib.h>
30#include <string.h>
31#include <stdio.h>
32
129fa670
KM
33struct ctlname topname[] = CTL_NAMES;
34struct ctlname kernname[] = CTL_KERN_NAMES;
35struct ctlname vmname[] = CTL_VM_NAMES;
36struct ctlname netname[] = CTL_NET_NAMES;
37struct ctlname hwname[] = CTL_HW_NAMES;
1fdacbde
KM
38struct ctlname debugname[CTL_DEBUG_MAXID];
39char names[BUFSIZ];
33a39b1e
KM
40
41struct list {
129fa670 42 struct ctlname *list;
33a39b1e 43 int size;
129fa670
KM
44};
45struct list toplist = { topname, CTL_MAXID };
46struct list secondlevel[] = {
33a39b1e
KM
47 { 0, 0 }, /* CTL_UNSPEC */
48 { kernname, KERN_MAXID }, /* CTL_KERN */
49 { vmname, VM_MAXID }, /* CTL_VM */
50 { 0, 0 }, /* CTL_FS */
51 { netname, NET_MAXID }, /* CTL_NET */
1fdacbde 52 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */
33a39b1e
KM
53 { hwname, HW_MAXID }, /* CTL_HW */
54 { 0, 0 }, /* CTL_MACHDEP */
55};
56
18ca9a3c 57int Aflag, aflag, nflag, wflag;
33a39b1e
KM
58
59int
60main(argc, argv)
61 int argc;
62 char *argv[];
63{
64 extern char *optarg;
65 extern int optind;
18ca9a3c 66 int ch, lvl1;
33a39b1e 67
18ca9a3c 68 while ((ch = getopt(argc, argv, "Aanw")) != EOF) {
33a39b1e
KM
69 switch (ch) {
70
71 case 'A':
72 Aflag = 1;
73 break;
74
75 case 'a':
76 aflag = 1;
77 break;
78
18ca9a3c
KM
79 case 'n':
80 nflag = 1;
81 break;
82
33a39b1e
KM
83 case 'w':
84 wflag = 1;
85 break;
86
87 default:
88 usage();
89 }
90 }
91 argc -= optind;
92 argv += optind;
93
94 if (Aflag || aflag) {
1fdacbde 95 debuginit();
18ca9a3c 96 for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
129fa670 97 listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
33a39b1e
KM
98 exit(0);
99 }
100 if (argc == 0)
101 usage();
102 while (argc-- > 0)
103 parse(*argv, 1);
104 exit(0);
105}
106
107/*
108 * List all variables known to the system.
109 */
129fa670
KM
110listall(prefix, lp)
111 char *prefix;
33a39b1e 112 struct list *lp;
129fa670 113{
18ca9a3c 114 int lvl2;
33a39b1e
KM
115 char *cp, name[BUFSIZ];
116
18ca9a3c
KM
117 if (lp->list == 0)
118 return;
129fa670 119 strcpy(name, prefix);
18ca9a3c
KM
120 cp = &name[strlen(name)];
121 *cp++ = '.';
129fa670
KM
122 for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
123 if (lp->list[lvl2].ctl_name == 0)
124 continue;
125 strcpy(cp, lp->list[lvl2].ctl_name);
18ca9a3c 126 parse(name, Aflag);
33a39b1e
KM
127 }
128}
129
130/*
131 * Parse a name into a MIB entry.
132 * Lookup and print out the MIB entry if it exists.
133 * Set a new value if requested.
134 */
135parse(string, flags)
136 char *string;
137 int flags;
138{
129fa670 139 int indx, type, size, len;
33a39b1e
KM
140 int isclockrate = 0;
141 void *newval = 0;
142 int intval, newsize = 0;
129fa670
KM
143 quad_t quadval;
144 struct list *lp;
33a39b1e
KM
145 int mib[CTL_MAXNAME];
146 char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ];
147
148 bufp = buf;
149 snprintf(buf, BUFSIZ, "%s", string);
150 if ((cp = strchr(string, '=')) != NULL) {
151 if (!wflag) {
152 fprintf(stderr, "Must specify -w to set variables\n");
153 exit(2);
154 }
155 *strchr(buf, '=') = '\0';
156 *cp++ = '\0';
157 while (isspace(*cp))
158 cp++;
129fa670
KM
159 newval = cp;
160 newsize = strlen(cp);
33a39b1e 161 }
129fa670 162 if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
33a39b1e
KM
163 return;
164 mib[0] = indx;
1fdacbde
KM
165 if (indx == CTL_DEBUG)
166 debuginit();
33a39b1e
KM
167 lp = &secondlevel[indx];
168 if (lp->list == 0) {
169 fprintf(stderr, "%s: class is not implemented\n",
170 topname[indx]);
171 return;
172 }
18ca9a3c 173 if (bufp == NULL) {
129fa670 174 listall(topname[indx].ctl_name, lp);
18ca9a3c
KM
175 return;
176 }
33a39b1e
KM
177 if ((indx = findname(string, "second", &bufp, lp)) == -1)
178 return;
179 mib[1] = indx;
129fa670
KM
180 type = lp->list[indx].ctl_type;
181 len = 2;
33a39b1e
KM
182 switch (mib[0]) {
183
184 case CTL_KERN:
185 switch (mib[1]) {
186 case KERN_VNODE:
187 case KERN_FILE:
188 if (flags == 0)
189 return;
190 fprintf(stderr,
191 "Use pstat to view %s information\n", string);
192 return;
193 case KERN_PROC:
194 if (flags == 0)
195 return;
196 fprintf(stderr,
197 "Use ps to view %s information\n", string);
198 return;
199 case KERN_CLOCKRATE:
200 isclockrate = 1;
201 break;
202 }
203 break;
204
205 case CTL_HW:
206 break;
207
208 case CTL_VM:
209 if (mib[1] == VM_LOADAVG) {
210 double loads[3];
211
212 getloadavg(loads, 3);
18ca9a3c
KM
213 if (!nflag)
214 fprintf(stdout, "%s: ", string);
215 fprintf(stdout, "%.2f %.2f %.2f\n",
33a39b1e
KM
216 loads[0], loads[1], loads[2]);
217 return;
218 }
219 if (flags == 0)
220 return;
221 fprintf(stderr,
222 "Use vmstat or systat to view %s information\n", string);
223 return;
224
225 case CTL_NET:
129fa670
KM
226 if (mib[1] == PF_INET) {
227 len = sysctl_inet(string, &bufp, mib, flags, &type);
228 if (len >= 0)
229 break;
230 return;
231 }
33a39b1e
KM
232 if (flags == 0)
233 return;
234 fprintf(stderr, "Use netstat to view %s information\n", string);
235 return;
236
33a39b1e 237 case CTL_DEBUG:
1fdacbde
KM
238 mib[2] = CTL_DEBUG_VALUE;
239 len = 3;
240 break;
241
242 case CTL_FS:
33a39b1e
KM
243 case CTL_MACHDEP:
244 break;
245
246 default:
247 fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
248 return;
249
250 }
129fa670
KM
251 if (bufp) {
252 fprintf(stderr, "name %s in %s is unknown\n", *bufp, string);
253 return;
254 }
255 if (newsize > 0) {
256 switch (type) {
257 case CTLTYPE_INT:
258 intval = atoi(newval);
259 newval = &intval;
260 newsize = sizeof intval;
261 break;
33a39b1e 262
129fa670
KM
263 case CTLTYPE_QUAD:
264 sscanf(newval, "%qd", &quadval);
265 newval = &quadval;
266 newsize = sizeof quadval;
267 break;
268 }
269 }
33a39b1e 270 size = BUFSIZ;
129fa670 271 if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
33a39b1e
KM
272 if (flags == 0)
273 return;
274 switch (errno) {
275 case EOPNOTSUPP:
276 fprintf(stderr, "%s: value is not available\n", string);
277 return;
278 case ENOTDIR:
279 fprintf(stderr, "%s: specification is incomplete\n",
280 string);
281 return;
282 case ENOMEM:
283 fprintf(stderr, "%s: type is unknown to this program\n",
284 string);
285 return;
286 default:
287 perror(string);
288 return;
289 }
290 }
291 if (isclockrate) {
292 struct clockinfo *clkp = (struct clockinfo *)buf;
293
18ca9a3c
KM
294 if (!nflag)
295 fprintf(stdout, "%s: ", string);
33a39b1e 296 fprintf(stdout,
18ca9a3c
KM
297 "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
298 clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
33a39b1e
KM
299 return;
300 }
129fa670
KM
301 switch (type) {
302 case CTLTYPE_INT:
18ca9a3c
KM
303 if (newsize == 0) {
304 if (!nflag)
305 fprintf(stdout, "%s = ", string);
306 fprintf(stdout, "%d\n", *(int *)buf);
307 } else {
308 if (!nflag)
309 fprintf(stdout, "%s: %d -> ", string,
310 *(int *)buf);
311 fprintf(stdout, "%d\n", *(int *)newval);
312 }
129fa670
KM
313 return;
314
315 case CTLTYPE_STRING:
18ca9a3c
KM
316 if (newsize == 0) {
317 if (!nflag)
318 fprintf(stdout, "%s = ", string);
319 fprintf(stdout, "%s\n", buf);
320 } else {
321 if (!nflag)
322 fprintf(stdout, "%s: %s -> ", string, buf);
323 fprintf(stdout, "%s\n", newval);
324 }
129fa670
KM
325 return;
326
327 case CTLTYPE_QUAD:
328 if (newsize == 0) {
329 if (!nflag)
330 fprintf(stdout, "%s = ", string);
331 fprintf(stdout, "%qd\n", *(quad_t *)buf);
332 } else {
333 if (!nflag)
334 fprintf(stdout, "%s: %qd -> ", string,
335 *(quad_t *)buf);
336 fprintf(stdout, "%qd\n", *(quad_t *)newval);
337 }
338 return;
339
340 case CTLTYPE_STRUCT:
341 fprintf(stderr, "%s: unknown structure returned\n",
342 string);
343 return;
344
345 default:
346 case CTLTYPE_NODE:
347 fprintf(stderr, "%s: unknown type returned\n",
348 string);
349 return;
350 }
351}
352
1fdacbde
KM
353/*
354 * Initialize the set of debugging names
355 */
356debuginit()
357{
358 int mib[3], size, loc, i;
359
360 if (secondlevel[CTL_DEBUG].list != 0)
361 return;
362 secondlevel[CTL_DEBUG].list = debugname;
363 mib[0] = CTL_DEBUG;
364 mib[2] = CTL_DEBUG_NAME;
365 for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) {
366 mib[1] = i;
367 size = BUFSIZ - loc;
368 if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
369 continue;
370 debugname[i].ctl_name = &names[loc];
371 debugname[i].ctl_type = CTLTYPE_INT;
372 loc += size;
373 }
374}
375
129fa670
KM
376struct ctlname inetname[] = CTL_IPPROTO_NAMES;
377struct ctlname ipname[] = IPCTL_NAMES;
378struct ctlname icmpname[] = ICMPCTL_NAMES;
379struct list inetlist = { inetname, IPPROTO_MAXID };
380struct list inetvars[] = {
381 { ipname, IPCTL_MAXID },
382 { icmpname, ICMPCTL_MAXID },
383};
384
385/*
386 * handle internet requests
387 */
388sysctl_inet(string, bufpp, mib, flags, typep)
389 char *string;
390 char **bufpp;
391 int mib[];
392 int flags;
393 int *typep;
394{
395 struct list *lp;
396 int indx;
397
398 if (*bufpp == NULL) {
399 listall(string, &inetlist);
400 return (-1);
401 }
402 if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
403 return (-1);
404 mib[2] = indx;
405 if (indx < 2)
406 lp = &inetvars[indx];
407 else if (!flags)
408 return (-1);
409 else {
410 fprintf(stderr, "%s: no variables defined for this protocol\n",
411 string);
412 return (-1);
413 }
414 if (*bufpp == NULL) {
415 listall(string, lp);
416 return (-1);
417 }
418 if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
419 return (-1);
420 mib[3] = indx;
421 *typep = lp->list[indx].ctl_type;
422 return (4);
33a39b1e
KM
423}
424
425/*
426 * Scan a list of names searching for a particular name.
427 */
428findname(string, level, bufp, namelist)
429 char *string;
430 char *level;
431 char **bufp;
432 struct list *namelist;
433{
434 char *name;
435 int i;
436
437 if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
438 fprintf(stderr, "%s: incomplete specification\n", string);
439 return (-1);
440 }
441 for (i = 0; i < namelist->size; i++)
cdbdb4d7
CT
442 if (namelist->list[i].ctl_name != NULL &&
443 strcmp(name, namelist->list[i].ctl_name) == 0)
33a39b1e
KM
444 break;
445 if (i == namelist->size) {
446 fprintf(stderr, "%s level name %s in %s is invalid\n",
447 level, name, string);
448 return (-1);
449 }
450 return (i);
451}
452
453usage()
454{
455
31ac5c9a
KM
456 (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
457 "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
458 "sysctl [-n] -a", "sysctl [-n] -A");
33a39b1e
KM
459 exit(1);
460}