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