/* This utility is normally used in the probe section of the sendmail startup script. It walks the sendmail.cf file, search for file included by sendmail. It picks the revision date for each file and compare the newest file with the daemon startup date. It outputs "restart" if sendmail must be restarted, or nothing if all is fine. */ #include #include #include #include #include #include #include #include /* Return the maximum between file revision date and date */ static time_t check_date (const char *file, time_t date) { struct stat st; if (stat(file,&st)!=-1 && st.st_mtime > date) date = st.st_mtime; return date; } /* Read the first line of a file Return -1 if any error. */ static int process_readfile (const char *path, char *buf, int sizebuf) { int ret = -1; // No error message signaled as "path" is a file under /proc/pid // and the process may vanish while we are reading it. FILE *fin = fopen (path,"r"); if (fin != NULL){ if (fgets (buf,sizebuf-1,fin)!=NULL){ ret = 0; } fclose (fin); } return ret; } struct PS_PROC { char cmdline[256], user[10], cmd[40], state, ttyc[4]; int uid, pid, ppid, pgrp, session, tty, tpgid, utime, stime, cutime, cstime, counter, priority, start_time, signal, blocked, sigignore, sigcatch; unsigned int flags, min_flt, cmin_flt, maj_flt, cmaj_flt, timeout, it_real_value, vsize, rss, rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip, wchan; }; /* Read the file /proc/pid/stat into the struct PS_PROC Return -1 if any error. */ static int process_readstat(int pid, PS_PROC &_psp) { int ret = -1; char tmppath[PATH_MAX]; sprintf (tmppath,"/proc/%d/stat",pid); char buf[PATH_MAX]; if (process_readfile (tmppath,buf,sizeof(buf))!=-1){ PS_PROC psp; sscanf(buf, "%d %s %c %d %d %d %d %d %u %u " "%u %u %u %d %d %d %d %d %d %u " "%u %d %u %u %u %u %u %u %u %u %u " "%u %u %u %u\n", &psp.pid, psp.cmd, &psp.state, &psp.ppid, &psp.pgrp, &psp.session, &psp.tty, &psp.tpgid, &psp.flags, &psp.min_flt, &psp.cmin_flt, &psp.maj_flt, &psp.cmaj_flt, &psp.utime, &psp.stime, &psp.cutime, &psp.cstime, &psp.counter, &psp.priority, &psp.timeout, &psp.it_real_value, &psp.start_time, &psp.vsize, &psp.rss, &psp.rss_rlim, &psp.start_code, &psp.end_code, &psp.start_stack, &psp.kstk_esp, &psp.kstk_eip, &psp.signal, &psp.blocked, &psp.sigignore, &psp.sigcatch, &psp.wchan); _psp = psp; ret = 0; } return ret; } /* Return the start time of a process. Return -1 is the process is dead. */ static time_t process_getstarttime (int pid) { time_t ret = -1; long uptime; char buf[200]; if (process_readfile ("/proc/uptime",buf,sizeof(buf))!=-1){ uptime = atoi(buf); PS_PROC psp; if (process_readstat(pid,psp)!=-1){ time_t seconds = uptime - (psp.start_time / HZ); ret = time(NULL) - seconds; } } return ret; } int main (int argc, char *argv[]) { int ret = -1; if (argc != 3){ fprintf (stderr,"sendmail-check path_of_sendmail.cf pidfile\n"); }else{ time_t date = 0; date = check_date (argv[1],date); FILE *fin = fopen (argv[1],"r"); if (fin != NULL){ char buf[1000]; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ if (buf[0] == 'F'){ char *pt = buf; while (*pt > ' ') pt++; while (isspace(*pt)) pt++; // We have the file name now char file[1000]; char *dst = file; while (*pt > ' ') *dst++ = *pt++; *dst = '\0'; date = check_date (file,date); } } fclose (fin); } fin = fopen (argv[2],"r"); if (fin != NULL){ int pid; if (fscanf(fin,"%d",&pid)==1){ time_t start = process_getstarttime (pid); if (date > start) printf ("restart\n"); }else{ // The pid file is broken. Better do a restart printf ("restart\n"); } fclose (fin); }else{ printf ("start\n"); } } return ret; }