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 (c) 1999-2000 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Postprocessor for NFS server logging. 31 */ 32 #include <arpa/inet.h> 33 #include <assert.h> 34 #include <deflt.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <netinet/in.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <strings.h> 42 #include <signal.h> 43 #include <syslog.h> 44 #include <limits.h> 45 #include <libintl.h> 46 #include <locale.h> 47 #include <unistd.h> 48 #include <sys/types.h> 49 #include <sys/utsname.h> 50 #include <sys/stat.h> 51 #include <sys/resource.h> 52 #include <rpc/clnt_stat.h> 53 #include <nfs/nfs.h> 54 #include <nfs/export.h> 55 #include <nfs/nfs_log.h> 56 #include "fhtab.h" 57 #include "nfslogd.h" 58 #include "buffer_list.h" 59 #include "../lib/nfslog_config.h" 60 #include "../lib/nfslogtab.h" 61 62 enum pidfile_operation { 63 PID_STARTUP, PID_SHUTDOWN 64 }; 65 66 static int nfslogtab_deactivate_after_boot(void); 67 static int 68 nfslogtab_remove(struct buffer_ent **, struct buffer_ent **, boolean_t); 69 static int cycle_logs(nfsl_config_t *, int); 70 static void enable_logcycling(void); 71 static int process_pidfile(enum pidfile_operation); 72 static void short_cleanup(void); 73 static void full_cleanup(void); 74 static void transactions_timeout(nfsl_config_t *); 75 static void close_all_translogs(nfsl_config_t *); 76 int cycle_log(char *, int); 77 static boolean_t is_cycle_needed(char *, void **, boolean_t, int *); 78 79 /* 80 * Configuration information. 81 */ 82 83 int debug = 0; 84 boolean_t test = B_FALSE; 85 time_t mapping_update_interval = MAPPING_UPDATE_INTERVAL; 86 /* prune_timeout measures how old a database entry must be to be pruned */ 87 time_t prune_timeout = (SECSPERHOUR * 7 * 24); 88 int max_logs_preserve = MAX_LOGS_PRESERVE; 89 uint_t idle_time = IDLE_TIME; 90 static mode_t Umask = NFSLOG_UMASK; 91 static long cycle_frequency = CYCLE_FREQUENCY; 92 /* prune_frequency measures how often should prune_dbs be called */ 93 static long prune_frequency = (SECSPERHOUR * 24); 94 static int min_size = MIN_PROCESSING_SIZE; 95 static volatile bool_t need2cycle = FALSE; 96 static volatile bool_t need2prune = FALSE; 97 boolean_t keep_running = B_TRUE; 98 boolean_t quick_cleaning = B_FALSE; 99 100 /*ARGSUSED*/ 101 int 102 main(int argc, char **argv) 103 { 104 struct rlimit rl; 105 int error = 0; 106 char *defp; 107 pid_t pid; 108 109 timestruc_t logtab_update; 110 time_t process_start, last_prune = time(0); 111 time_t last_cycle = time(0); /* last time logs were cycled */ 112 int processed, buffers_processed; 113 struct buffer_ent *buffer_list = NULL, *bep, *next; 114 nfsl_config_t *config_list = NULL; 115 char *fhtable_to_prune = NULL; 116 117 /* 118 * Check to make sure user is root. 119 */ 120 if (geteuid() != 0) { 121 (void) fprintf(stderr, gettext("%s must be run as root\n"), 122 argv[0]); 123 exit(1); 124 } 125 126 /* 127 * Read defaults file. 128 */ 129 if (defopen(NFSLOG_OPTIONS_FILE) == 0) { 130 if ((defp = defread("DEBUG=")) != NULL) { 131 debug = atoi(defp); 132 if (debug > 0) 133 (void) printf("debug=%d\n", debug); 134 } 135 if ((defp = defread("TEST=")) != NULL) { 136 if (strcmp(defp, "TRUE") == 0) 137 test = B_TRUE; 138 if (debug > 0) { 139 if (test) 140 (void) printf("test=TRUE\n"); 141 else 142 (void) printf("test=FALSE\n"); 143 } 144 } 145 /* 146 * Set Umask for log and fhtable creation. 147 */ 148 if ((defp = defread("UMASK=")) != NULL) { 149 if (sscanf(defp, "%lo", &Umask) != 1) 150 Umask = NFSLOG_UMASK; 151 } 152 /* 153 * Minimum size buffer should reach before processing. 154 */ 155 if ((defp = defread("MIN_PROCESSING_SIZE=")) != NULL) { 156 min_size = atoi(defp); 157 if (debug > 0) 158 (void) printf("min_size=%d\n", min_size); 159 } 160 /* 161 * Number of seconds the daemon should 162 * sleep waiting for more work. 163 */ 164 if ((defp = defread("IDLE_TIME=")) != NULL) { 165 idle_time = (uint_t)atoi(defp); 166 if (debug > 0) 167 (void) printf("idle_time=%d\n", idle_time); 168 } 169 /* 170 * Maximum number of logs to preserve. 171 */ 172 if ((defp = defread("MAX_LOGS_PRESERVE=")) != NULL) { 173 max_logs_preserve = atoi(defp); 174 if (debug > 0) { 175 (void) printf("max_logs_preserve=%d\n", 176 max_logs_preserve); 177 } 178 } 179 /* 180 * Frequency of atime updates. 181 */ 182 if ((defp = defread("MAPPING_UPDATE_INTERVAL=")) != NULL) { 183 mapping_update_interval = atoi(defp); 184 if (debug > 0) { 185 (void) printf("mapping_update_interval=%ld\n", 186 mapping_update_interval); 187 } 188 } 189 /* 190 * Time to remove entries 191 */ 192 if ((defp = defread("PRUNE_TIMEOUT=")) != NULL) { 193 /* 194 * Prune timeout is in hours but we want 195 * deal with the time in seconds internally. 196 */ 197 prune_timeout = atoi(defp); 198 prune_timeout *= SECSPERHOUR; 199 if (prune_timeout < prune_frequency) 200 prune_frequency = prune_timeout; 201 if (debug > 0) { 202 (void) printf("prune_timeout=%ld\n", 203 prune_timeout); 204 } 205 } 206 /* 207 * fhtable to prune when start (for debug/test purposes) 208 */ 209 if ((defp = defread("PRUNE_FHTABLE=")) != NULL) { 210 /* 211 * Specify full pathname of fhtable to prune before 212 * any processing is to be done 213 */ 214 if (fhtable_to_prune = malloc(strlen(defp) + 1)) { 215 (void) strcpy(fhtable_to_prune, defp); 216 if (debug > 0) { 217 (void) printf("fhtable to prune=%s\n", 218 fhtable_to_prune); 219 } 220 } else { 221 syslog(LOG_ERR, gettext( 222 "malloc fhtable_to_prune error %s\n"), 223 strerror(errno)); 224 } 225 } 226 /* 227 * Log cycle frequency. 228 */ 229 if ((defp = defread("CYCLE_FREQUENCY=")) != NULL) { 230 cycle_frequency = atol(defp); 231 if (debug > 0) { 232 (void) printf("cycle_frequency=%ld\n", 233 cycle_frequency); 234 } 235 } 236 /* 237 * defopen of NULL closes the open defaults file. 238 */ 239 (void) defopen((char *)NULL); 240 } 241 242 if (Umask > ((mode_t)0777)) 243 Umask = NFSLOG_UMASK; 244 (void) umask(Umask); 245 246 if (getrlimit(RLIMIT_FSIZE, &rl) < 0) { 247 error = errno; 248 (void) fprintf(stderr, gettext( 249 "getrlimit failed error is %d - %s\n"), 250 error, strerror(error)); 251 exit(1); 252 } 253 if (min_size < 0 || min_size > rl.rlim_cur) { 254 (void) fprintf(stderr, gettext( 255 "MIN_PROCESSING_SIZE out of range, should be >= 0 and " 256 "< %d. Check %s.\n"), rl.rlim_cur, NFSLOG_OPTIONS_FILE); 257 exit(1); 258 } 259 if (idle_time > INT_MAX) { 260 (void) fprintf(stderr, gettext( 261 "IDLE_TIME out of range, should be >= 0 and " 262 "< %d. Check %s.\n"), INT_MAX, NFSLOG_OPTIONS_FILE); 263 exit(1); 264 } 265 if (max_logs_preserve < 0 || max_logs_preserve > INT_MAX) { 266 (void) fprintf(stderr, gettext( 267 "MAX_LOGS_PRESERVE out of range, should be >= 0 and " 268 "< %d. Check %s.\n"), INT_MAX, NFSLOG_OPTIONS_FILE); 269 exit(1); 270 } 271 if (mapping_update_interval < 0|| mapping_update_interval > INT_MAX) { 272 (void) fprintf(stderr, gettext( 273 "MAPPING_UPDATE_INTERVAL out of range, " 274 "should be >= 0 and " 275 "< %d. Check %s.\n"), INT_MAX, NFSLOG_OPTIONS_FILE); 276 exit(1); 277 } 278 if (cycle_frequency < 0 || cycle_frequency > INT_MAX) { 279 (void) fprintf(stderr, gettext( 280 "CYCLE_FREQUENCY out of range, should be >= 0 and " 281 "< %d. Check %s.\n"), INT_MAX, NFSLOG_OPTIONS_FILE); 282 exit(1); 283 } 284 /* get value in seconds */ 285 cycle_frequency = cycle_frequency * 60 * 60; 286 287 /* 288 * If we dump core, it will be /core 289 */ 290 if (chdir("/") < 0) 291 (void) fprintf(stderr, gettext("chdir /: %s"), strerror(errno)); 292 293 /* 294 * Config errors to stderr 295 */ 296 nfsl_errs_to_syslog = B_FALSE; 297 298 #ifndef DEBUG 299 pid = fork(); 300 if (pid == -1) { 301 (void) fprintf(stderr, gettext("%s: fork failure\n"), 302 argv[0]); 303 exit(1); 304 } 305 if (pid != 0) 306 exit(0); 307 /* 308 * Config errors to syslog 309 */ 310 nfsl_errs_to_syslog = B_TRUE; 311 #endif /* DEBUG */ 312 313 (void) setlocale(LC_ALL, ""); 314 #if !defined(TEXT_DOMAIN) 315 #define TEXT_DOMAIN "SYS_TEST" 316 #endif 317 (void) textdomain(TEXT_DOMAIN); 318 319 /* 320 * Check to see if nfslogd is already running. 321 */ 322 if (process_pidfile(PID_STARTUP) != 0) { 323 exit(1); 324 } 325 326 (void) sigset(SIGUSR1, (void (*)(int))enable_logcycling); 327 (void) sigset(SIGHUP, (void (*)(int))full_cleanup); 328 (void) sigset(SIGTERM, (void(*)(int))short_cleanup); 329 330 #ifndef DEBUG 331 /* 332 * Close existing file descriptors, open "/dev/null" as 333 * standard input, output, and error, and detach from 334 * controlling terminal. 335 */ 336 if (!debug && !test) { 337 closefrom(0); 338 (void) open("/dev/null", O_RDONLY); 339 (void) open("/dev/null", O_WRONLY); 340 (void) dup(1); 341 } 342 (void) setsid(); 343 #endif /* DEBUG */ 344 345 openlog(argv[0], LOG_PID, LOG_DAEMON); 346 347 public_fh.fh_len = NFS_FHMAXDATA; 348 public_fh.fh_xlen = NFS_FHMAXDATA; 349 350 /* 351 * Call once at startup to handle the nfslogtab 352 */ 353 if (nfslogtab_deactivate_after_boot() == -1) 354 exit(1); 355 356 /* 357 * Get a list of buffers that need to be processed. 358 */ 359 if (error = getbuffer_list(&buffer_list, &logtab_update)) { 360 syslog(LOG_ERR, gettext("Could not read %s: %s"), 361 NFSLOGTAB, strerror(error)); 362 goto done; 363 } 364 365 /* 366 * Get the configuration list. 367 */ 368 if (error = nfsl_getconfig_list(&config_list)) { 369 syslog(LOG_ERR, gettext( 370 "Could not obtain configuration list: %s"), 371 strerror(error)); 372 goto done; 373 } 374 375 /* 376 * loop to process the work being generated by the NFS server 377 */ 378 while (keep_running) { 379 buffers_processed = 0; 380 (void) checkbuffer_list(&buffer_list, &logtab_update); 381 382 while (buffer_list == NULL) { 383 /* 384 * Nothing to do 385 */ 386 (void) sleep(idle_time); 387 388 if (!keep_running) { 389 /* 390 * We have been interrupted and asked to 391 * flush our transactions and exit. 392 */ 393 close_all_translogs(config_list); 394 goto done; 395 } 396 (void) checkbuffer_list(&buffer_list, &logtab_update); 397 } 398 399 process_start = time(0); 400 401 if (error = nfsl_checkconfig_list(&config_list, NULL)) { 402 syslog(LOG_ERR, gettext( 403 "Could not update configuration list: %s"), 404 strerror(error)); 405 nfsl_freeconfig_list(&config_list); 406 goto done; 407 } 408 409 if (difftime(time(0), last_cycle) > cycle_frequency) 410 need2cycle = TRUE; 411 if (need2cycle) { 412 error = cycle_logs(config_list, max_logs_preserve); 413 if (error) { 414 syslog(LOG_WARNING, gettext( 415 "One or more logfiles couldn't be cycled, " 416 "continuing regular processing")); 417 } 418 need2cycle = FALSE; 419 last_cycle = time(0); 420 } 421 if (difftime(time(0), last_prune) > prune_frequency) 422 need2prune = TRUE; 423 if (need2prune || fhtable_to_prune) { 424 error = prune_dbs(fhtable_to_prune); 425 if (error) { 426 syslog(LOG_WARNING, gettext( 427 "Error in cleaning database files")); 428 } 429 need2prune = FALSE; 430 last_prune = time(0); 431 /* After the first time, use the normal procedure */ 432 free(fhtable_to_prune); 433 fhtable_to_prune = NULL; 434 } 435 436 for (bep = buffer_list; bep != NULL; bep = next) { 437 next = bep->be_next; 438 processed = 0; 439 error = process_buffer(bep, &config_list, 440 min_size, idle_time, &processed); 441 if (error == 0 && processed) { 442 if (bep->be_error) { 443 syslog(LOG_ERR, gettext( 444 "Buffer file '%s' " 445 "processed successfully."), 446 bep->be_name); 447 } 448 error = 449 nfslogtab_remove(&buffer_list, &bep, B_FALSE); 450 } else if (error == ENOENT) { 451 syslog(LOG_ERR, gettext("Removed entry" 452 "\t\"%s\t%s\t%d\" from %s"), 453 bep->be_name, 454 bep->be_sharepnt->se_name, 455 bep->be_sharepnt->se_state, 456 NFSLOGTAB); 457 error = 458 nfslogtab_remove(&buffer_list, &bep, B_TRUE); 459 } else if (error && error != bep->be_error) { 460 /* 461 * An error different from what we've reported 462 * before occured. 463 */ 464 syslog(LOG_ERR, gettext( 465 "Cannot process buffer file '%s' - " 466 "will retry on every iteration."), 467 bep->be_name); 468 } 469 470 if (bep != NULL) 471 bep->be_error = error; 472 buffers_processed += processed; 473 } 474 475 transactions_timeout(config_list); 476 477 if (keep_running) { 478 uint_t process_time; 479 480 /* 481 * Sleep idle_time minus however long it took us 482 * to process the buffers. 483 */ 484 process_time = 485 (uint_t)(difftime(time(0), process_start)); 486 if (process_time < idle_time) 487 (void) sleep(idle_time - process_time); 488 } 489 } 490 491 done: 492 /* 493 * Make sure to clean house before we exit 494 */ 495 close_all_translogs(config_list); 496 free_buffer_list(&buffer_list); 497 nfsl_freeconfig_list(&config_list); 498 499 (void) process_pidfile(PID_SHUTDOWN); 500 501 return (error); 502 } 503 504 static void 505 short_cleanup(void) 506 { 507 if (debug) { 508 (void) fprintf(stderr, 509 "SIGTERM received, setting state to terminate...\n"); 510 } 511 quick_cleaning = B_TRUE; 512 keep_running = B_FALSE; 513 } 514 515 static void 516 full_cleanup(void) 517 { 518 if (debug) { 519 (void) fprintf(stderr, 520 "SIGHUP received, setting state to shutdown...\n"); 521 } 522 quick_cleaning = keep_running = B_FALSE; 523 } 524 525 /* 526 * Removes nfslogtab entries matching the specified buffer_ent, 527 * if 'inactive_only' is set, then only inactive entries are removed. 528 * The buffer_list and sharepoint list entries are removed appropriately. 529 * Returns 0 on success, error otherwise. 530 */ 531 static int 532 nfslogtab_remove( 533 struct buffer_ent **buffer_list, 534 struct buffer_ent **bep, 535 boolean_t allstates) 536 { 537 FILE *fd; 538 int error = 0; 539 struct sharepnt_ent *sep, *next; 540 541 fd = fopen(NFSLOGTAB, "r+"); 542 rewind(fd); 543 if (fd == NULL) { 544 error = errno; 545 syslog(LOG_ERR, gettext("%s - %s\n"), NFSLOGTAB, 546 strerror(error)); 547 return (error); 548 } 549 550 if (lockf(fileno(fd), F_LOCK, 0L) < 0) { 551 error = errno; 552 syslog(LOG_ERR, gettext("cannot lock %s - %s\n"), NFSLOGTAB, 553 strerror(error)); 554 (void) fclose(fd); 555 return (error); 556 } 557 558 for (sep = (*bep)->be_sharepnt; sep != NULL; sep = next) { 559 next = sep->se_next; 560 if (!allstates && sep->se_state == LES_ACTIVE) 561 continue; 562 if (error = logtab_rement(fd, (*bep)->be_name, sep->se_name, 563 NULL, sep->se_state)) { 564 syslog(LOG_ERR, gettext("cannot update %s\n"), 565 NFSLOGTAB); 566 error = EIO; 567 goto errout; 568 } 569 remove_sharepnt_ent(&((*bep)->be_sharepnt), sep); 570 } 571 572 if ((*bep)->be_sharepnt == NULL) { 573 /* 574 * All sharepoints were removed from NFSLOGTAB. 575 * Remove this buffer from our list. 576 */ 577 remove_buffer_ent(buffer_list, *bep); 578 *bep = NULL; 579 } 580 581 errout: (void) fclose(fd); 582 583 return (error); 584 } 585 586 /* 587 * Deactivates entries if nfslogtab is older than the boot time. 588 */ 589 static int 590 nfslogtab_deactivate_after_boot(void) 591 { 592 FILE *fd; 593 int error = 0; 594 595 fd = fopen(NFSLOGTAB, "r+"); 596 if (fd == NULL) { 597 error = errno; 598 if (error != ENOENT) { 599 syslog(LOG_ERR, gettext("%s: %s\n"), NFSLOGTAB, 600 strerror(error)); 601 return (-1); 602 } 603 return (0); 604 } 605 606 if (lockf(fileno(fd), F_LOCK, 0L) < 0) { 607 error = errno; 608 syslog(LOG_ERR, gettext("cannot lock %s: %s\n"), 609 NFSLOGTAB, strerror(error)); 610 (void) fclose(fd); 611 return (-1); 612 } 613 614 if (logtab_deactivate_after_boot(fd) == -1) { 615 syslog(LOG_ERR, gettext( 616 "Cannot deactivate all entries in %s\n"), NFSLOGTAB); 617 (void) fclose(fd); 618 return (-1); 619 } 620 621 (void) fclose(fd); 622 return (0); 623 } 624 625 /* 626 * Enables the log file cycling flag. 627 */ 628 static void 629 enable_logcycling(void) 630 { 631 need2cycle = TRUE; 632 } 633 634 /* 635 * Cycle all log files that have been active since the last cycling. 636 * This means it's not simply listed in the configuration file, but 637 * there's information associated with it. 638 */ 639 static int 640 cycle_logs(nfsl_config_t *listp, int max_logs_preserve) 641 { 642 nfsl_config_t *clp; 643 void *processed_list = NULL; 644 int error = 0, total_errors = 0; 645 646 for (clp = listp; clp != NULL; clp = clp->nc_next) { 647 error = 0; 648 649 /* 650 * Process transpath log. 651 */ 652 if (clp->nc_logpath) { 653 if (is_cycle_needed(clp->nc_logpath, &processed_list, 654 B_FALSE, &error)) { 655 if (clp->nc_transcookie != NULL) { 656 nfslog_close_transactions( 657 &clp->nc_transcookie); 658 assert(clp->nc_transcookie == NULL); 659 } 660 error = cycle_log(clp->nc_logpath, 661 max_logs_preserve); 662 } else if (error) 663 goto errout; 664 } 665 total_errors += error; 666 667 /* 668 * Process elfpath log. 669 */ 670 if (clp->nc_rpclogpath) { 671 if (is_cycle_needed(clp->nc_rpclogpath, &processed_list, 672 B_FALSE, &error)) { 673 error = cycle_log(clp->nc_rpclogpath, 674 max_logs_preserve); 675 } else if (error) 676 goto errout; 677 } 678 total_errors += error; 679 } 680 681 errout: 682 /* 683 * Free the list of processed entries. 684 */ 685 (void) is_cycle_needed(NULL, &processed_list, B_TRUE, &error); 686 687 return (total_errors); 688 } 689 690 /* 691 * Returns TRUE if this log has not yet been cycled, FALSE otherwise. 692 * '*head' points to the list of entries that have been processed. 693 * If this is a new entry, it gets inserted at the beginning of the 694 * list, and returns TRUE. 695 * 696 * The list is freed if 'need2free' is set, and returns FALSE. 697 * Sets 'error' on failure, and returns FALSE. 698 */ 699 static boolean_t 700 is_cycle_needed(char *path, void **list, boolean_t need2free, int *error) 701 { 702 struct list { 703 char *log; 704 struct list *next; 705 } *head, *next, *p; 706 707 head = (struct list *)(*list); 708 if (need2free) { 709 /* 710 * Free the list and return 711 */ 712 for (p = head; p != NULL; p = next) { 713 next = p->next; 714 free(p); 715 } 716 head = NULL; 717 return (B_FALSE); 718 } 719 720 assert(path != NULL); 721 *error = 0; 722 for (p = head; p != NULL; p = p->next) { 723 /* 724 * Have we seen this before? 725 */ 726 if (strcmp(p->log, path) == 0) 727 return (B_FALSE); 728 } 729 730 /* 731 * Add it to the list 732 */ 733 if ((p = (struct list *)malloc(sizeof (*p))) == NULL) { 734 *error = ENOMEM; 735 syslog(LOG_ERR, gettext("Cannot allocate memory.")); 736 return (B_FALSE); 737 } 738 p->log = path; 739 p->next = head; 740 head = p; 741 742 return (B_TRUE); 743 } 744 745 /* 746 * cycle given log file. 747 */ 748 int 749 cycle_log(char *filename, int max_logs_preserve) 750 { 751 int i; 752 char *file_1; 753 char *file_2; 754 int error = 0; 755 struct stat st; 756 757 if (max_logs_preserve == 0) 758 return (0); 759 760 if (stat(filename, &st) == -1) { 761 if (errno == ENOENT) { 762 /* 763 * Nothing to cycle. 764 */ 765 return (0); 766 } 767 return (errno); 768 } 769 file_1 = (char *)malloc(PATH_MAX); 770 file_2 = (char *)malloc(PATH_MAX); 771 for (i = max_logs_preserve - 2; i >= 0; i--) { 772 (void) sprintf(file_1, "%s.%d", filename, i); 773 (void) sprintf(file_2, "%s.%d", filename, (i + 1)); 774 if (rename(file_1, file_2) == -1) { 775 error = errno; 776 if (error != ENOENT) { 777 syslog(LOG_ERR, gettext( 778 "cycle_log: can not rename %s to %s: %s"), 779 file_1, file_2, strerror(error)); 780 goto out; 781 } 782 } 783 } 784 (void) sprintf(file_1, "%s.0", filename); 785 if (rename(filename, file_1) == -1) { 786 error = errno; 787 if (error != ENOENT) { 788 syslog(LOG_ERR, gettext( 789 "cycle_log: can not rename %s to %s: %s"), 790 filename, file_1, strerror(error)); 791 goto out; 792 } 793 } 794 error = 0; 795 796 out: free(file_1); 797 free(file_2); 798 799 return (error); 800 } 801 802 /* 803 * If operation = PID_STARTUP then checks the nfslogd.pid file, it is opened 804 * if it exists, read and the pid is checked for an active process. If no 805 * active process is found, the pid of this process is written to the file, 806 * and 0 is returned, otherwise non-zero error is returned. 807 * 808 * If operation = PID_SHUTDOWN then removes the nfslogd.pid file and 0 is 809 * returned. 810 */ 811 static int 812 process_pidfile(enum pidfile_operation op) 813 { 814 int fd, read_count; 815 int error = 0; 816 pid_t pid, mypid; 817 char *PidFile = NFSLOGD_PIDFILE; 818 int open_flags; 819 820 if (op == PID_STARTUP) 821 open_flags = O_RDWR | O_CREAT; 822 else { 823 assert(op == PID_SHUTDOWN); 824 open_flags = O_RDWR; 825 } 826 827 if ((fd = open(PidFile, open_flags, 0600)) < 0) { 828 error = errno; 829 if (error == ENOENT && op == PID_SHUTDOWN) { 830 /* 831 * We were going to remove it anyway 832 */ 833 error = 0; 834 goto out; 835 } 836 (void) fprintf(stderr, gettext( 837 "cannot open or create pid file %s\n"), PidFile); 838 goto out; 839 } 840 if (lockf(fd, F_LOCK, 0) < 0) { 841 error = errno; 842 (void) fprintf(stderr, gettext( 843 "Cannot lock %s - %s\n"), PidFile, 844 strerror(error)); 845 goto out; 846 } 847 if ((read_count = read(fd, &pid, sizeof (pid))) < 0) { 848 error = errno; 849 (void) fprintf(stderr, gettext( 850 "Can not read from file %s - %s\n"), PidFile, 851 strerror(error)); 852 } 853 854 mypid = getpid(); 855 if (op == PID_STARTUP) { 856 if (read_count > 0) { 857 if (kill(pid, 0) == 0) { 858 error = EEXIST; 859 (void) fprintf(stderr, gettext( 860 "Terminated - nfslogd(%ld) already " 861 "running.\n"), pid); 862 goto out; 863 } else if (errno != ESRCH) { 864 error = errno; 865 (void) fprintf(stderr, gettext( 866 "Unexpected error returned %s\n"), 867 strerror(error)); 868 goto out; 869 } 870 } 871 pid = mypid; 872 /* 873 * rewind the file to overwrite old pid 874 */ 875 (void) lseek(fd, 0, SEEK_SET); 876 if (write(fd, &mypid, sizeof (mypid)) < 0) { 877 error = errno; 878 (void) fprintf(stderr, gettext( 879 "Cannot update %s: %s\n"), 880 PidFile, strerror(error)); 881 } 882 } else { 883 assert(pid == mypid); 884 if (unlink(PidFile)) { 885 error = errno; 886 syslog(LOG_ERR, gettext("Cannot remove %s: %s"), 887 strerror(error)); 888 } 889 } 890 out: 891 if (fd >= 0) 892 (void) close(fd); 893 return (error); 894 } 895 896 /* 897 * Forces a timeout on all open transactions. 898 */ 899 static void 900 transactions_timeout(nfsl_config_t *clp) 901 { 902 for (; clp != NULL; clp = clp->nc_next) { 903 if (clp->nc_transcookie != NULL) { 904 nfslog_process_trans_timeout( 905 (struct nfslog_trans_file *)clp->nc_transcookie, 906 FALSE); 907 } 908 } 909 } 910 911 /* 912 * Closes all transaction logs causing outstanding transactions 913 * to be flushed to their respective log. 914 */ 915 static void 916 close_all_translogs(nfsl_config_t *clp) 917 { 918 for (; clp != NULL; clp = clp->nc_next) { 919 if (clp->nc_transcookie != NULL) { 920 nfslog_close_transactions(&clp->nc_transcookie); 921 assert(clp->nc_transcookie == NULL); 922 } 923 } 924 } 925