/* ** If LOGGING is defined, this module logs invocation info ** in /tes/lib/vanilla.log (if it exists already and is ** writable). */ #ifdef LOGGING #include #include #include #include #include #include #include #include #include #include #include #include #include "version.h" struct { char exec_path[PATH_MAX]; struct timeval start_time, end_time; char start_time_str[32]; char end_time_str[32]; char dataset_path[PATH_MAX]; char **args; int nargs; } loginfo; /* items to be logged */ typedef void (*sighandler)(int); sighandler sighandlers[NSIG]; /* some arbitrary number */ #define INSTALL_HANDLER(handlers, sig, handler) \ if (((handlers)[(sig)] = signal((sig), (handler))) == SIG_IGN){ \ signal((sig), SIG_IGN); \ (handlers)[(sig)] = SIG_IGN; \ } static void invocation_log_end() { time_t clock; char *p; gettimeofday(&loginfo.end_time, NULL); clock = time(NULL); /* ctime_r(&clock, loginfo.end_time_str, sizeof(loginfo.end_time_str)); */ strcpy(loginfo.end_time_str, ctime(&clock)); if (p = strchr(loginfo.end_time_str, '\n')){ *p = 0; } } /* ** issignal = 0 -- called by exit() ** issignal = 1 -- called via a signal */ static void invocation_log_common_exit_handler(int issignal, int exit_status) { const char separator[] = "====================================================================="; const char invocation_log_file[] = "/tes/lib/vanilla.log"; char null_str[] = "(null)"; FILE *logfile; int i; struct timeval tdiff; struct flock sflock; int fd; char hostnamestr[1024]; char loginname[L_cuserid]; /* ** Make sure the log file already exits and is writable. ** If not, we don't want to create it. */ if ((fd = open(invocation_log_file, O_WRONLY | O_APPEND, 0666)) >= 0){ /* accumulate "end" statistics */ invocation_log_end(); /* evalulate time consumed during processing */ tdiff.tv_usec = loginfo.end_time.tv_usec - loginfo.start_time.tv_usec; tdiff.tv_sec = loginfo.end_time.tv_sec - loginfo.start_time.tv_sec; if (tdiff.tv_usec < 0){ tdiff.tv_sec --; tdiff.tv_usec += 1000000UL; } /* ** Obtain a write-lock on the file, so that log from one vanilla ** call does not get jumbled with other concurrent calls. */ sflock.l_type = F_WRLCK; sflock.l_whence = SEEK_CUR; sflock.l_start = 0; sflock.l_len = 0; /* till EOF */ while(fcntl(fd, F_SETLKW, &sflock) == EINTR); /* open the file in buffered mode, so that we can use fprintf() */ if ((logfile = fdopen(fd, "a")) != NULL){ /* format and print statistics */ fprintf(logfile, "\n%s\n", separator); fprintf(logfile, "%s: %s\n", loginfo.exec_path, version); strcpy(hostnamestr, ""); gethostname(hostnamestr, sizeof(hostnamestr)); strcpy(loginname, ""); cuserid(loginname); fprintf(logfile, "user: %d (%s) system: %s\n", getuid(), loginname, hostnamestr); fprintf(logfile, "started: %s\nfinished: %s\ntook: %ld.%ld sec\n", loginfo.start_time_str, loginfo.end_time_str, tdiff.tv_sec, (long)(0.5 + tdiff.tv_usec / 1E3)); fprintf(logfile, "exit-status: %d %s\n", exit_status, (issignal? "(signal)": "")); fprintf(logfile, "DATASET-full-path: \"%s\"\n", loginfo.dataset_path); fprintf(logfile, "command-line arguments: \n"); for(i = 0; i < loginfo.nargs; i++){ fprintf(logfile, " \"%s\"\n", (loginfo.args[i]? loginfo.args[i]: null_str)); } fprintf(logfile, "%s\n", separator); fclose(logfile); } while(fcntl(fd, F_UNLCK, &sflock) == EINTR); close(fd); } if (!issignal) exit(exit_status); else { INSTALL_HANDLER(sighandlers, exit_status, sighandlers[exit_status]); raise(exit_status); } } void invocation_log_on_exit(int exit_status) { invocation_log_common_exit_handler(0, exit_status); } void invocation_log_on_signal(int sig) { invocation_log_common_exit_handler(1, sig); } void invocation_log_start(int ac, char **av) { int i; time_t clock; char *p; if (av[0]){ realpath(av[0], loginfo.exec_path); } else { strcpy(loginfo.exec_path, "(null)"); } clock = time(NULL); /* ctime_r(&clock, loginfo.start_time_str, sizeof(loginfo.start_time_str)); */ strcpy(loginfo.start_time_str, ctime(&clock)); if (p = strchr(loginfo.start_time_str, '\n')){ *p = 0; } gettimeofday(&loginfo.start_time, NULL); loginfo.nargs = ac; loginfo.args = (char **)calloc(sizeof(char *), loginfo.nargs); for(i = 0; i < ac; i++){ loginfo.args[i] = strdup(av[i]); } /* atexit(stats_exit); -- does not give exit_status */ /* install signal handlers */ INSTALL_HANDLER(sighandlers, SIGSEGV, invocation_log_on_signal); INSTALL_HANDLER(sighandlers, SIGBUS, invocation_log_on_signal); INSTALL_HANDLER(sighandlers, SIGPIPE, invocation_log_on_signal); INSTALL_HANDLER(sighandlers, SIGXCPU, invocation_log_on_signal); INSTALL_HANDLER(sighandlers, SIGXFSZ, invocation_log_on_signal); } void invocation_log_dataset(char *dataset) { realpath(dataset, loginfo.dataset_path); } #endif /* LOGGING */