/* * OpenPBS (Portable Batch System) v2.3 Software License * * Copyright (c) 1999-2000 Veridian Information Solutions, Inc. * All rights reserved. * * --------------------------------------------------------------------------- * For a license to use or redistribute the OpenPBS software under conditions * other than those described below, or to purchase support for this software, * please contact Veridian Systems, PBS Products Department ("Licensor") at: * * www.OpenPBS.org +1 650 967-4675 sales@OpenPBS.org * 877 902-4PBS (US toll-free) * --------------------------------------------------------------------------- * * This license covers use of the OpenPBS v2.3 software (the "Software") at * your site or location, and, for certain users, redistribution of the * Software to other sites and locations. Use and redistribution of * OpenPBS v2.3 in source and binary forms, with or without modification, * are permitted provided that all of the following conditions are met. * After December 31, 2001, only conditions 3-6 must be met: * * 1. Commercial and/or non-commercial use of the Software is permitted * provided a current software registration is on file at www.OpenPBS.org. * If use of this software contributes to a publication, product, or * service, proper attribution must be given; see www.OpenPBS.org/credit.html * * 2. Redistribution in any form is only permitted for non-commercial, * non-profit purposes. There can be no charge for the Software or any * software incorporating the Software. Further, there can be no * expectation of revenue generated as a consequence of redistributing * the Software. * * 3. Any Redistribution of source code must retain the above copyright notice * and the acknowledgment contained in paragraph 6, this list of conditions * and the disclaimer contained in paragraph 7. * * 4. Any Redistribution in binary form must reproduce the above copyright * notice and the acknowledgment contained in paragraph 6, this list of * conditions and the disclaimer contained in paragraph 7 in the * documentation and/or other materials provided with the distribution. * * 5. Redistributions in any form must be accompanied by information on how to * obtain complete source code for the OpenPBS software and any * modifications and/or additions to the OpenPBS software. The source code * must either be included in the distribution or be available for no more * than the cost of distribution plus a nominal fee, and all modifications * and additions to the Software must be freely redistributable by any party * (including Licensor) without restriction. * * 6. All advertising materials mentioning features or use of the Software must * display the following acknowledgment: * * "This product includes software developed by NASA Ames Research Center, * Lawrence Livermore National Laboratory, and Veridian Information * Solutions, Inc. * Visit www.OpenPBS.org for OpenPBS software support, * products, and information." * * 7. DISCLAIMER OF WARRANTY * * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT * ARE EXPRESSLY DISCLAIMED. * * IN NO EVENT SHALL VERIDIAN CORPORATION, ITS AFFILIATED COMPANIES, OR THE * U.S. GOVERNMENT OR ANY OF ITS AGENCIES BE LIABLE FOR ANY DIRECT OR INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This license will be governed by the laws of the Commonwealth of Virginia, * without reference to its choice of law rules. */ /* * pbs_log.c - contains functions to log error and event messages to * the log file. * * Functions included are: * log_open() * log_err() * log_ext() * log_record() * log_close() * log_roll() * log_size() */ #include /* the master config generated by configure */ #include "pbs_log.h" #include "portability.h" #include "pbs_error.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #if SYSLOG #include #endif #include /* backtrace information */ #include #include void job_log_close(int msg); /* Global Data */ char log_buffer[LOG_BUF_SIZE]; char log_directory[_POSIX_PATH_MAX/2]; char job_log_directory[_POSIX_PATH_MAX/2]; char log_host_port[1024]; char log_host[1024]; char log_suffix[1024]; char *msg_daemonname = (char *)"unset"; /* Local Data */ static int log_auto_switch = 0; static int log_open_day; static FILE *logfile; /* open stream for log file */ static char *logpath = NULL; static volatile int log_opened = 0; #if SYSLOG static int syslogopen = 0; #endif /* SYSLOG */ pthread_mutex_t log_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; /* variables for job logging */ static int job_log_auto_switch = 0; static int joblog_open_day; static FILE *joblogfile; /* open stream for log file */ static char *joblogpath = NULL; static volatile int job_log_opened = 0; pthread_mutex_t job_log_mutex = PTHREAD_MUTEX_INITIALIZER; /* * the order of these names MUST match the defintions of * PBS_EVENTCLASS_* in log.h */ static const char *class_names[] = { "n/a", "Svr", "Que", "Job", "Req", "Fil", "Act", "node", "trqauthd" }; /* External functions called */ /* local prototypes */ const char *log_get_severity_string(int); /* * mk_log_name - make the log name used by MOM * based on the date: yyyymmdd */ static char *mk_log_name( char *pbuf) /* O (minsize=1024) */ { struct tm *ptm; struct tm tmpPtm; time_t time_now = time(NULL); memset(&tmpPtm, 0, sizeof(struct tm)); ptm = localtime_r(&time_now,&tmpPtm); if (log_suffix[0] != '\0') { if (!strcasecmp(log_suffix, "%h")) { snprintf(pbuf, PATH_MAX, "%s/%04d%02d%02d.%s", log_directory, ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, (log_host[0] != '\0') ? log_host : "localhost"); } else { snprintf(pbuf, PATH_MAX, "%s/%04d%02d%02d.%s", log_directory, ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, log_suffix); } } else { snprintf(pbuf, PATH_MAX, "%s/%04d%02d%02d", log_directory, ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday); } log_open_day = ptm->tm_yday; /* Julian date log opened */ return(pbuf); } /* END mk_log_name() */ /* * mk_job_log_name - make the log name used by MOM * based on the date: yyyymmdd */ static char *mk_job_log_name( char *pbuf, int buf_size) { struct tm *ptm; struct tm tmpPtm; time_t time_now = time(NULL); ptm = localtime_r(&time_now,&tmpPtm); if (log_suffix[0] != '\0') { if (!strcasecmp(log_suffix, "%h")) { snprintf(pbuf, buf_size, "%s/%04d%02d%02d.%s", job_log_directory, ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, (log_host[0] != '\0') ? log_host : "localhost"); } else { snprintf(pbuf, buf_size, "%s/%04d%02d%02d.%s", job_log_directory, ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, log_suffix); } } else { snprintf(pbuf, buf_size, "%s/%04d%02d%02d", job_log_directory, ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday); } joblog_open_day = ptm->tm_yday; /* Julian date log opened */ return(pbuf); } /* END mk_job_log_name() */ int log_init( const char *suffix, /* I (optional) */ const char *hostname) /* I (optional) */ { if (suffix != NULL) snprintf(log_suffix, sizeof(log_suffix), "%s", suffix); if (hostname != NULL) snprintf(log_host, sizeof(log_host), "%s", hostname); return(PBSE_NONE); } /* END log_init() */ /* * log_open() - open the log file for append. * * Opens a (new) log file. * If a log file is already open, and the new file is successfully opened, * the old file is closed. Otherwise the old file is left open. */ int log_open( char *filename, /* abs filename or NULL */ char *directory) /* normal log directory */ { char buf[PATH_MAX]; char buf2[1024]; int fds; if (log_opened > 0) { return(-1); /* already open */ } if (log_directory != directory) /* some calls pass in log_directory */ { snprintf(log_directory, (_POSIX_PATH_MAX) / 2 - 1, "%s", directory); } if ((filename == NULL) || (*filename == '\0')) { filename = mk_log_name(buf); log_auto_switch = 1; } else if (*filename != '/') { return(-1); /* must be absolute path */ } if ((fds = open(filename, O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0) { log_opened = -1; /* note that open failed */ return(-1); } if (fds < 3) { log_opened = fcntl(fds, F_DUPFD, 3); /* overload variable */ if (log_opened < 0) { close(fds); return(-1); } close(fds); fds = log_opened; } /* save the path of the last opened logfile for log_roll */ if (logpath != filename) { if (logpath != NULL) free(logpath); logpath = strdup(filename); } logfile = fdopen(fds, "a"); if (logfile == NULL) { log_opened = -1; return(-1); } setvbuf(logfile, NULL, _IOLBF, 0); /* set line buffering */ log_opened = 1; /* note that file is open */ pthread_mutex_unlock(&log_mutex); if (log_host_port[0]) snprintf(buf2, sizeof(buf2), "Log opened at %s", log_host_port); else snprintf(buf2, sizeof(buf2), "Log opened"); log_record( PBSEVENT_SYSTEM, PBS_EVENTCLASS_SERVER, "Log", buf2); pthread_mutex_lock(&log_mutex); return(0); } /* END log_open() */ /* * job_log_open() - open the log file for append. * * Opens a (new) log file. * If a log file is already open, and the new file is successfully opened, * the old file is closed. Otherwise the old file is left open. */ int job_log_open( char *filename, /* abs filename or NULL */ char *directory) /* normal log directory */ { char buf[_POSIX_PATH_MAX]; char err_log[256]; int fds; if (job_log_opened > 0) { return(1); /* already open */ } if (job_log_directory != directory) /* some calls pass in job_log_directory */ { snprintf(job_log_directory, (_POSIX_PATH_MAX) / 2 - 1, "%s", directory); } if ((filename == NULL) || (*filename == '\0')) { filename = mk_job_log_name(buf, _POSIX_PATH_MAX); job_log_auto_switch = 1; } else if (*filename != '/') { sprintf(err_log, "must use absolute file path: %s", filename); log_err(-1, __func__, err_log); return(-1); /* must be absolute path */ } if ((fds = open(filename, O_CREAT | O_WRONLY | O_APPEND, 0644)) < 0) { job_log_opened = -1; /* note that open failed */ sprintf(err_log, "could not open %s ", filename); log_err(errno, __func__, err_log); return(-1); } if (fds < 3) { job_log_opened = fcntl(fds, F_DUPFD, 3); /* overload variable */ if (job_log_opened < 0) { close(fds); log_err(errno, __func__, "failed to dup job log file descriptor"); return(-1); } close(fds); fds = job_log_opened; } /* save the path of the last opened joblogfile for log_roll */ if (joblogpath != filename) { if (joblogpath != NULL) free(joblogpath); joblogpath = strdup(filename); } joblogfile = fdopen(fds, "a"); setvbuf(joblogfile, NULL, _IOLBF, 0); /* set line buffering */ job_log_opened = 1; /* note that file is open */ return(0); } /* END job_log_open() */ /* * log_err - log an internal error * The error is recorded to the pbs log file and to syslogd if it is * available. If the error file has not been opened and if syslog is * not defined, then the console is opened. */ void log_err( int errnum, /* I (errno or PBSErrno) */ const char *routine, /* I */ const char *text) /* I */ { log_ext(errnum,routine,text,LOG_ERR); return; } /* END log_err() */ /* * log_ext (log extended) - log message to syslog (if available) and to the TORQUE log. * * The error is recorded to the TORQUE log file and to syslogd if it is * available. If the error file has not been opened and if syslog is * not defined, then the console is opened. * Note that this function differs from log_err in that you can specify a severity * level that will accompany the message in the syslog (see 'manpage syslog' for a list * of severity/priority levels). This function, is in fact, used by log_err--it just uses * a severity level of LOG_ERR */ void log_ext( int errnum, /* I (errno or PBSErrno) */ const char *routine, /* I */ const char *text, /* I */ int severity) /* I */ { char buf[LOG_BUF_SIZE]; char *EPtr = NULL; char EBuf[1024]; char tmpLine[2048]; const char *SeverityText = NULL; tmpLine[0] = '\0'; EBuf[0] = '\0'; if (errnum == -1) { buf[0] = '\0'; } else { /* NOTE: some strerror() routines return "Unknown error X" w/bad errno */ if (errnum >= 15000) { EPtr = pbse_to_txt(errnum); } else { EPtr = strerror(errnum); } if (EPtr == NULL) { sprintf(EBuf, "unexpected error %d", errnum); EPtr = EBuf; } sprintf(tmpLine,"%s (%d) in ", EPtr, errnum); } SeverityText = log_get_severity_string(severity); snprintf(buf,sizeof(buf),"%s::%s%s, %s", SeverityText, tmpLine, routine, text); buf[LOG_BUF_SIZE - 1] = '\0'; pthread_mutex_lock(&log_mutex); if (log_opened == 0) { #if !SYSLOG log_open("/dev/console", log_directory); #endif /* not SYSLOG */ } if (isatty(2)) { fprintf(stderr, "%s: %s\n", msg_daemonname, buf); } if (log_opened > 0) { pthread_mutex_unlock(&log_mutex); log_record( PBSEVENT_ERROR | PBSEVENT_FORCE, PBS_EVENTCLASS_SERVER, msg_daemonname, buf); } else pthread_mutex_unlock(&log_mutex); #if SYSLOG if (syslogopen == 0) { openlog(msg_daemonname, LOG_NOWAIT, LOG_DAEMON); syslogopen = 1; } syslog(severity|LOG_DAEMON,"%s",buf); #endif /* SYSLOG */ return; } /* END log_ext() */ /** * Returns a string to represent the syslog severity-level given. */ const char *log_get_severity_string( int severity) { const char *result = NULL; /* We can't just index into an array to get the strings, as we don't always * have control over what the value of the LOG_* consts are */ switch (severity) { case LOG_EMERG: result = "LOG_EMERGENCY"; break; case LOG_ALERT: result = "LOG_ALERT"; break; case LOG_CRIT: result = "LOG_CRITICAL"; break; case LOG_ERR: result = "LOG_ERROR"; break; case LOG_WARNING: result = "LOG_WARNING"; break; case LOG_NOTICE: result = "LOG_NOTICE"; break; case LOG_DEBUG: result = "LOG_DEBUG"; break; case LOG_INFO: default: result = "LOG_INFO"; break; } return(result); } /* END log_get_severity_string() */ /* record job information of completed job to job log */ int log_job_record(const char *buf) { struct tm *ptm; struct tm tmpPtm; time_t now; now = time((time_t *)0); ptm = localtime_r(&now,&tmpPtm); pthread_mutex_lock(&job_log_mutex); /* do we need to switch the log to the new day? */ if (job_log_auto_switch && (ptm->tm_yday != joblog_open_day)) { job_log_close(1); job_log_open(NULL, job_log_directory); if (job_log_opened < 1) { log_err(-1, __func__, "job_log_opened < 1"); pthread_mutex_unlock(&job_log_mutex); return(-1); } } fprintf(joblogfile, "%s\n", buf); fflush(joblogfile); pthread_mutex_unlock(&job_log_mutex); return(0); } /* * See if the log is open. In client commands this will return false. */ bool log_available(int eventtype) { #if SYSLOG if(eventtype&PBSEVENT_SYSLOG) return true; #endif if(log_opened < 1) return true; return false; } /* * log_record - log a message to the log file * The log file must have been opened by log_open(). * * NOTE: do not use in pbs_mom spawned children - does not write to syslog!!! * * The caller should ensure proper formating of the message if "text" * is to contain "continuation lines". */ void log_record( int eventtype, /* I */ int objclass, /* I */ const char *objname, /* I */ const char *text) /* I */ { int tryagain = 2; time_t now; pid_t thr_id = -1; struct tm *ptm; struct tm tmpPtm; int rc = 0; FILE *savlog; char *start = NULL, *end = NULL; size_t nchars; int eventclass = 0; char time_formatted_str[64]; thr_id = syscall(SYS_gettid); pthread_mutex_lock(&log_mutex); #if SYSLOG if (eventtype & PBSEVENT_SYSLOG) { if (syslogopen == 0) { openlog(msg_daemonname, LOG_NOWAIT, LOG_DAEMON); syslogopen = 1; } syslog(LOG_ERR | LOG_DAEMON,"%s",text); } #endif /* SYSLOG */ if (log_opened < 1) { pthread_mutex_unlock(&log_mutex); return; } now = time((time_t *)0); /* get time for message */ ptm = localtime_r(&now,&tmpPtm); /* Do we need to switch the log? */ if (log_auto_switch && (ptm->tm_yday != log_open_day)) { log_close(1); log_open(NULL, log_directory); if (log_opened < 1) { pthread_mutex_unlock(&log_mutex); return; } } time_formatted_str[0] = 0; log_get_set_eventclass(&eventclass, GETV); if (eventclass == PBS_EVENTCLASS_TRQAUTHD) { log_format_trq_timestamp(time_formatted_str, sizeof(time_formatted_str)); } /* * Looking for the newline characters and splitting the output message * on them. Sequence "\r\n" is mapped to the single newline. */ start = (char *)text; while (1) { for (end = start; *end != '\n' && *end != '\r' && *end != '\0'; end++) ; nchars = end - start; if (*end == '\r' && *(end + 1) == '\n') end++; while (tryagain) { if (eventclass != PBS_EVENTCLASS_TRQAUTHD) { rc = fprintf(logfile, "%02d/%02d/%04d %02d:%02d:%02d;%04x;%10.10s.%d;%s;%s;%s%.*s\n", ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_year + 1900, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (eventtype & ~PBSEVENT_FORCE), msg_daemonname, thr_id, class_names[objclass], objname, (text == start ? "" : "[continued]"), (int)nchars, start); } else { rc = fprintf(logfile, "%s %s%.*s\n", time_formatted_str, (text == start ? "" : "[continued]"), (int)nchars, start); } if ((rc < 0) && (errno == EPIPE) && (tryagain == 2)) { /* the log file descriptor has been changed--it now points to a socket! * reopen log and leave the previous file descriptor alone--do not close it */ log_opened = 0; log_open(NULL, log_directory); tryagain--; } else { tryagain = 0; } } if (rc < 0) break; if (*end == '\0') break; start = end + 1; } /* END while (1) */ fflush(logfile); if (rc < 0) { rc = errno; clearerr(logfile); savlog = logfile; logfile = fopen("/dev/console", "w"); /* we need to add this check to make sure the disk isn't full so we don't segfault * if we can't open this then we're going to have a nice surprise failure */ if (logfile != NULL) { pthread_mutex_unlock(&log_mutex); log_err(rc, __func__, "PBS cannot write to its log"); fclose(logfile); pthread_mutex_lock(&log_mutex); } logfile = savlog; } pthread_mutex_unlock(&log_mutex); return; } /* END log_record() */ /* * log_close - close the current open log file */ void log_close( int msg) /* BOOLEAN - write close message */ { char buf[1024]; if (log_opened == 1) { log_auto_switch = 0; if (msg) { if (log_host_port[0]) snprintf(buf, sizeof(buf), "Log closed at %s", log_host_port); else snprintf(buf, sizeof(buf), "Log closed"); pthread_mutex_unlock(&log_mutex); log_record( PBSEVENT_SYSTEM, PBS_EVENTCLASS_SERVER, "Log", buf); pthread_mutex_lock(&log_mutex); } fclose(logfile); log_opened = 0; } #if SYSLOG if (syslogopen) closelog(); #endif /* SYSLOG */ return; } /* END log_close() */ /* * job_log_close - close the current open job log file */ void job_log_close( int msg) /* BOOLEAN - write close message */ { if (job_log_opened == 1) { job_log_auto_switch = 0; if (msg) { log_record( PBSEVENT_SYSTEM, PBS_EVENTCLASS_SERVER, "Log", "Log closed"); } fclose(joblogfile); job_log_opened = 0; } #if SYSLOG if (syslogopen) closelog(); #endif /* SYSLOG */ return; } /* END job_log_close() */ /** * log_remove_old - Removes log files older than a given time. * This function removes files from the given path if they were last modified after ExpireTime. * * Note that this function will skip over special filenames like '.' and '..'. * * @param DirPath (I) * @param ExpireTime (I, how old the file must be to be removed, in seconds) * if (Expiretime == 0), nothing will be removed * @return 0 on success, non-zero otherwise */ int log_remove_old( char *DirPath, /* I (path in which we're removing files)*/ unsigned long ExpireTime) /* I (how old the file must be to be removed, in seconds) */ { char tmpPath[MAX_PATH_LEN]; DIR *DirHandle; struct dirent *FileHandle; struct stat sbuf; unsigned long FMTime; unsigned long TTime; int IsDir = FALSE; TTime = time((time_t *)NULL); /* check the input for an empty path */ if ((DirPath == NULL) || (DirPath[0] == '\0')) { return(-1); } if (ExpireTime == 0) { return(0); } /* open directory for reading */ DirHandle = opendir(DirPath); /* fail if path couldn't be opened */ if (DirHandle == (DIR *)NULL) { return(-1); } FileHandle = readdir(DirHandle); while (FileHandle != (struct dirent *)NULL) { /* attempt to delete old files */ if (!strcmp(FileHandle->d_name,".") || !strcmp(FileHandle->d_name,"..")) { /* skip special file names */ FileHandle = readdir(DirHandle); continue; } snprintf(tmpPath,sizeof(tmpPath),"%s/%s", DirPath, FileHandle->d_name); if (stat(tmpPath,&sbuf) == -1) { /* -1 is the failure value for stat */ FMTime = 0; FileHandle = readdir(DirHandle); continue; } /* set FMTime's value */ FMTime = (unsigned long)sbuf.st_mtime; if ((IsDir == FALSE) && (TTime - FMTime) > ExpireTime) { /* file is too old - delete it */ remove(tmpPath); } FileHandle = readdir(DirHandle); } /* end file checking while loop */ closedir(DirHandle); return(0); } /* END log_remove_ld() */ void log_roll( int max_depth) { int i, suffix_size, file_buf_len, as; int err = 0; char *source = NULL; char *dest = NULL; pthread_mutex_lock(&log_mutex); if (!log_opened) { pthread_mutex_unlock(&log_mutex); return; } /* save value of log_auto_switch */ as = log_auto_switch; log_close(1); /* find out how many characters the suffix could be. (save in suffix_size) start at 1 to account for the "." */ for (i = max_depth, suffix_size = 1;i > 0;suffix_size++, i /= 10) /* NO-OP */; /* allocate memory for rolling */ file_buf_len = sizeof(char) * (strlen(logpath) + suffix_size + 1) /* NO-OP */; source = (char*)calloc(1, file_buf_len); dest = (char*)calloc(1, file_buf_len); if ((source == NULL) || (dest == NULL)) { err = errno; goto done_roll; } /* call unlink to delete logname.max_depth - it doesn't matter if it doesn't exist, so we'll ignore ENOENT */ sprintf(dest, "%s.%d", logpath, max_depth); if ((unlink(dest) != 0) && (errno != ENOENT)) { err = errno; goto done_roll; } /* logname.max_depth is gone, so roll the rest of the log files */ for (i = max_depth - 1;i >= 0;i--) { if (i == 0) { strcpy(source, logpath); } else { sprintf(source, "%s.%d", logpath, i); } sprintf(dest, "%s.%d", logpath, i + 1); /* rename file if it exists */ if ((rename(source, dest) != 0) && (errno != ENOENT)) { err = errno; goto done_roll; } } /* END for (i) */ done_roll: if (as) { log_open(NULL, log_directory); } else { log_open(logpath, log_directory); } pthread_mutex_unlock(&log_mutex); if (source != NULL) free(source); if (dest != NULL) free(dest); if (err != 0) { log_err(err, "log_roll", "error while rollng logs"); } else { log_record( PBSEVENT_SYSTEM, PBS_EVENTCLASS_SERVER, "Log", "Log Rolled"); } return; } /* END log_roll() */ void job_log_roll( int max_depth) { int i, suffix_size, file_buf_len, as; int err = 0; char *source = NULL; char *dest = NULL; pthread_mutex_lock(&job_log_mutex); if (!job_log_opened) { pthread_mutex_unlock(&job_log_mutex); return; } /* save value of job_log_auto_switch */ as = job_log_auto_switch; job_log_close(1); /* find out how many characters the suffix could be. (save in suffix_size) start at 1 to account for the "." */ for (i = max_depth, suffix_size = 1;i > 0;suffix_size++, i /= 10) /* NO-OP */; /* allocate memory for rolling */ file_buf_len = sizeof(char) * (strlen(joblogpath) + suffix_size + 1); source = (char*)calloc(1, file_buf_len); dest = (char*)calloc(1, file_buf_len); if ((source == NULL) || (dest == NULL)) { err = errno; goto done_job_roll; } /* call unlink to delete logname.max_depth - it doesn't matter if it doesn't exist, so we'll ignore ENOENT */ sprintf(dest, "%s.%d", joblogpath, max_depth); if ((unlink(dest) != 0) && (errno != ENOENT)) { err = errno; goto done_job_roll; } /* logname.max_depth is gone, so roll the rest of the log files */ for (i = max_depth - 1;i >= 0;i--) { if (i == 0) { strcpy(source, joblogpath); } else { sprintf(source, "%s.%d", joblogpath, i); } sprintf(dest, "%s.%d", joblogpath, i + 1); /* rename file if it exists */ if ((rename(source, dest) != 0) && (errno != ENOENT)) { err = errno; goto done_job_roll; } } /* END for (i) */ done_job_roll: if (as) { job_log_open(NULL, job_log_directory); } else { job_log_open(joblogpath, job_log_directory); } if (source != NULL) free(source); if (dest != NULL) free(dest); if (err != 0) { log_err(err, "log_roll", "error while rollng logs"); } else { log_record( PBSEVENT_SYSTEM, PBS_EVENTCLASS_SERVER, "Job Log", "Job Log Rolled"); } pthread_mutex_unlock(&job_log_mutex); return; } /* END job_log_roll() */ /* return size of log file in kilobytes */ long log_size(void) { #if defined(HAVE_STRUCT_STAT64) && defined(HAVE_STAT64) && defined(LARGEFILE_WORKS) struct stat64 file_stat = {0}; #else struct stat file_stat; #endif pthread_mutex_lock(&log_mutex); #if defined(HAVE_STRUCT_STAT64) && defined(HAVE_STAT64) && defined(LARGEFILE_WORKS) if (log_opened && (fstat64(fileno(logfile), &file_stat) != 0)) #else if (log_opened && (fstat(fileno(logfile), &file_stat) != 0)) #endif { /* FAILURE */ pthread_mutex_unlock(&log_mutex); /* log_err through log_ext will lock the log_mutex, so release log_mutex before calling log_err */ log_err(errno, "log_size", "PBS cannot fstat logfile"); return(0); } if (!log_opened) { pthread_mutex_unlock(&log_mutex); log_err(EAGAIN, "log_size", "PBS cannot find size of log file because logfile has not been opened"); return(0); } pthread_mutex_unlock(&log_mutex); return(file_stat.st_size / 1024); } /* return size of job log file in kilobytes */ long job_log_size(void) { #if defined(HAVE_STRUCT_STAT64) && defined(HAVE_STAT64) && defined(LARGEFILE_WORKS) struct stat64 file_stat; #else struct stat file_stat; #endif memset(&file_stat, 0, sizeof(file_stat)); pthread_mutex_lock(&job_log_mutex); #if defined(HAVE_STRUCT_STAT64) && defined(HAVE_STAT64) && defined(LARGEFILE_WORKS) if (job_log_opened && (fstat64(fileno(joblogfile), &file_stat) != 0)) #else if (job_log_opened && (fstat(fileno(joblogfile), &file_stat) != 0)) #endif { /* FAILURE */ log_err(errno, __func__, "PBS cannot fstat joblogfile"); pthread_mutex_unlock(&job_log_mutex); return(0); } pthread_mutex_unlock(&job_log_mutex); return(file_stat.st_size / 1024); } void print_trace( int socknum) { void *array[10]; int size; char **meth_names; int cntr; char msg[120]; char meth_name[20]; size = backtrace(array, 10); meth_names = backtrace_symbols(array, size); snprintf(meth_name, sizeof(meth_name), "pt - pos %d", socknum); snprintf(msg, sizeof(msg), "Obtained %d stack frames.\n", size); log_record(PBSEVENT_SYSTEM, PBS_EVENTCLASS_SERVER, meth_name, msg); for (cntr = 0; cntr < size; cntr++) { log_record(PBSEVENT_SYSTEM, PBS_EVENTCLASS_SERVER, meth_name, meth_names[cntr]); } free(meth_names); } void log_get_set_eventclass( int *objclass, SGetter action) { static int log_objclass = 0; if (action == SETV) log_objclass = *objclass; else if (action == GETV) *objclass = log_objclass; } /* end of log_get_set_evnetclass */ void log_format_trq_timestamp( char *time_formatted_str, unsigned int buflen) { char buffer[30]; struct timeval tv; time_t curtime; struct tm result; unsigned int milisec=0; gettimeofday(&tv, NULL); curtime=tv.tv_sec; localtime_r(&curtime, &result); strftime(buffer,30,"%Y-%m-%d %H:%M:%S.", &result); milisec = tv.tv_usec/100; snprintf(time_formatted_str, buflen, "%s%04d", buffer, milisec); } /* end of log_format_trq_timestamp */ void log_set_hostname_sharelogging(const char *server_name, const char *server_port) { char ip[64]; char hostnm[1024]; char *hostname = NULL; struct hostent *he; struct in_addr **addr_list; if (server_name) hostname = (char *)server_name; else if (gethostname(hostnm, sizeof(hostnm)) == 0) hostname = hostnm; if (hostname) { if ((he = gethostbyname(hostname)) == NULL) { strcpy(ip, "null"); } else { addr_list = (struct in_addr **) he->h_addr_list; if (addr_list[0]) snprintf(ip , sizeof(ip), "%s", inet_ntoa(*addr_list[0])); else strcpy(ip, "null"); } } else { strcpy(ip, "null"); strcpy(hostnm, "null"); hostname = hostnm; } snprintf(log_host_port, sizeof(log_host_port), "%s:%s (host: %s)", ip, server_port, hostname); } void log_get_host_port(char *host_n_port, size_t s) { snprintf(host_n_port, s, "%s", log_host_port); } /* END pbs_log.c */