xref: /illumos-gate/usr/src/cmd/acctadm/aconf.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/acctctl.h>
32 
33 #include <unistd.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <limits.h>
40 
41 #include "aconf.h"
42 #include "utils.h"
43 #include "res.h"
44 
45 #define	BUFSZ	(PATH_MAX + 80)
46 
47 typedef struct ac_token {
48 	char *tok_name;
49 	int tok_type;
50 	int (*tok_parse)(acctconf_t *, char *, int);
51 	int (*tok_print)(acctconf_t *, FILE *, int);
52 } ac_token_t;
53 
54 static int print_enable(acctconf_t *, FILE *, int);
55 static int print_file(acctconf_t *, FILE *, int);
56 static int print_tracked(acctconf_t *, FILE *, int);
57 static int print_untracked(acctconf_t *, FILE *, int);
58 
59 static ac_token_t tokens[] = {
60 	{ "ACCTADM_PROC_ENABLE",
61 		AC_PROC, aconf_str2enable, print_enable },
62 	{ "ACCTADM_PROC_FILE",
63 		AC_PROC, aconf_str2file, print_file },
64 	{ "ACCTADM_PROC_TRACKED",
65 		AC_PROC, aconf_str2tracked, print_tracked },
66 	{ "ACCTADM_PROC_UNTRACKED",
67 		AC_PROC, aconf_str2untracked, print_untracked },
68 	{ "ACCTADM_TASK_ENABLE",
69 		AC_TASK, aconf_str2enable, print_enable },
70 	{ "ACCTADM_TASK_FILE",
71 		AC_TASK, aconf_str2file, print_file },
72 	{ "ACCTADM_TASK_TRACKED",
73 		AC_TASK, aconf_str2tracked, print_tracked },
74 	{ "ACCTADM_TASK_UNTRACKED",
75 		AC_TASK, aconf_str2untracked, print_untracked },
76 	{ "ACCTADM_FLOW_ENABLE",
77 		AC_FLOW, aconf_str2enable, print_enable },
78 	{ "ACCTADM_FLOW_FILE",
79 		AC_FLOW, aconf_str2file, print_file },
80 	{ "ACCTADM_FLOW_TRACKED",
81 		AC_FLOW, aconf_str2tracked, print_tracked },
82 	{ "ACCTADM_FLOW_UNTRACKED",
83 		AC_FLOW, aconf_str2untracked, print_untracked },
84 	{ NULL,
85 		AC_NONE, NULL, NULL }
86 };
87 
88 void
89 aconf_init(acctconf_t *acp)
90 {
91 	void *buf;
92 	void *pathname;
93 	char *tracked, *untracked;
94 	int state;
95 
96 	if ((buf = malloc(AC_BUFSIZE)) == NULL ||
97 	    (pathname = malloc(MAXPATHLEN)) == NULL)
98 		die(gettext("not enough memory\n"));
99 
100 	/*
101 	 * Initialize process accounting settings
102 	 */
103 	(void) memset(pathname, 0, MAXPATHLEN);
104 	if (acctctl(AC_PROC | AC_STATE_GET, &state, sizeof (int)) == -1)
105 		die(gettext("cannot get process accounting state\n"));
106 	acp->ac_proc_state = state;
107 	if (acctctl(AC_PROC | AC_FILE_GET, pathname, MAXPATHLEN) == -1) {
108 		if (errno == ENOTACTIVE)
109 			(void) strlcpy(acp->ac_proc_file,
110 			    AC_STR_NONE, MAXPATHLEN);
111 		else
112 			die(gettext("cannot get process accounting file name"));
113 	} else {
114 		(void) strlcpy(acp->ac_proc_file, pathname, MAXPATHLEN);
115 	}
116 	(void) memset(buf, 0, AC_BUFSIZE);
117 	if (acctctl(AC_PROC | AC_RES_GET, buf, AC_BUFSIZE) == -1)
118 		die(gettext("cannot obtain the list of enabled resources\n"));
119 	tracked = buf2str(buf, AC_BUFSIZE, AC_ON, AC_PROC);
120 	untracked = buf2str(buf, AC_BUFSIZE, AC_OFF, AC_PROC);
121 	(void) strlcpy(acp->ac_proc_tracked, tracked, MAXRESLEN);
122 	(void) strlcpy(acp->ac_proc_untracked, untracked, MAXRESLEN);
123 	free(tracked);
124 	free(untracked);
125 
126 	/*
127 	 * Initialize flow accounting settings
128 	 */
129 	(void) memset(pathname, 0, MAXPATHLEN);
130 	if (acctctl(AC_FLOW | AC_STATE_GET, &state, sizeof (int)) == -1)
131 		die(gettext("cannot get flow accounting state\n"));
132 	acp->ac_flow_state = state;
133 	if (acctctl(AC_FLOW | AC_FILE_GET, pathname, MAXPATHLEN) == -1) {
134 		if (errno == ENOTACTIVE)
135 			(void) strlcpy(acp->ac_flow_file,
136 			    AC_STR_NONE, MAXPATHLEN);
137 		else
138 			die(gettext("cannot get flow accounting file name"));
139 	} else {
140 		(void) strlcpy(acp->ac_flow_file, pathname, MAXPATHLEN);
141 	}
142 	(void) memset(buf, 0, AC_BUFSIZE);
143 	if (acctctl(AC_FLOW | AC_RES_GET, buf, AC_BUFSIZE) == -1)
144 		die(gettext("cannot obtain the list of enabled resources\n"));
145 	tracked = buf2str(buf, AC_BUFSIZE, AC_ON, AC_FLOW);
146 	untracked = buf2str(buf, AC_BUFSIZE, AC_OFF, AC_FLOW);
147 	(void) strlcpy(acp->ac_flow_tracked, tracked, MAXRESLEN);
148 	(void) strlcpy(acp->ac_flow_untracked, untracked, MAXRESLEN);
149 	free(tracked);
150 	free(untracked);
151 
152 	/*
153 	 * Initialize task accounting settings
154 	 */
155 	(void) memset(pathname, 0, MAXPATHLEN);
156 	if (acctctl(AC_TASK | AC_STATE_GET, &state, sizeof (int)) == -1)
157 		die(gettext("cannot get task accounting state\n"));
158 	acp->ac_task_state = state;
159 	if (acctctl(AC_TASK | AC_FILE_GET, pathname, MAXPATHLEN) == -1) {
160 		if (errno == ENOTACTIVE)
161 			(void) strlcpy(acp->ac_task_file,
162 			    AC_STR_NONE, MAXPATHLEN);
163 		else
164 			die(gettext("cannot get task accounting file name"));
165 	} else {
166 		(void) strlcpy(acp->ac_task_file, pathname, MAXPATHLEN);
167 	}
168 	(void) memset(buf, 0, AC_BUFSIZE);
169 	if (acctctl(AC_TASK | AC_RES_GET, buf, AC_BUFSIZE) == -1)
170 		die(gettext("cannot obtain the list of enabled resources\n"));
171 	tracked = buf2str(buf, AC_BUFSIZE, AC_ON, AC_TASK);
172 	untracked = buf2str(buf, AC_BUFSIZE, AC_OFF, AC_TASK);
173 	(void) strlcpy(acp->ac_task_tracked, tracked, MAXRESLEN);
174 	(void) strlcpy(acp->ac_task_untracked, untracked, MAXRESLEN);
175 	free(pathname);
176 	free(buf);
177 	free(tracked);
178 	free(untracked);
179 }
180 
181 int
182 aconf_create(acctconf_t *acp, const char *fpath)
183 {
184 	if ((acp->ac_conf_fd = open(fpath, O_RDWR | O_CREAT, AC_PERM)) == -1) {
185 		warn(gettext("failed to open %s"), fpath);
186 		return (-1);
187 	}
188 	if ((acp->ac_conf_fp = fdopen(acp->ac_conf_fd, "r+")) == NULL) {
189 		warn(gettext("failed to open stream for %s"), fpath);
190 		return (-1);
191 	}
192 	return (0);
193 }
194 
195 int
196 aconf_open(acctconf_t *acp, const char *fpath)
197 {
198 	char buf[BUFSZ];
199 	int line;
200 	int ret = 0;
201 
202 	if ((acp->ac_conf_fd = open(fpath, O_RDONLY, AC_PERM)) == -1) {
203 		warn(gettext("failed to open %s"), fpath);
204 		return (-1);
205 	}
206 	if ((acp->ac_conf_fp = fdopen(acp->ac_conf_fd, "r")) == NULL) {
207 		warn(gettext("failed to open stream for %s"), fpath);
208 		return (-1);
209 	}
210 	for (line = 1; fgets(buf, BUFSZ, acp->ac_conf_fp) != NULL; line++) {
211 		char name[BUFSZ], value[BUFSZ];
212 		ac_token_t *tokp;
213 		int len;
214 
215 		if (buf[0] == '#' || buf[0] == '\n')
216 			continue;
217 		/*
218 		 * Look for "name=value", with optional whitespace on either
219 		 * side, terminated by a newline, and consuming the whole line.
220 		 */
221 		/* LINTED - unbounded string specifier */
222 		if (sscanf(buf, " %[^=]=%s \n%n", name, value, &len) == 2 &&
223 		    name[0] != '\0' && value[0] != '\0' && len == strlen(buf)) {
224 			/*
225 			 * Locate a matching token in the tokens[] table,
226 			 * and invoke its parsing function.
227 			 */
228 			for (tokp = tokens; tokp->tok_name != NULL; tokp++) {
229 				if (strcmp(name, tokp->tok_name) == 0) {
230 					if (tokp->tok_parse(acp, value,
231 					    tokp->tok_type) == -1) {
232 						warn(gettext("\"%s\", line %d: "
233 						    "warning: invalid %s\n"),
234 						    fpath, line, name);
235 						ret = -1;
236 					}
237 					break;
238 				}
239 			}
240 			/*
241 			 * If we hit the end of the tokens[] table,
242 			 * no matching token was found.
243 			 */
244 			if (tokp->tok_name == NULL) {
245 				warn(gettext("\"%s\", line %d: warning: "
246 				    "invalid token: %s\n"), fpath, line, name);
247 				ret = -1;
248 			}
249 		} else {
250 			warn(gettext("\"%s\", line %d: syntax error\n"),
251 			    fpath, line);
252 			ret = -1;
253 		}
254 	}
255 	if (line == 1) {
256 		warn(gettext("cannot read settings from %s\n"), fpath);
257 		ret = -1;
258 	}
259 	return (ret);
260 }
261 
262 int
263 aconf_setup(acctconf_t *acp)
264 {
265 	void *buf;
266 
267 	if ((buf = malloc(AC_BUFSIZE)) == NULL)
268 		die(gettext("not enough memory\n"));
269 
270 	/*
271 	 * Setup process accounting
272 	 */
273 	(void) memset(buf, 0, AC_BUFSIZE);
274 	str2buf(buf, acp->ac_proc_untracked, AC_OFF, AC_PROC);
275 	str2buf(buf, acp->ac_proc_tracked, AC_ON, AC_PROC);
276 	if (acctctl(AC_PROC | AC_RES_SET, buf, AC_BUFSIZE) == -1) {
277 		warn(gettext("cannot enable or disable resources\n"));
278 		return (-1);
279 	}
280 	if (strcmp(acp->ac_proc_file, AC_STR_NONE) != 0) {
281 		if (acctctl(AC_PROC | AC_FILE_SET,
282 		    acp->ac_proc_file, strlen(acp->ac_proc_file) + 1) == -1) {
283 			warn(gettext("cannot open accounting file"));
284 			return (-1);
285 		}
286 	} else {
287 		if (acctctl(AC_PROC | AC_FILE_SET, NULL, 0) == -1) {
288 			warn(gettext("cannot close accounting file\n"));
289 			return (-1);
290 		}
291 	}
292 	if (acctctl(AC_PROC | AC_STATE_SET, &acp->ac_proc_state,
293 	    sizeof (int)) == -1) {
294 		warn(gettext("cannot enable/disable process accounting"));
295 		return (-1);
296 	}
297 
298 	/*
299 	 * Setup flow accounting
300 	 */
301 	(void) memset(buf, 0, AC_BUFSIZE);
302 	str2buf(buf, acp->ac_flow_untracked, AC_OFF, AC_FLOW);
303 	str2buf(buf, acp->ac_flow_tracked, AC_ON, AC_FLOW);
304 	if (acctctl(AC_FLOW | AC_RES_SET, buf, AC_BUFSIZE) == -1) {
305 		warn(gettext("cannot enable or disable resources\n"));
306 		return (-1);
307 	}
308 	if (strcmp(acp->ac_flow_file, AC_STR_NONE) != 0) {
309 		if (acctctl(AC_FLOW | AC_FILE_SET,
310 		    acp->ac_flow_file, strlen(acp->ac_flow_file) + 1) == -1) {
311 			warn(gettext("cannot open accounting file"));
312 			return (-1);
313 		}
314 	} else {
315 		if (acctctl(AC_FLOW | AC_FILE_SET, NULL, 0) == -1) {
316 			warn(gettext("cannot close accounting file\n"));
317 			return (-1);
318 		}
319 	}
320 	if (acctctl(AC_FLOW | AC_STATE_SET, &acp->ac_flow_state,
321 	    sizeof (int)) == -1) {
322 		warn(gettext("cannot enable/disable flow accounting"));
323 		return (-1);
324 	}
325 
326 
327 	/*
328 	 * Setup task accounting
329 	 */
330 	(void) memset(buf, 0, AC_BUFSIZE);
331 	str2buf(buf, acp->ac_task_untracked, AC_OFF, AC_TASK);
332 	str2buf(buf, acp->ac_task_tracked, AC_ON, AC_TASK);
333 	if (acctctl(AC_TASK | AC_RES_SET, buf, AC_BUFSIZE) == -1) {
334 		warn(gettext("cannot enable or disable resources\n"));
335 		return (-1);
336 	}
337 	if (strcmp(acp->ac_task_file, AC_STR_NONE) != 0) {
338 		if (acctctl(AC_TASK | AC_FILE_SET,
339 		    acp->ac_task_file, strlen(acp->ac_task_file) + 1) == -1) {
340 			warn(gettext("cannot set accounting file"));
341 			return (-1);
342 		}
343 	} else {
344 		if (acctctl(AC_TASK | AC_FILE_SET, NULL, 0) == -1) {
345 			warn(gettext("cannot close accounting file\n"));
346 			return (-1);
347 		}
348 	}
349 	if (acctctl(AC_TASK | AC_STATE_SET, &acp->ac_task_state,
350 	    sizeof (int)) == -1) {
351 		warn(gettext("cannot enable/disable task accounting"));
352 		return (-1);
353 	}
354 
355 	free(buf);
356 	return (0);
357 }
358 
359 int
360 aconf_close(acctconf_t *acp)
361 {
362 	if (acp->ac_conf_fp != NULL && fclose(acp->ac_conf_fp) != 0)
363 		return (-1);
364 	else
365 		return (0);
366 }
367 
368 int
369 aconf_write(acctconf_t *acp)
370 {
371 	ac_token_t *tokp;
372 
373 	if (fseeko(acp->ac_conf_fp, (off_t)0, SEEK_SET) == -1) {
374 		warn(gettext("failed to seek config file"));
375 		return (-1);
376 	}
377 	if (ftruncate(acp->ac_conf_fd, (off_t)0) == -1) {
378 		warn(gettext("failed to truncate config file"));
379 		return (-1);
380 	}
381 	(void) fputs("#\n# acctadm.conf\n#\n"
382 	    "# Configuration parameters for extended accounting.\n"
383 	    "# Do NOT edit this file by hand -- use acctadm(1m) instead.\n"
384 	    "#\n", acp->ac_conf_fp);
385 	for (tokp = tokens; tokp->tok_name != NULL; tokp++) {
386 		if (fprintf(acp->ac_conf_fp, "%s=", tokp->tok_name) == -1 ||
387 		    tokp->tok_print(acp, acp->ac_conf_fp,
388 		    tokp->tok_type) == -1) {
389 			warn(gettext("failed to write token"));
390 			return (-1);
391 		}
392 	}
393 	if (fflush(acp->ac_conf_fp) != 0)
394 		warn(gettext("warning: failed to flush config file"));
395 	if (fsync(acp->ac_conf_fd) == -1)
396 		warn(gettext("warning: failed to sync config file to disk"));
397 	if (fchmod(acp->ac_conf_fd, AC_PERM) == -1)
398 		warn(gettext("warning: failed to reset mode on config file"));
399 	if (fchown(acp->ac_conf_fd, AC_OWNER, AC_GROUP) == -1)
400 		warn(gettext("warning: failed to reset owner on config file"));
401 	return (0);
402 }
403 
404 void
405 aconf_print(acctconf_t *acp, FILE *fp, int type)
406 {
407 	if (type & AC_TASK) {
408 		(void) fprintf(fp,
409 		    gettext("            Task accounting: %s\n"),
410 		    acp->ac_task_state ?
411 		    gettext("active") : gettext("inactive"));
412 		(void) fprintf(fp,
413 		    gettext("       Task accounting file: %s\n"),
414 		    acp->ac_task_file);
415 		(void) fprintf(fp,
416 		    gettext("     Tracked task resources: %s\n"),
417 		    acp->ac_task_tracked);
418 		(void) fprintf(fp,
419 		    gettext("   Untracked task resources: %s\n"),
420 		    acp->ac_task_untracked);
421 	}
422 	if (type & AC_PROC) {
423 		(void) fprintf(fp,
424 		    gettext("         Process accounting: %s\n"),
425 		    acp->ac_proc_state ?
426 		    gettext("active") : gettext("inactive"));
427 		(void) fprintf(fp,
428 		    gettext("    Process accounting file: %s\n"),
429 		    acp->ac_proc_file);
430 		(void) fprintf(fp,
431 		    gettext("  Tracked process resources: %s\n"),
432 		    acp->ac_proc_tracked);
433 		(void) fprintf(fp,
434 		    gettext("Untracked process resources: %s\n"),
435 		    acp->ac_proc_untracked);
436 	}
437 	if (type & AC_FLOW) {
438 		(void) fprintf(fp,
439 		    gettext("            Flow accounting: %s\n"),
440 		    acp->ac_flow_state ?
441 		    gettext("active") : gettext("inactive"));
442 		(void) fprintf(fp,
443 		    gettext("       Flow accounting file: %s\n"),
444 		    acp->ac_flow_file);
445 		(void) fprintf(fp,
446 		    gettext("     Tracked flow resources: %s\n"),
447 		    acp->ac_flow_tracked);
448 		(void) fprintf(fp,
449 		    gettext("   Untracked flow resources: %s\n"),
450 		    acp->ac_flow_untracked);
451 	}
452 }
453 
454 int
455 aconf_str2enable(acctconf_t *acp, char *buf, int type)
456 {
457 	int state;
458 
459 	if (strcasecmp(buf, AC_STR_YES) == 0)
460 		state = AC_ON;
461 	else if (strcasecmp(buf, AC_STR_NO) == 0)
462 		state = AC_OFF;
463 	else
464 		return (-1);
465 	if (type == AC_PROC)
466 		acp->ac_proc_state = state;
467 	else if (type == AC_TASK)
468 		acp->ac_task_state = state;
469 	else if (type == AC_FLOW)
470 		acp->ac_flow_state = state;
471 	else
472 		return (-1);
473 	return (0);
474 }
475 
476 int
477 aconf_str2file(acctconf_t *acp, char *buf, int type)
478 {
479 	if (strcmp(buf, AC_STR_NONE) != 0 && !valid_abspath(buf))
480 		return (-1);
481 	if (type == AC_PROC)
482 		(void) strlcpy(acp->ac_proc_file, buf, MAXPATHLEN);
483 	else if (type == AC_TASK)
484 		(void) strlcpy(acp->ac_task_file, buf, MAXPATHLEN);
485 	else if (type == AC_FLOW)
486 		(void) strlcpy(acp->ac_flow_file, buf, MAXPATHLEN);
487 	return (0);
488 }
489 
490 int
491 aconf_str2tracked(acctconf_t *acp, char *buf, int type)
492 {
493 	if (type == AC_PROC)
494 		(void) strlcpy(acp->ac_proc_tracked, buf, MAXRESLEN);
495 	else if (type == AC_TASK)
496 		(void) strlcpy(acp->ac_task_tracked, buf, MAXRESLEN);
497 	else if (type == AC_FLOW)
498 		(void) strlcpy(acp->ac_flow_tracked, buf, MAXRESLEN);
499 	else
500 		return (-1);
501 	return (0);
502 }
503 
504 int
505 aconf_str2untracked(acctconf_t *acp, char *buf, int type)
506 {
507 	if (type == AC_PROC)
508 		(void) strlcpy(acp->ac_proc_untracked, buf, MAXRESLEN);
509 	else if (type == AC_TASK)
510 		(void) strlcpy(acp->ac_task_untracked, buf, MAXRESLEN);
511 	else if (type == AC_FLOW)
512 		(void) strlcpy(acp->ac_flow_untracked, buf, MAXRESLEN);
513 	else
514 		return (-1);
515 	return (0);
516 }
517 
518 static int
519 print_enable(acctconf_t *acp, FILE *fp, int type)
520 {
521 	if (type == AC_PROC)
522 		return (fprintf(fp, "%s\n", (acp->ac_proc_state == AC_OFF) ?
523 		    AC_STR_NO : AC_STR_YES));
524 	else if (type == AC_TASK)
525 		return (fprintf(fp, "%s\n", (acp->ac_task_state == AC_OFF) ?
526 		    AC_STR_NO : AC_STR_YES));
527 	else if (type == AC_FLOW)
528 		return (fprintf(fp, "%s\n", (acp->ac_flow_state == AC_OFF) ?
529 		    AC_STR_NO : AC_STR_YES));
530 	else
531 		return (-1);
532 }
533 
534 static int
535 print_file(acctconf_t *acp, FILE *fp, int type)
536 {
537 	if (type == AC_PROC)
538 		return (fprintf(fp, "%s\n", acp->ac_proc_file));
539 	else if (type == AC_TASK)
540 		return (fprintf(fp, "%s\n", acp->ac_task_file));
541 	else if (type == AC_FLOW)
542 		return (fprintf(fp, "%s\n", acp->ac_flow_file));
543 	else
544 		return (-1);
545 }
546 
547 static int
548 print_tracked(acctconf_t *acp, FILE *fp, int type)
549 {
550 	if (type == AC_PROC)
551 		return (fprintf(fp, "%s\n", acp->ac_proc_tracked));
552 	else if (type == AC_TASK)
553 		return (fprintf(fp, "%s\n", acp->ac_task_tracked));
554 	else if (type == AC_FLOW)
555 		return (fprintf(fp, "%s\n", acp->ac_flow_tracked));
556 	else
557 		return (-1);
558 }
559 
560 static int
561 print_untracked(acctconf_t *acp, FILE *fp, int type)
562 {
563 	if (type == AC_PROC)
564 		return (fprintf(fp, "%s\n", acp->ac_proc_untracked));
565 	else if (type == AC_TASK)
566 		return (fprintf(fp, "%s\n", acp->ac_task_untracked));
567 	else if (type == AC_FLOW)
568 		return (fprintf(fp, "%s\n", acp->ac_flow_untracked));
569 	else
570 		return (-1);
571 }
572