newsyslog.c revision 30160
1100966Siwasaki/*
2100966Siwasaki * This file contains changes from the Open Software Foundation.
3100966Siwasaki */
4100966Siwasaki
5167802Sjkim/*
6100966Siwasaki
7100966SiwasakiCopyright 1988, 1989 by the Massachusetts Institute of Technology
8100966Siwasaki
9100966SiwasakiPermission to use, copy, modify, and distribute this software
10100966Siwasakiand its documentation for any purpose and without fee is
11100966Siwasakihereby granted, provided that the above copyright notice
12100966Siwasakiappear in all copies and that both that copyright notice and
13167802Sjkimthis permission notice appear in supporting documentation,
14100966Siwasakiand that the names of M.I.T. and the M.I.T. S.I.P.B. not be
15100966Siwasakiused in advertising or publicity pertaining to distribution
16100966Siwasakiof the software without specific, written prior permission.
17100966SiwasakiM.I.T. and the M.I.T. S.I.P.B. make no representations about
18100966Siwasakithe suitability of this software for any purpose.  It is
19100966Siwasakiprovided "as is" without express or implied warranty.
20100966Siwasaki
21100966Siwasaki*/
22100966Siwasaki
23100966Siwasaki/*
24100966Siwasaki *      newsyslog - roll over selected logs at the appropriate time,
25100966Siwasaki *              keeping the a specified number of backup files around.
26100966Siwasaki */
27100966Siwasaki
28100966Siwasaki#ifndef lint
29100966Siwasakistatic const char rcsid[] =
30100966Siwasaki	"$Id: newsyslog.c,v 1.13 1997/05/06 23:11:06 brian Exp $";
31100966Siwasaki#endif /* not lint */
32100966Siwasaki
33100966Siwasaki#ifndef CONF
34100966Siwasaki#define CONF "/etc/athena/newsyslog.conf" /* Configuration file */
35100966Siwasaki#endif
36100966Siwasaki#ifndef PIDFILE
37100966Siwasaki#define PIDFILE "/etc/syslog.pid"
38100966Siwasaki#endif
39100966Siwasaki#ifndef COMPRESS_PATH
40100966Siwasaki#define COMPRESS_PATH "/usr/ucb/compress" /* File compression program */
41100966Siwasaki#endif
42100966Siwasaki#ifndef COMPRESS_PROG
43100966Siwasaki#define COMPRESS_PROG "compress"
44100966Siwasaki#endif
45100966Siwasaki#ifndef COMPRESS_POSTFIX
46100966Siwasaki#define COMPRESS_POSTFIX ".Z"
47100966Siwasaki#endif
48100966Siwasaki
49100966Siwasaki#include <ctype.h>
50100966Siwasaki#include <err.h>
51100966Siwasaki#include <fcntl.h>
52100966Siwasaki#include <grp.h>
53100966Siwasaki#include <pwd.h>
54100966Siwasaki#include <signal.h>
55100966Siwasaki#include <stdio.h>
56100966Siwasaki#include <stdlib.h>
57100966Siwasaki#include <string.h>
58100966Siwasaki#include <unistd.h>
59100966Siwasaki#include <sys/types.h>
60100966Siwasaki#include <sys/time.h>
61100966Siwasaki#include <sys/stat.h>
62100966Siwasaki#include <sys/param.h>
63100966Siwasaki#include <sys/wait.h>
64100966Siwasaki
65100966Siwasaki#define kbytes(size)  (((size) + 1023) >> 10)
66100966Siwasaki#ifdef _IBMR2
67100966Siwasaki/* Calculates (db * DEV_BSIZE) */
68100966Siwasaki#define dbtob(db)  ((unsigned)(db) << UBSHIFT)
69100966Siwasaki#endif
70100966Siwasaki
71100966Siwasaki#define CE_COMPACT 1            /* Compact the achived log files */
72100966Siwasaki#define CE_BINARY  2            /* Logfile is in binary, don't add */
73100966Siwasaki                                /* status messages */
74100966Siwasaki#define NONE -1
75100966Siwasaki
76100966Siwasakistruct conf_entry {
77100966Siwasaki        char    *log;           /* Name of the log */
78100966Siwasaki	char	*pid_file;	/* PID file */
79100966Siwasaki        int     uid;            /* Owner of log */
80100966Siwasaki        int     gid;            /* Group of log */
81100966Siwasaki        int     numlogs;        /* Number of logs to keep */
82100966Siwasaki        int     size;           /* Size cutoff to trigger trimming the log */
83100966Siwasaki        int     hours;          /* Hours between log trimming */
84100966Siwasaki        int     permissions;    /* File permissions on the log */
85100966Siwasaki        int     flags;          /* Flags (CE_COMPACT & CE_BINARY)  */
86100966Siwasaki        struct conf_entry       *next; /* Linked list pointer */
87100966Siwasaki};
88100966Siwasaki
89100966Siwasakiint     verbose = 0;            /* Print out what's going on */
90100966Siwasakiint     needroot = 1;           /* Root privs are necessary */
91100966Siwasakiint     noaction = 0;           /* Don't do anything, just show it */
92100966Siwasakichar    *conf = CONF;           /* Configuration file to use */
93100966Siwasakitime_t  timenow;
94100966Siwasakipid_t   syslog_pid;             /* read in from /etc/syslog.pid */
95100966Siwasaki#define MIN_PID         5
96100966Siwasaki#define MAX_PID		30000   /* was 65534, see /usr/include/sys/proc.h */
97100966Siwasakichar    hostname[MAXHOSTNAMELEN+1]; /* hostname */
98100966Siwasakichar    *daytime;               /* timenow in human readable form */
99100966Siwasaki
100100966Siwasaki#ifndef OSF
101100966Siwasakichar *strdup(char *strp);
102100966Siwasaki#endif
103100966Siwasaki
104100966Siwasakistatic struct conf_entry *parse_file();
105100966Siwasakistatic char *sob(char *p);
106100966Siwasakistatic char *son(char *p);
107100966Siwasakistatic char *missing_field(char *p,char *errline);
108100966Siwasakistatic void do_entry(struct conf_entry *ent);
109100966Siwasakistatic void PRS(int argc,char **argv);
110100966Siwasakistatic void usage();
111100966Siwasakistatic void dotrim(char *log,char *pid_file,int numdays,int falgs,int perm, int owner_uid,int group_gid);
112100966Siwasakistatic int log_trim(char *log);
113100966Siwasakistatic void compress_log(char *log);
114100966Siwasakistatic int sizefile(char *file);
115100966Siwasakistatic int age_old_log(char *file);
116100966Siwasakistatic pid_t get_pid(char *pid_file);
117100966Siwasaki
118167802Sjkimint main(argc,argv)
119100966Siwasaki        int argc;
120100966Siwasaki        char **argv;
121100966Siwasaki{
122100966Siwasaki        struct conf_entry *p, *q;
123100966Siwasaki
124167802Sjkim        PRS(argc,argv);
125167802Sjkim        if (needroot && getuid() && geteuid())
126167802Sjkim                errx(1, "must have root privs");
127167802Sjkim        p = q = parse_file();
128167802Sjkim
129167802Sjkim	syslog_pid = needroot ? get_pid(PIDFILE) : 0;
130167802Sjkim
131167802Sjkim        while (p) {
132167802Sjkim                do_entry(p);
133167802Sjkim                p=p->next;
134167802Sjkim                free((char *) q);
135167802Sjkim                q=p;
136167802Sjkim        }
137167802Sjkim        return(0);
138167802Sjkim}
139167802Sjkim
140167802Sjkimstatic void do_entry(ent)
141167802Sjkim        struct conf_entry       *ent;
142167802Sjkim
143167802Sjkim{
144167802Sjkim        int     size, modtime;
145167802Sjkim
146167802Sjkim        if (verbose) {
147167802Sjkim                if (ent->flags & CE_COMPACT)
148167802Sjkim                        printf("%s <%dZ>: ",ent->log,ent->numlogs);
149167802Sjkim                else
150167802Sjkim                        printf("%s <%d>: ",ent->log,ent->numlogs);
151167802Sjkim        }
152167802Sjkim        size = sizefile(ent->log);
153167802Sjkim        modtime = age_old_log(ent->log);
154167802Sjkim        if (size < 0) {
155167802Sjkim                if (verbose)
156167802Sjkim                        printf("does not exist.\n");
157167802Sjkim        } else {
158100966Siwasaki                if (verbose && (ent->size > 0))
159100966Siwasaki                        printf("size (Kb): %d [%d] ", size, ent->size);
160100966Siwasaki                if (verbose && (ent->hours > 0))
161100966Siwasaki                        printf(" age (hr): %d [%d] ", modtime, ent->hours);
162100966Siwasaki                if (((ent->size > 0) && (size >= ent->size)) ||
163100966Siwasaki                    ((ent->hours > 0) && ((modtime >= ent->hours)
164100966Siwasaki                                        || (modtime < 0)))) {
165100966Siwasaki                        if (verbose)
166100966Siwasaki                                printf("--> trimming log....\n");
167100966Siwasaki                        if (noaction && !verbose) {
168100966Siwasaki                                if (ent->flags & CE_COMPACT)
169100966Siwasaki                                        printf("%s <%dZ>: trimming",
170100966Siwasaki                                               ent->log,ent->numlogs);
171100966Siwasaki                                else
172100966Siwasaki                                        printf("%s <%d>: trimming",
173167802Sjkim                                               ent->log,ent->numlogs);
174167802Sjkim                        }
175167802Sjkim                        dotrim(ent->log, ent->pid_file, ent->numlogs,
176100966Siwasaki			    ent->flags, ent->permissions, ent->uid, ent->gid);
177100966Siwasaki                } else {
178100966Siwasaki                        if (verbose)
179100966Siwasaki                                printf("--> skipping\n");
180167802Sjkim                }
181167802Sjkim        }
182167802Sjkim}
183167802Sjkim
184167802Sjkimstatic void PRS(argc,argv)
185100966Siwasaki        int argc;
186100966Siwasaki        char **argv;
187100966Siwasaki{
188138287Smarks        int     c;
189151937Sjkim	char	*p;
190100966Siwasaki
191100966Siwasaki        timenow = time((time_t *) 0);
192100966Siwasaki        daytime = ctime(&timenow) + 4;
193151937Sjkim        daytime[15] = '\0';
194151937Sjkim
195151937Sjkim        /* Let's get our hostname */
196151937Sjkim        (void) gethostname(hostname, sizeof(hostname));
197167802Sjkim
198151937Sjkim	/* Truncate domain */
199151937Sjkim	if ((p = strchr(hostname, '.'))) {
200100966Siwasaki		*p = '\0';
201151937Sjkim	}
202151937Sjkim
203151937Sjkim        optind = 1;             /* Start options parsing */
204151937Sjkim        while ((c=getopt(argc,argv,"nrvf:t:")) != -1)
205151937Sjkim                switch (c) {
206151937Sjkim                case 'n':
207151937Sjkim                        noaction++; /* This implies needroot as off */
208151937Sjkim                        /* fall through */
209167802Sjkim                case 'r':
210167802Sjkim                        needroot = 0;
211100966Siwasaki                        break;
212151937Sjkim                case 'v':
213100966Siwasaki                        verbose++;
214100966Siwasaki                        break;
215151937Sjkim                case 'f':
216100966Siwasaki                        conf = optarg;
217151937Sjkim                        break;
218167802Sjkim                default:
219100966Siwasaki                        usage();
220151937Sjkim                }
221100966Siwasaki        }
222100966Siwasaki
223151937Sjkimstatic void usage()
224100966Siwasaki{
225151937Sjkim        fprintf(stderr, "usage: newsyslog [-nrv] [-f config-file]\n");
226167802Sjkim        exit(1);
227167802Sjkim}
228100966Siwasaki
229151937Sjkim/* Parse a configuration file and return a linked list of all the logs
230100966Siwasaki * to process
231100966Siwasaki */
232151937Sjkimstatic struct conf_entry *parse_file()
233100966Siwasaki{
234151937Sjkim        FILE    *f;
235167802Sjkim        char    line[BUFSIZ], *parse, *q;
236100966Siwasaki        char    *errline, *group;
237151937Sjkim        struct conf_entry *first = NULL;
238100966Siwasaki        struct conf_entry *working = NULL;
239100966Siwasaki        struct passwd *pass;
240151937Sjkim        struct group *grp;
241100966Siwasaki	int eol;
242151937Sjkim
243100966Siwasaki        if (strcmp(conf,"-"))
244151937Sjkim                f = fopen(conf,"r");
245100966Siwasaki        else
246100966Siwasaki                f = stdin;
247151937Sjkim        if (!f)
248100966Siwasaki                err(1, "%s", conf);
249151937Sjkim        while (fgets(line,BUFSIZ,f)) {
250100966Siwasaki                if ((line[0]== '\n') || (line[0] == '#'))
251151937Sjkim                        continue;
252100966Siwasaki                errline = strdup(line);
253100966Siwasaki                if (!first) {
254151937Sjkim                        working = (struct conf_entry *) malloc(sizeof(struct conf_entry));
255100966Siwasaki                        first = working;
256151937Sjkim                } else {
257167802Sjkim                        working->next = (struct conf_entry *) malloc(sizeof(struct conf_entry));
258167802Sjkim                        working = working->next;
259167802Sjkim                }
260167802Sjkim
261167802Sjkim                q = parse = missing_field(sob(line),errline);
262100966Siwasaki                parse = son(line);
263151937Sjkim		if (!*parse)
264100966Siwasaki                  errx(1, "malformed line (missing fields):\n%s", errline);
265100966Siwasaki                *parse = '\0';
266151937Sjkim                working->log = strdup(q);
267100966Siwasaki
268151937Sjkim                q = parse = missing_field(sob(++parse),errline);
269167802Sjkim                parse = son(parse);
270167802Sjkim		if (!*parse)
271100966Siwasaki                  errx(1, "malformed line (missing fields):\n%s", errline);
272151937Sjkim                *parse = '\0';
273100966Siwasaki                if ((group = strchr(q, '.')) != NULL) {
274100966Siwasaki                    *group++ = '\0';
275151937Sjkim                    if (*q) {
276100966Siwasaki                        if (!(isnumber(*q))) {
277151937Sjkim                            if ((pass = getpwnam(q)) == NULL)
278100966Siwasaki                                errx(1,
279151937Sjkim                                  "error in config file; unknown user:\n%s",
280100966Siwasaki                                  errline);
281100966Siwasaki                            working->uid = pass->pw_uid;
282151937Sjkim                        } else
283100966Siwasaki                            working->uid = atoi(q);
284151937Sjkim                    } else
285167802Sjkim                        working->uid = NONE;
286100966Siwasaki
287151937Sjkim                    q = group;
288100966Siwasaki                    if (*q) {
289100966Siwasaki                        if (!(isnumber(*q))) {
290151937Sjkim                            if ((grp = getgrnam(q)) == NULL)
291151937Sjkim                                errx(1,
292151937Sjkim                                  "error in config file; unknown group:\n%s",
293151937Sjkim                                  errline);
294167802Sjkim                            working->gid = grp->gr_gid;
295167802Sjkim                        } else
296100966Siwasaki                            working->gid = atoi(q);
297151937Sjkim                    } else
298100966Siwasaki                        working->gid = NONE;
299151937Sjkim
300151937Sjkim                    q = parse = missing_field(sob(++parse),errline);
301151937Sjkim                    parse = son(parse);
302151937Sjkim		    if (!*parse)
303151937Sjkim                      errx(1, "malformed line (missing fields):\n%s", errline);
304151937Sjkim                    *parse = '\0';
305151937Sjkim                }
306151937Sjkim                else
307167802Sjkim                    working->uid = working->gid = NONE;
308167802Sjkim
309167802Sjkim                if (!sscanf(q,"%o",&working->permissions))
310167802Sjkim                        errx(1, "error in config file; bad permissions:\n%s",
311167802Sjkim                          errline);
312100966Siwasaki
313151937Sjkim                q = parse = missing_field(sob(++parse),errline);
314100966Siwasaki                parse = son(parse);
315100966Siwasaki		if (!*parse)
316151937Sjkim                  errx(1, "malformed line (missing fields):\n%s", errline);
317100966Siwasaki                *parse = '\0';
318151937Sjkim                if (!sscanf(q,"%d",&working->numlogs))
319100966Siwasaki                        errx(1, "error in config file; bad number:\n%s",
320151937Sjkim                          errline);
321100966Siwasaki
322100966Siwasaki                q = parse = missing_field(sob(++parse),errline);
323151937Sjkim                parse = son(parse);
324100966Siwasaki		if (!*parse)
325151937Sjkim                  errx(1, "malformed line (missing fields):\n%s", errline);
326167802Sjkim                *parse = '\0';
327167802Sjkim                if (isdigit(*q))
328167802Sjkim                        working->size = atoi(q);
329167802Sjkim                else
330167802Sjkim                        working->size = -1;
331100966Siwasaki
332151937Sjkim                q = parse = missing_field(sob(++parse),errline);
333100966Siwasaki                parse = son(parse);
334100966Siwasaki		eol = !*parse;
335151937Sjkim                *parse = '\0';
336100966Siwasaki                if (isdigit(*q))
337151937Sjkim                        working->hours = atoi(q);
338167802Sjkim                else
339167802Sjkim                        working->hours = -1;
340167802Sjkim
341100966Siwasaki		if (eol)
342151937Sjkim		  q = NULL;
343100966Siwasaki		else {
344100966Siwasaki                  q = parse = sob(++parse); /* Optional field */
345151937Sjkim                  parse = son(parse);
346167802Sjkim		  if (!*parse)
347167802Sjkim                    eol = 1;
348167802Sjkim                  *parse = '\0';
349151937Sjkim		}
350151937Sjkim
351151937Sjkim                working->flags = 0;
352100966Siwasaki                while (q && *q && !isspace(*q)) {
353151937Sjkim                        if ((*q == 'Z') || (*q == 'z'))
354151937Sjkim                                working->flags |= CE_COMPACT;
355151937Sjkim                        else if ((*q == 'B') || (*q == 'b'))
356151937Sjkim                                working->flags |= CE_BINARY;
357151937Sjkim                        else if (*q != '-')
358151937Sjkim                           errx(1, "illegal flag in config file -- %c", *q);
359151937Sjkim                        q++;
360151937Sjkim                }
361151937Sjkim
362151937Sjkim		if (eol)
363167802Sjkim		  q = NULL;
364167802Sjkim		else {
365167802Sjkim		  q = parse = sob(++parse); /* Optional field */
366167802Sjkim		  *(parse = son(parse)) = '\0';
367167802Sjkim		}
368167802Sjkim
369167802Sjkim		working->pid_file = NULL;
370167802Sjkim		if (q && *q) {
371100966Siwasaki			if (*q == '/')
372151937Sjkim				working->pid_file = strdup(q);
373100966Siwasaki                        else
374151937Sjkim			   errx(1, "illegal pid file in config file:\n%s", q);
375100966Siwasaki		}
376151937Sjkim
377151937Sjkim                free(errline);
378100966Siwasaki        }
379151937Sjkim        if (working)
380151937Sjkim                working->next = (struct conf_entry *) NULL;
381167802Sjkim        (void) fclose(f);
382167802Sjkim        return(first);
383167802Sjkim}
384167802Sjkim
385167802Sjkimstatic char *missing_field(p,errline)
386151937Sjkim        char    *p,*errline;
387151937Sjkim{
388151937Sjkim        if (!p || !*p)
389151937Sjkim            errx(1, "missing field in config file:\n%s", errline);
390151937Sjkim        return(p);
391151937Sjkim}
392151937Sjkim
393151937Sjkimstatic void dotrim(log,pid_file,numdays,flags,perm,owner_uid,group_gid)
394167802Sjkim        char    *log;
395167802Sjkim	char    *pid_file;
396167802Sjkim        int     numdays;
397167802Sjkim        int     flags;
398167802Sjkim        int     perm;
399100966Siwasaki        int     owner_uid;
400151937Sjkim        int     group_gid;
401100966Siwasaki{
402100966Siwasaki        char    file1 [MAXPATHLEN+1], file2 [MAXPATHLEN+1];
403151937Sjkim        char    zfile1[MAXPATHLEN+1], zfile2[MAXPATHLEN+1];
404100966Siwasaki	int     notified, need_notification, fd, _numdays;
405151937Sjkim        struct  stat st;
406151937Sjkim	pid_t   pid;
407167802Sjkim
408167802Sjkim#ifdef _IBMR2
409167802Sjkim/* AIX 3.1 has a broken fchown- if the owner_uid is -1, it will actually */
410167802Sjkim/* change it to be owned by uid -1, instead of leaving it as is, as it is */
411167802Sjkim/* supposed to. */
412100966Siwasaki                if (owner_uid == -1)
413151937Sjkim                  owner_uid = geteuid();
414100966Siwasaki#endif
415100966Siwasaki
416151937Sjkim        /* Remove oldest log */
417100966Siwasaki        (void) sprintf(file1,"%s.%d",log,numdays);
418151937Sjkim        (void) strcpy(zfile1, file1);
419167802Sjkim        (void) strcat(zfile1, COMPRESS_POSTFIX);
420167802Sjkim
421167802Sjkim        if (noaction) {
422100966Siwasaki                printf("rm -f %s\n", file1);
423100966Siwasaki                printf("rm -f %s\n", zfile1);
424151937Sjkim        } else {
425100966Siwasaki                (void) unlink(file1);
426100966Siwasaki                (void) unlink(zfile1);
427151937Sjkim        }
428100966Siwasaki
429151937Sjkim        /* Move down log files */
430167802Sjkim	_numdays = numdays;	/* preserve */
431167802Sjkim        while (numdays--) {
432167802Sjkim                (void) strcpy(file2,file1);
433167802Sjkim                (void) sprintf(file1,"%s.%d",log,numdays);
434167802Sjkim                (void) strcpy(zfile1, file1);
435100966Siwasaki                (void) strcpy(zfile2, file2);
436151937Sjkim                if (lstat(file1, &st)) {
437100966Siwasaki                        (void) strcat(zfile1, COMPRESS_POSTFIX);
438100966Siwasaki                        (void) strcat(zfile2, COMPRESS_POSTFIX);
439100966Siwasaki			if (lstat(zfile1, &st)) continue;
440100966Siwasaki                }
441100966Siwasaki                if (noaction) {
442138287Smarks                        printf("mv %s %s\n",zfile1,zfile2);
443100966Siwasaki                        printf("chmod %o %s\n", perm, zfile2);
444151937Sjkim                        printf("chown %d.%d %s\n",
445100966Siwasaki                               owner_uid, group_gid, zfile2);
446151937Sjkim                } else {
447100966Siwasaki                        (void) rename(zfile1, zfile2);
448167802Sjkim                        (void) chmod(zfile2, perm);
449167802Sjkim                        (void) chown(zfile2, owner_uid, group_gid);
450167802Sjkim                }
451100966Siwasaki        }
452151937Sjkim        if (!noaction && !(flags & CE_BINARY))
453100966Siwasaki                (void) log_trim(log);  /* Report the trimming to the old log */
454167802Sjkim
455167802Sjkim	if (!_numdays) {
456167802Sjkim		if (noaction)
457167802Sjkim			printf("rm %s\n",log);
458167802Sjkim		else
459167802Sjkim			(void)unlink(log);
460167802Sjkim	}
461167802Sjkim	else {
462100966Siwasaki		if (noaction)
463151937Sjkim			printf("mv %s to %s\n",log,file1);
464151937Sjkim		else
465167802Sjkim			(void)rename(log, file1);
466167802Sjkim	}
467167802Sjkim
468167802Sjkim        if (noaction)
469167802Sjkim                printf("Start new log...");
470167802Sjkim        else {
471167802Sjkim                fd = creat(log,perm);
472167802Sjkim                if (fd < 0)
473167802Sjkim                        err(1, "can't start new log");
474167802Sjkim                if (fchown(fd, owner_uid, group_gid))
475151937Sjkim                        err(1, "can't chmod new log file");
476151937Sjkim                (void) close(fd);
477151937Sjkim                if (!(flags & CE_BINARY))
478167802Sjkim                        if (log_trim(log))    /* Add status message */
479167802Sjkim                             err(1, "can't add status message to log");
480167802Sjkim        }
481167802Sjkim        if (noaction)
482151937Sjkim                printf("chmod %o %s...",perm,log);
483151937Sjkim        else
484151937Sjkim                (void) chmod(log,perm);
485100966Siwasaki
486100966Siwasaki	pid = 0;
487	need_notification = notified = 0;
488	if (pid_file != NULL) {
489		need_notification = 1;
490		pid = get_pid(pid_file);
491	} else if (needroot && !(flags & CE_BINARY)) {
492		need_notification = 1;
493		pid = syslog_pid;
494	}
495
496	if (pid) {
497		if (noaction) {
498			notified = 1;
499			printf("kill -HUP %d\n", (int)pid);
500		} else if (kill(pid,SIGHUP))
501			warn("can't notify daemon, pid %d", (int)pid);
502		else {
503			notified = 1;
504			if (verbose)
505				printf("daemon pid %d notified\n", (int)pid);
506		}
507	}
508
509	if ((flags & CE_COMPACT)) {
510		if (need_notification && !notified)
511			warnx("log not compressed because daemon not notified");
512		else if (noaction)
513                        printf("Compress %s.0\n",log);
514		else {
515			if (notified) {
516				if (verbose)
517					printf("small pause to allow daemon to close log\n");
518				sleep(3);
519			}
520                        compress_log(log);
521		}
522        }
523}
524
525/* Log the fact that the logs were turned over */
526static int log_trim(log)
527        char    *log;
528{
529        FILE    *f;
530        if ((f = fopen(log,"a")) == NULL)
531                return(-1);
532        fprintf(f,"%s %s newsyslog[%d]: logfile turned over\n",
533                daytime, hostname, (int)getpid());
534        if (fclose(f) == EOF)
535                err(1, "log_trim: fclose:");
536        return(0);
537}
538
539/* Fork of /usr/ucb/compress to compress the old log file */
540static void compress_log(log)
541        char    *log;
542{
543	pid_t   pid;
544	char    tmp[MAXPATHLEN+1];
545
546        (void) sprintf(tmp,"%s.0",log);
547	pid = fork();
548        if (pid < 0)
549                err(1, "fork");
550        else if (!pid) {
551		(void) execl(COMPRESS_PATH,COMPRESS_PROG,"-f",tmp,0);
552		err(1, COMPRESS_PATH);
553        }
554}
555
556/* Return size in kilobytes of a file */
557static int sizefile(file)
558        char    *file;
559{
560        struct stat sb;
561
562        if (stat(file,&sb) < 0)
563                return(-1);
564        return(kbytes(dbtob(sb.st_blocks)));
565}
566
567/* Return the age of old log file (file.0) */
568static int age_old_log(file)
569        char    *file;
570{
571        struct stat sb;
572        char tmp[MAXPATHLEN+sizeof(".0")+sizeof(COMPRESS_POSTFIX)+1];
573
574        (void) strcpy(tmp,file);
575        if (stat(strcat(tmp,".0"),&sb) < 0)
576            if (stat(strcat(tmp,COMPRESS_POSTFIX), &sb) < 0)
577                return(-1);
578        return( (int) (timenow - sb.st_mtime + 1800) / 3600);
579}
580
581static pid_t get_pid(pid_file)
582	char *pid_file;
583{
584	FILE *f;
585	char  line[BUFSIZ];
586	pid_t pid = 0;
587
588	if ((f = fopen(pid_file,"r")) == NULL)
589		warn("can't open %s pid file to restart a daemon",
590			pid_file);
591	else {
592		if (fgets(line,BUFSIZ,f)) {
593			pid = atol(line);
594			if (pid < MIN_PID || pid > MAX_PID) {
595				warnx("preposterous process number: %d", (int)pid);
596				pid = 0;
597			}
598		} else
599			warn("can't read %s pid file to restart a daemon",
600				pid_file);
601		(void)fclose(f);
602	}
603	return pid;
604}
605
606#ifndef OSF
607/* Duplicate a string using malloc */
608
609char *strdup(strp)
610register char   *strp;
611{
612        register char *cp;
613
614        if ((cp = malloc((unsigned) strlen(strp) + 1)) == NULL)
615                abort();
616        return(strcpy (cp, strp));
617}
618#endif
619
620/* Skip Over Blanks */
621char *sob(p)
622	register char   *p;
623{
624        while (p && *p && isspace(*p))
625                p++;
626        return(p);
627}
628
629/* Skip Over Non-Blanks */
630char *son(p)
631	register char   *p;
632{
633        while (p && *p && !isspace(*p))
634                p++;
635        return(p);
636}
637