#include #include #include #include #include #include #include #include "log.h" #include "params.h" // logging, monochrome, quiet_level #include "pids.h" #include "shm.h" #include "trinity.h" #include "utils.h" #define BUFSIZE 1024 // decoded syscall args are fprintf'd directly, this is for everything else. char ANSI_RED[] = ""; char ANSI_GREEN[] = ""; char ANSI_YELLOW[] = ""; char ANSI_BLUE[] = ""; char ANSI_MAGENTA[] = ""; char ANSI_CYAN[] = ""; char ANSI_WHITE[] = ""; char ANSI_RESET[] = ""; FILE *mainlogfile; static bool logfiles_opened = FALSE; static FILE *open_logfile(const char *logfilename) { FILE *file; unlink(logfilename); file = fopen(logfilename, "w"); if (!file) outputerr("## couldn't open logfile %s\n", logfilename); return file; } void open_main_logfile(void) { mainlogfile = open_logfile("trinity.log"); if (!mainlogfile) exit(EXIT_FAILURE); logfiles_opened = TRUE; //FIXME: This is a bit crap } void open_child_logfile(struct childdata *child) { char *logfilename; if (logging == FALSE) return; logfilename = zmalloc(64); sprintf(logfilename, "trinity-child%u.log", child->num); child->logfile = open_logfile(logfilename); if (!child->logfile) { shm->exit_reason = EXIT_LOGFILE_OPEN_ERROR; exit(EXIT_FAILURE); } free(logfilename); child->logdirty = FALSE; } void close_logfile(FILE **filehandle) { if (*filehandle == NULL) return; fclose(*filehandle); *filehandle = NULL; } static FILE * find_child_logfile_handle(pid_t pid) { int i; unsigned int j; FILE *log = NULL; i = find_childno(pid); if (i != CHILD_NOT_FOUND) { log = shm->children[i]->logfile; } else { /* This is pretty ugly, and should never happen, * but try again a second later, in case we're racing setup/teardown. * FIXME: We may not even need this now that we have proper locking; test it. */ sleep(1); i = find_childno(pid); if (i == CHILD_NOT_FOUND) { outputerr("Couldn't find child for pid %d\n", pid); return mainlogfile; } log = shm->children[i]->logfile; } if (log != NULL) return log; /* if the logfile hadn't been set, log to main. */ shm->children[i]->logfile = mainlogfile; outputerr("## child %d logfile handle was null logging to main!\n", i); outputerr("## Couldn't find logfile for pid %d\n", pid); dump_childnos(); outputerr("## Logfiles for pids: "); for_each_child(j) outputerr("%p ", shm->children[j]->logfile); outputerr("\n"); (void)fflush(stdout); sleep(5); return mainlogfile; } FILE *find_logfile_handle(void) { FILE *handle = NULL; if ((logging == TRUE) && (logfiles_opened)) { pid_t pid; pid = getpid(); if (pid == initpid) return mainlogfile; if (pid == shm->mainpid) return mainlogfile; if (pid == watchdog_pid) return mainlogfile; handle = find_child_logfile_handle(pid); } return handle; } /* * Flush any pending log writes to disk. * Only to be called from child context. */ void synclogs(void) { int fd; if (logging == FALSE) return; if (this_child->logdirty == FALSE) return; fflush(this_child->logfile); fd = fileno(this_child->logfile); if (fd != -1) (void) fsync(fd); this_child->logdirty = FALSE; /* If we're flushing the child log, may as well flush * any other logs while we're writing to disk. */ (void)fflush(mainlogfile); fsync(fileno(mainlogfile)); } void strip_ansi(char *ansibuf) { char *from = ansibuf, *to = ansibuf; unsigned int len, i; /* If we've specified monochrome, we won't have any ANSI codes * in the buffer to be stripped out. */ if (monochrome == TRUE) return; /* because we look ahead two bytes as we scan the buffer, * we only want to scan a maximum of buffer len - 2 bytes * to avoid reading past the end. */ len = strlen(ansibuf) - 2; for (i = 0; i < len; i++) { *to = from[i]; if (from[i] == '') { if (from[i + 2] == '1') i += 6; // ANSI_COLOUR else i += 3; // ANSI_RESET } else { to++; } } /* copy the trailing 2 bytes */ *to++ = from[i++]; *to++ = from[i]; *to = 0; } /* * level defines whether it gets displayed to the screen with printf. * (it always logs). * 0 = everything, even all the registers * 1 = Watchdog prints syscall count * 2 = Just the reseed values * */ void output(unsigned char level, const char *fmt, ...) { va_list args; int n; FILE *handle; pid_t pid; char outputbuf[BUFSIZE]; char *prefix = NULL; char watchdog_prefix[]="[watchdog]"; char init_prefix[]="[init]"; char main_prefix[]="[main]"; char child_prefix[32]; if (logging == FALSE && level >= quiet_level) return; /* prefix preparation */ pid = getpid(); if (pid == watchdog_pid) prefix = watchdog_prefix; if (pid == initpid) prefix = init_prefix; if (pid == shm->mainpid) prefix = main_prefix; if (prefix == NULL) { unsigned int childno; childno = find_childno(pid); snprintf(child_prefix, sizeof(child_prefix), "[child%u:%u]", childno, pid); prefix = child_prefix; shm->children[childno]->logdirty = TRUE; } /* formatting output */ va_start(args, fmt); n = vsnprintf(outputbuf, sizeof(outputbuf), fmt, args); va_end(args); if (n < 0) { outputerr("## Something went wrong in output() [%d]\n", n); if (getpid() == shm->mainpid) exit_main_fail(); else exit(EXIT_FAILURE); } /* stdout output if needed */ if (quiet_level >= level) { printf("%s %s", prefix, outputbuf); (void)fflush(stdout); } /* go on with file logs only if enabled */ if (logging == FALSE) return; handle = find_logfile_handle(); if (!handle) return; strip_ansi(outputbuf); fprintf(handle, "%s %s", prefix, outputbuf); (void)fflush(handle); } /* * Used as a way to consolidated all printf calls if someones one to redirect it to somewhere else. * note: this function ignores quiet_level since it main purpose is error output. */ void outputerr(const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); } void outputstd(const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stdout, fmt, args); va_end(args); } .