newsyslog.c revision 1.21 1 1.21 ad /* $NetBSD: newsyslog.c,v 1.21 1999/11/30 12:03:24 ad Exp $ */
2 1.12 thorpej
3 1.1 cgd /*
4 1.1 cgd * This file contains changes from the Open Software Foundation.
5 1.1 cgd */
6 1.1 cgd
7 1.1 cgd /*
8 1.1 cgd
9 1.2 cgd Copyright 1988, 1989 by the Massachusetts Institute of Technology
10 1.1 cgd
11 1.2 cgd Permission to use, copy, modify, and distribute this software
12 1.2 cgd and its documentation for any purpose and without fee is
13 1.2 cgd hereby granted, provided that the above copyright notice
14 1.2 cgd appear in all copies and that both that copyright notice and
15 1.2 cgd this permission notice appear in supporting documentation,
16 1.2 cgd and that the names of M.I.T. and the M.I.T. S.I.P.B. not be
17 1.2 cgd used in advertising or publicity pertaining to distribution
18 1.2 cgd of the software without specific, written prior permission.
19 1.2 cgd M.I.T. and the M.I.T. S.I.P.B. make no representations about
20 1.2 cgd the suitability of this software for any purpose. It is
21 1.2 cgd provided "as is" without express or implied warranty.
22 1.1 cgd
23 1.1 cgd */
24 1.1 cgd
25 1.1 cgd /*
26 1.1 cgd * newsyslog - roll over selected logs at the appropriate time,
27 1.1 cgd * keeping the a specified number of backup files around.
28 1.1 cgd */
29 1.1 cgd
30 1.13 lukem #include <sys/cdefs.h>
31 1.5 mycroft #ifndef lint
32 1.21 ad __RCSID("$NetBSD: newsyslog.c,v 1.21 1999/11/30 12:03:24 ad Exp $");
33 1.5 mycroft #endif /* not lint */
34 1.1 cgd
35 1.1 cgd #ifndef CONF
36 1.1 cgd #define CONF "/etc/athena/newsyslog.conf" /* Configuration file */
37 1.1 cgd #endif
38 1.1 cgd #ifndef PIDFILE
39 1.1 cgd #define PIDFILE "/etc/syslog.pid"
40 1.1 cgd #endif
41 1.1 cgd #ifndef COMPRESS
42 1.1 cgd #define COMPRESS "/usr/ucb/compress" /* File compression program */
43 1.1 cgd #endif
44 1.3 cgd #ifndef COMPRESS_POSTFIX
45 1.3 cgd #define COMPRESS_POSTFIX ".Z"
46 1.3 cgd #endif
47 1.1 cgd
48 1.1 cgd #include <sys/types.h>
49 1.1 cgd #include <sys/time.h>
50 1.1 cgd #include <sys/stat.h>
51 1.1 cgd #include <sys/param.h>
52 1.1 cgd #include <sys/wait.h>
53 1.1 cgd
54 1.13 lukem #include <ctype.h>
55 1.13 lukem #include <fcntl.h>
56 1.13 lukem #include <grp.h>
57 1.13 lukem #include <pwd.h>
58 1.13 lukem #include <signal.h>
59 1.13 lukem #include <stdio.h>
60 1.13 lukem #include <stdlib.h>
61 1.13 lukem #include <string.h>
62 1.14 kleink #include <time.h>
63 1.13 lukem #include <unistd.h>
64 1.13 lukem
65 1.1 cgd #define kbytes(size) (((size) + 1023) >> 10)
66 1.1 cgd #ifdef _IBMR2
67 1.1 cgd /* Calculates (db * DEV_BSIZE) */
68 1.1 cgd #define dbtob(db) ((unsigned)(db) << UBSHIFT)
69 1.1 cgd #endif
70 1.1 cgd
71 1.1 cgd #define CE_COMPACT 1 /* Compact the achived log files */
72 1.1 cgd #define CE_BINARY 2 /* Logfile is in binary, don't add */
73 1.1 cgd /* status messages */
74 1.21 ad #define CE_NOSIGNAL 4 /* Don't send a signal when trimmed */
75 1.1 cgd #define NONE -1
76 1.1 cgd
77 1.1 cgd struct conf_entry {
78 1.1 cgd char *log; /* Name of the log */
79 1.1 cgd int uid; /* Owner of log */
80 1.1 cgd int gid; /* Group of log */
81 1.1 cgd int numlogs; /* Number of logs to keep */
82 1.1 cgd int size; /* Size cutoff to trigger trimming the log */
83 1.1 cgd int hours; /* Hours between log trimming */
84 1.1 cgd int permissions; /* File permissions on the log */
85 1.21 ad int flags; /* Flags (CE_*) */
86 1.20 ad char *pidfile; /* Name of file containing PID to signal */
87 1.21 ad int signum; /* Signal to send */
88 1.1 cgd struct conf_entry *next; /* Linked list pointer */
89 1.1 cgd };
90 1.1 cgd
91 1.1 cgd char *progname; /* contains argv[0] */
92 1.1 cgd int verbose = 0; /* Print out what's going on */
93 1.1 cgd int needroot = 1; /* Root privs are necessary */
94 1.1 cgd int noaction = 0; /* Don't do anything, just show it */
95 1.21 ad int force; /* Force the trim no matter what */
96 1.1 cgd char *conf = CONF; /* Configuration file to use */
97 1.1 cgd time_t timenow;
98 1.1 cgd int syslog_pid; /* read in from /etc/syslog.pid */
99 1.7 pk #define MIN_PID 3
100 1.7 pk #define MAX_PID 65534
101 1.15 mrg char hostname[MAXHOSTNAMELEN + 1]; /* hostname */
102 1.1 cgd char *daytime; /* timenow in human readable form */
103 1.1 cgd
104 1.1 cgd
105 1.13 lukem void PRS __P((int, char **));
106 1.13 lukem int age_old_log __P((char *));
107 1.13 lukem void compress_log __P((char *));
108 1.21 ad void dotrim __P((char *, int, int, int, int, int, char *, int));
109 1.13 lukem void do_entry __P((struct conf_entry *));
110 1.13 lukem int isnumber __P((char *));
111 1.13 lukem int log_trim __P((char *));
112 1.13 lukem int main __P((int, char **));
113 1.13 lukem char *missing_field __P((char *, char *));
114 1.13 lukem struct conf_entry *parse_file __P((void));
115 1.13 lukem int sizefile __P((char *));
116 1.13 lukem char *sob __P((char *));
117 1.13 lukem char *son __P((char *));
118 1.13 lukem void usage __P((void));
119 1.21 ad int getsig __P((char *));
120 1.1 cgd
121 1.13 lukem int
122 1.1 cgd main(argc,argv)
123 1.1 cgd int argc;
124 1.1 cgd char **argv;
125 1.1 cgd {
126 1.1 cgd struct conf_entry *p, *q;
127 1.1 cgd
128 1.1 cgd PRS(argc,argv);
129 1.1 cgd if (needroot && getuid() && geteuid()) {
130 1.1 cgd fprintf(stderr,"%s: must have root privs\n",progname);
131 1.1 cgd exit(1);
132 1.1 cgd }
133 1.1 cgd p = q = parse_file();
134 1.1 cgd while (p) {
135 1.1 cgd do_entry(p);
136 1.1 cgd p=p->next;
137 1.1 cgd free((char *) q);
138 1.1 cgd q=p;
139 1.1 cgd }
140 1.1 cgd exit(0);
141 1.1 cgd }
142 1.1 cgd
143 1.13 lukem void
144 1.1 cgd do_entry(ent)
145 1.1 cgd struct conf_entry *ent;
146 1.1 cgd {
147 1.1 cgd int size, modtime;
148 1.1 cgd
149 1.1 cgd if (verbose) {
150 1.1 cgd if (ent->flags & CE_COMPACT)
151 1.1 cgd printf("%s <%dZ>: ",ent->log,ent->numlogs);
152 1.1 cgd else
153 1.1 cgd printf("%s <%d>: ",ent->log,ent->numlogs);
154 1.1 cgd }
155 1.1 cgd size = sizefile(ent->log);
156 1.1 cgd modtime = age_old_log(ent->log);
157 1.1 cgd if (size < 0) {
158 1.1 cgd if (verbose)
159 1.1 cgd printf("does not exist.\n");
160 1.1 cgd } else {
161 1.1 cgd if (verbose && (ent->size > 0))
162 1.1 cgd printf("size (Kb): %d [%d] ", size, ent->size);
163 1.1 cgd if (verbose && (ent->hours > 0))
164 1.1 cgd printf(" age (hr): %d [%d] ", modtime, ent->hours);
165 1.21 ad if (force || ((ent->size > 0) && (size >= ent->size)) ||
166 1.1 cgd ((ent->hours > 0) && ((modtime >= ent->hours)
167 1.1 cgd || (modtime < 0)))) {
168 1.1 cgd if (verbose)
169 1.1 cgd printf("--> trimming log....\n");
170 1.1 cgd if (noaction && !verbose) {
171 1.1 cgd if (ent->flags & CE_COMPACT)
172 1.1 cgd printf("%s <%dZ>: trimming",
173 1.1 cgd ent->log,ent->numlogs);
174 1.1 cgd else
175 1.1 cgd printf("%s <%d>: trimming",
176 1.1 cgd ent->log,ent->numlogs);
177 1.1 cgd }
178 1.1 cgd dotrim(ent->log, ent->numlogs, ent->flags,
179 1.20 ad ent->permissions, ent->uid, ent->gid,
180 1.21 ad ent->pidfile, ent->signum);
181 1.1 cgd } else {
182 1.1 cgd if (verbose)
183 1.1 cgd printf("--> skipping\n");
184 1.1 cgd }
185 1.1 cgd }
186 1.1 cgd }
187 1.1 cgd
188 1.13 lukem void
189 1.1 cgd PRS(argc,argv)
190 1.1 cgd int argc;
191 1.1 cgd char **argv;
192 1.1 cgd {
193 1.1 cgd int c;
194 1.1 cgd FILE *f;
195 1.1 cgd char line[BUFSIZ];
196 1.8 jtc char *p;
197 1.1 cgd
198 1.1 cgd progname = argv[0];
199 1.1 cgd timenow = time((time_t *) 0);
200 1.8 jtc daytime = ctime(&timenow) + 4;
201 1.10 pk daytime[15] = '\0';
202 1.1 cgd
203 1.1 cgd /* Let's find the pid of syslogd */
204 1.1 cgd syslog_pid = 0;
205 1.1 cgd f = fopen(PIDFILE,"r");
206 1.1 cgd if (f && fgets(line,BUFSIZ,f))
207 1.1 cgd syslog_pid = atoi(line);
208 1.7 pk if (f)
209 1.7 pk (void)fclose(f);
210 1.1 cgd
211 1.1 cgd /* Let's get our hostname */
212 1.15 mrg (void)gethostname(hostname, sizeof(hostname));
213 1.15 mrg hostname[sizeof(hostname) - 1] = '\0';
214 1.8 jtc
215 1.8 jtc /* Truncate domain */
216 1.13 lukem if ((p = strchr(hostname, '.')) != NULL) {
217 1.8 jtc *p = '\0';
218 1.8 jtc }
219 1.1 cgd
220 1.1 cgd optind = 1; /* Start options parsing */
221 1.21 ad while ((c=getopt(argc,argv,"Fnrvf:")) != -1)
222 1.1 cgd switch (c) {
223 1.1 cgd case 'n':
224 1.1 cgd noaction++; /* This implies needroot as off */
225 1.1 cgd /* fall through */
226 1.1 cgd case 'r':
227 1.1 cgd needroot = 0;
228 1.1 cgd break;
229 1.1 cgd case 'v':
230 1.1 cgd verbose++;
231 1.1 cgd break;
232 1.1 cgd case 'f':
233 1.1 cgd conf = optarg;
234 1.1 cgd break;
235 1.21 ad case 'F':
236 1.21 ad force++;
237 1.21 ad break;
238 1.1 cgd default:
239 1.1 cgd usage();
240 1.1 cgd }
241 1.13 lukem }
242 1.1 cgd
243 1.13 lukem void
244 1.1 cgd usage()
245 1.1 cgd {
246 1.1 cgd fprintf(stderr,
247 1.21 ad "Usage: %s <-Fnrv> <-f config-file>\n", progname);
248 1.1 cgd exit(1);
249 1.1 cgd }
250 1.1 cgd
251 1.1 cgd /* Parse a configuration file and return a linked list of all the logs
252 1.1 cgd * to process
253 1.1 cgd */
254 1.13 lukem struct conf_entry *
255 1.13 lukem parse_file()
256 1.1 cgd {
257 1.1 cgd FILE *f;
258 1.1 cgd char line[BUFSIZ], *parse, *q;
259 1.21 ad char *errline, *group, prev;
260 1.1 cgd struct conf_entry *first = NULL;
261 1.1 cgd struct conf_entry *working;
262 1.1 cgd struct passwd *pass;
263 1.1 cgd struct group *grp;
264 1.1 cgd
265 1.13 lukem working = NULL;
266 1.1 cgd if (strcmp(conf,"-"))
267 1.1 cgd f = fopen(conf,"r");
268 1.1 cgd else
269 1.1 cgd f = stdin;
270 1.1 cgd if (!f) {
271 1.1 cgd (void) fprintf(stderr,"%s: ",progname);
272 1.1 cgd perror(conf);
273 1.1 cgd exit(1);
274 1.1 cgd }
275 1.1 cgd while (fgets(line,BUFSIZ,f)) {
276 1.1 cgd if ((line[0]== '\n') || (line[0] == '#'))
277 1.1 cgd continue;
278 1.1 cgd errline = strdup(line);
279 1.1 cgd if (!first) {
280 1.1 cgd working = (struct conf_entry *) malloc(sizeof(struct conf_entry));
281 1.1 cgd first = working;
282 1.1 cgd } else {
283 1.1 cgd working->next = (struct conf_entry *) malloc(sizeof(struct conf_entry));
284 1.1 cgd working = working->next;
285 1.1 cgd }
286 1.1 cgd
287 1.1 cgd q = parse = missing_field(sob(line),errline);
288 1.1 cgd *(parse = son(line)) = '\0';
289 1.1 cgd working->log = strdup(q);
290 1.1 cgd
291 1.1 cgd q = parse = missing_field(sob(++parse),errline);
292 1.1 cgd *(parse = son(parse)) = '\0';
293 1.19 ad if ((group = strchr(q, ':')) != NULL || (group = strchr(q, '.')) != NULL) {
294 1.1 cgd *group++ = '\0';
295 1.1 cgd if (*q) {
296 1.1 cgd if (!(isnumber(q))) {
297 1.1 cgd if ((pass = getpwnam(q)) == NULL) {
298 1.1 cgd fprintf(stderr,
299 1.1 cgd "Error in config file; unknown user:\n");
300 1.1 cgd fputs(errline,stderr);
301 1.1 cgd exit(1);
302 1.1 cgd }
303 1.1 cgd working->uid = pass->pw_uid;
304 1.1 cgd } else
305 1.1 cgd working->uid = atoi(q);
306 1.1 cgd } else
307 1.1 cgd working->uid = NONE;
308 1.1 cgd
309 1.1 cgd q = group;
310 1.1 cgd if (*q) {
311 1.1 cgd if (!(isnumber(q))) {
312 1.1 cgd if ((grp = getgrnam(q)) == NULL) {
313 1.1 cgd fprintf(stderr,
314 1.1 cgd "Error in config file; unknown group:\n");
315 1.1 cgd fputs(errline,stderr);
316 1.1 cgd exit(1);
317 1.1 cgd }
318 1.1 cgd working->gid = grp->gr_gid;
319 1.1 cgd } else
320 1.1 cgd working->gid = atoi(q);
321 1.1 cgd } else
322 1.1 cgd working->gid = NONE;
323 1.1 cgd
324 1.1 cgd q = parse = missing_field(sob(++parse),errline);
325 1.1 cgd *(parse = son(parse)) = '\0';
326 1.1 cgd }
327 1.1 cgd else
328 1.1 cgd working->uid = working->gid = NONE;
329 1.1 cgd
330 1.1 cgd if (!sscanf(q,"%o",&working->permissions)) {
331 1.1 cgd fprintf(stderr,
332 1.1 cgd "Error in config file; bad permissions:\n");
333 1.1 cgd fputs(errline,stderr);
334 1.1 cgd exit(1);
335 1.1 cgd }
336 1.1 cgd
337 1.1 cgd q = parse = missing_field(sob(++parse),errline);
338 1.1 cgd *(parse = son(parse)) = '\0';
339 1.1 cgd if (!sscanf(q,"%d",&working->numlogs)) {
340 1.1 cgd fprintf(stderr,
341 1.1 cgd "Error in config file; bad number:\n");
342 1.1 cgd fputs(errline,stderr);
343 1.1 cgd exit(1);
344 1.1 cgd }
345 1.1 cgd
346 1.1 cgd q = parse = missing_field(sob(++parse),errline);
347 1.1 cgd *(parse = son(parse)) = '\0';
348 1.17 christos if (isdigit((unsigned char)*q))
349 1.1 cgd working->size = atoi(q);
350 1.1 cgd else
351 1.1 cgd working->size = -1;
352 1.1 cgd
353 1.1 cgd q = parse = missing_field(sob(++parse),errline);
354 1.1 cgd *(parse = son(parse)) = '\0';
355 1.17 christos if (isdigit((unsigned char)*q))
356 1.1 cgd working->hours = atoi(q);
357 1.1 cgd else
358 1.1 cgd working->hours = -1;
359 1.1 cgd
360 1.1 cgd q = parse = sob(++parse); /* Optional field */
361 1.21 ad prev = *(parse = son(parse));
362 1.21 ad *parse = '\0';
363 1.1 cgd working->flags = 0;
364 1.17 christos while (q && *q && !isspace((unsigned char)*q)) {
365 1.1 cgd if ((*q == 'Z') || (*q == 'z'))
366 1.1 cgd working->flags |= CE_COMPACT;
367 1.1 cgd else if ((*q == 'B') || (*q == 'b'))
368 1.1 cgd working->flags |= CE_BINARY;
369 1.21 ad else if ((*q == 'N') || (*q == 'n'))
370 1.21 ad working->flags |= CE_NOSIGNAL;
371 1.21 ad else if (*q != '-') {
372 1.1 cgd fprintf(stderr,
373 1.1 cgd "Illegal flag in config file -- %c\n",
374 1.1 cgd *q);
375 1.1 cgd exit(1);
376 1.1 cgd }
377 1.1 cgd q++;
378 1.1 cgd }
379 1.20 ad
380 1.21 ad if (prev != '\0' && (q = parse = sob(++parse)) != NULL &&
381 1.21 ad q[0] == '/') {
382 1.21 ad prev = *(parse = son(parse));
383 1.21 ad *parse++ = '\0';
384 1.21 ad working->pidfile = strdup(q);
385 1.21 ad } else {
386 1.21 ad working->pidfile = NULL;
387 1.21 ad prev = *parse;
388 1.21 ad }
389 1.21 ad
390 1.21 ad if (prev != '\0' && (q = parse = sob(parse)) != NULL &&
391 1.21 ad q[0] != '\0') {
392 1.20 ad *(parse = son(parse)) = '\0';
393 1.21 ad if ((working->signum = getsig(q)) < 0) {
394 1.21 ad fprintf(stderr,
395 1.21 ad "Illegal signal in config file -- %s\n",
396 1.21 ad q);
397 1.21 ad exit(1);
398 1.21 ad }
399 1.20 ad } else
400 1.21 ad working->signum = SIGHUP;
401 1.1 cgd
402 1.1 cgd free(errline);
403 1.1 cgd }
404 1.1 cgd if (working)
405 1.1 cgd working->next = (struct conf_entry *) NULL;
406 1.1 cgd (void) fclose(f);
407 1.1 cgd return(first);
408 1.1 cgd }
409 1.1 cgd
410 1.13 lukem char *
411 1.13 lukem missing_field(p,errline)
412 1.1 cgd char *p,*errline;
413 1.1 cgd {
414 1.1 cgd if (!p || !*p) {
415 1.1 cgd fprintf(stderr,"Missing field in config file:\n");
416 1.1 cgd fputs(errline,stderr);
417 1.1 cgd exit(1);
418 1.1 cgd }
419 1.1 cgd return(p);
420 1.1 cgd }
421 1.1 cgd
422 1.13 lukem void
423 1.21 ad dotrim(log,numdays,flags,perm,owner_uid,group_gid,pidfile,signum)
424 1.1 cgd char *log;
425 1.1 cgd int numdays;
426 1.1 cgd int flags;
427 1.1 cgd int perm;
428 1.1 cgd int owner_uid;
429 1.1 cgd int group_gid;
430 1.20 ad char *pidfile;
431 1.21 ad int signum;
432 1.1 cgd {
433 1.1 cgd char file1[128], file2[128];
434 1.1 cgd char zfile1[128], zfile2[128];
435 1.20 ad char line[BUFSIZ];
436 1.1 cgd int fd;
437 1.1 cgd struct stat st;
438 1.11 thorpej int ngen = numdays;
439 1.20 ad FILE *f;
440 1.20 ad pid_t pid;
441 1.1 cgd
442 1.1 cgd #ifdef _IBMR2
443 1.1 cgd /* AIX 3.1 has a broken fchown- if the owner_uid is -1, it will actually */
444 1.1 cgd /* change it to be owned by uid -1, instead of leaving it as is, as it is */
445 1.1 cgd /* supposed to. */
446 1.1 cgd if (owner_uid == -1)
447 1.1 cgd owner_uid = geteuid();
448 1.1 cgd #endif
449 1.1 cgd
450 1.20 ad if (pidfile != NULL && pidfile[0] != '\0') {
451 1.20 ad if ((f = fopen(pidfile,"r")) == NULL) {
452 1.20 ad (void) fprintf(stderr,"%s: ",progname);
453 1.20 ad perror(conf);
454 1.20 ad return;
455 1.20 ad }
456 1.20 ad
457 1.20 ad if (fgets(line,BUFSIZ,f))
458 1.20 ad pid = atoi(line);
459 1.20 ad if (f)
460 1.20 ad (void)fclose(f);
461 1.20 ad } else
462 1.20 ad pid = syslog_pid;
463 1.20 ad
464 1.1 cgd /* Remove oldest log */
465 1.1 cgd (void) sprintf(file1,"%s.%d",log,numdays);
466 1.1 cgd (void) strcpy(zfile1, file1);
467 1.3 cgd (void) strcat(zfile1, COMPRESS_POSTFIX);
468 1.1 cgd
469 1.1 cgd if (noaction) {
470 1.1 cgd printf("rm -f %s\n", file1);
471 1.1 cgd printf("rm -f %s\n", zfile1);
472 1.1 cgd } else {
473 1.1 cgd (void) unlink(file1);
474 1.1 cgd (void) unlink(zfile1);
475 1.1 cgd }
476 1.1 cgd
477 1.1 cgd /* Move down log files */
478 1.1 cgd while (numdays--) {
479 1.1 cgd (void) strcpy(file2,file1);
480 1.1 cgd (void) sprintf(file1,"%s.%d",log,numdays);
481 1.1 cgd (void) strcpy(zfile1, file1);
482 1.1 cgd (void) strcpy(zfile2, file2);
483 1.1 cgd if (lstat(file1, &st)) {
484 1.3 cgd (void) strcat(zfile1, COMPRESS_POSTFIX);
485 1.3 cgd (void) strcat(zfile2, COMPRESS_POSTFIX);
486 1.1 cgd if (lstat(zfile1, &st)) continue;
487 1.1 cgd }
488 1.1 cgd if (noaction) {
489 1.1 cgd printf("mv %s %s\n",zfile1,zfile2);
490 1.1 cgd printf("chmod %o %s\n", perm, zfile2);
491 1.1 cgd printf("chown %d.%d %s\n",
492 1.1 cgd owner_uid, group_gid, zfile2);
493 1.1 cgd } else {
494 1.1 cgd (void) rename(zfile1, zfile2);
495 1.1 cgd (void) chmod(zfile2, perm);
496 1.1 cgd (void) chown(zfile2, owner_uid, group_gid);
497 1.1 cgd }
498 1.1 cgd }
499 1.1 cgd if (!noaction && !(flags & CE_BINARY))
500 1.1 cgd (void) log_trim(log); /* Report the trimming to the old log */
501 1.1 cgd
502 1.17 christos if (ngen == 0) {
503 1.11 thorpej if (noaction)
504 1.11 thorpej printf("rm %s\n",log);
505 1.11 thorpej else
506 1.11 thorpej (void) unlink(log);
507 1.17 christos } else
508 1.11 thorpej if (noaction)
509 1.11 thorpej printf("mv %s to %s\n",log,file1);
510 1.11 thorpej else
511 1.11 thorpej (void) rename(log,file1);
512 1.11 thorpej
513 1.11 thorpej if (noaction)
514 1.1 cgd printf("Start new log...");
515 1.1 cgd else {
516 1.1 cgd fd = creat(log,perm);
517 1.1 cgd if (fd < 0) {
518 1.1 cgd perror("can't start new log");
519 1.1 cgd exit(1);
520 1.1 cgd }
521 1.1 cgd if (fchown(fd, owner_uid, group_gid)) {
522 1.1 cgd perror("can't chmod new log file");
523 1.1 cgd exit(1);
524 1.1 cgd }
525 1.1 cgd (void) close(fd);
526 1.1 cgd if (!(flags & CE_BINARY))
527 1.1 cgd if (log_trim(log)) { /* Add status message */
528 1.1 cgd perror("can't add status message to log");
529 1.1 cgd exit(1);
530 1.1 cgd }
531 1.1 cgd }
532 1.1 cgd if (noaction)
533 1.1 cgd printf("chmod %o %s...",perm,log);
534 1.1 cgd else
535 1.1 cgd (void) chmod(log,perm);
536 1.21 ad
537 1.21 ad if ((flags & CE_NOSIGNAL) == 0) {
538 1.21 ad if (noaction)
539 1.21 ad printf("kill -HUP %d\n",pid);
540 1.21 ad else if (pid < MIN_PID || pid > MAX_PID) {
541 1.21 ad fprintf(stderr,"%s: preposterous process number: %d\n",
542 1.21 ad progname, pid);
543 1.21 ad } else if (kill(pid, signum)) {
544 1.21 ad fprintf(stderr,"%s: ", progname);
545 1.21 ad perror("warning - could not restart daemon");
546 1.21 ad }
547 1.21 ad }
548 1.21 ad
549 1.21 ad if ((flags & CE_COMPACT) != 0) {
550 1.1 cgd if (noaction)
551 1.1 cgd printf("Compress %s.0\n",log);
552 1.1 cgd else
553 1.1 cgd compress_log(log);
554 1.1 cgd }
555 1.1 cgd }
556 1.1 cgd
557 1.1 cgd /* Log the fact that the logs were turned over */
558 1.13 lukem int
559 1.1 cgd log_trim(log)
560 1.1 cgd char *log;
561 1.1 cgd {
562 1.1 cgd FILE *f;
563 1.1 cgd if ((f = fopen(log,"a")) == NULL)
564 1.1 cgd return(-1);
565 1.17 christos fprintf(f,"%s %s newsyslog[%ld]: logfile turned over\n",
566 1.17 christos daytime, hostname, (u_long)getpid());
567 1.1 cgd if (fclose(f) == EOF) {
568 1.18 soren perror("log_trim: fclose");
569 1.1 cgd exit(1);
570 1.1 cgd }
571 1.1 cgd return(0);
572 1.1 cgd }
573 1.1 cgd
574 1.21 ad /* Fork off compress/gzip to compress the old log file */
575 1.13 lukem void
576 1.1 cgd compress_log(log)
577 1.1 cgd char *log;
578 1.1 cgd {
579 1.1 cgd int pid;
580 1.1 cgd char tmp[128];
581 1.1 cgd
582 1.1 cgd pid = fork();
583 1.1 cgd (void) sprintf(tmp,"%s.0",log);
584 1.1 cgd if (pid < 0) {
585 1.1 cgd fprintf(stderr,"%s: ",progname);
586 1.1 cgd perror("fork");
587 1.1 cgd exit(1);
588 1.1 cgd } else if (!pid) {
589 1.1 cgd (void) execl(COMPRESS,"compress","-f",tmp,0);
590 1.1 cgd fprintf(stderr,"%s: ",progname);
591 1.1 cgd perror(COMPRESS);
592 1.1 cgd exit(1);
593 1.1 cgd }
594 1.1 cgd }
595 1.1 cgd
596 1.1 cgd /* Return size in kilobytes of a file */
597 1.13 lukem int
598 1.13 lukem sizefile(file)
599 1.1 cgd char *file;
600 1.1 cgd {
601 1.1 cgd struct stat sb;
602 1.1 cgd
603 1.1 cgd if (stat(file,&sb) < 0)
604 1.1 cgd return(-1);
605 1.1 cgd return(kbytes(dbtob(sb.st_blocks)));
606 1.1 cgd }
607 1.1 cgd
608 1.1 cgd /* Return the age of old log file (file.0) */
609 1.13 lukem int
610 1.13 lukem age_old_log(file)
611 1.1 cgd char *file;
612 1.1 cgd {
613 1.1 cgd struct stat sb;
614 1.7 pk char tmp[MAXPATHLEN+3];
615 1.1 cgd
616 1.1 cgd (void) strcpy(tmp,file);
617 1.1 cgd if (stat(strcat(tmp,".0"),&sb) < 0)
618 1.3 cgd if (stat(strcat(tmp,COMPRESS_POSTFIX), &sb) < 0)
619 1.1 cgd return(-1);
620 1.1 cgd return( (int) (timenow - sb.st_mtime + 1800) / 3600);
621 1.1 cgd }
622 1.1 cgd
623 1.1 cgd /* Skip Over Blanks */
624 1.1 cgd char *sob(p)
625 1.13 lukem char *p;
626 1.1 cgd {
627 1.17 christos while (p && *p && isspace((unsigned char)*p))
628 1.1 cgd p++;
629 1.1 cgd return(p);
630 1.1 cgd }
631 1.1 cgd
632 1.1 cgd /* Skip Over Non-Blanks */
633 1.13 lukem char *
634 1.13 lukem son(p)
635 1.13 lukem char *p;
636 1.1 cgd {
637 1.17 christos while (p && *p && !isspace((unsigned char)*p))
638 1.1 cgd p++;
639 1.1 cgd return(p);
640 1.1 cgd }
641 1.1 cgd
642 1.1 cgd
643 1.1 cgd /* Check if string is actually a number */
644 1.1 cgd
645 1.13 lukem int
646 1.1 cgd isnumber(string)
647 1.13 lukem char *string;
648 1.1 cgd {
649 1.1 cgd while (*string != '\0') {
650 1.1 cgd if (*string < '0' || *string > '9') return(0);
651 1.1 cgd string++;
652 1.1 cgd }
653 1.1 cgd return(1);
654 1.21 ad }
655 1.21 ad
656 1.21 ad int
657 1.21 ad getsig(sig)
658 1.21 ad char *sig;
659 1.21 ad {
660 1.21 ad int n;
661 1.21 ad
662 1.21 ad if (isnumber(sig)) {
663 1.21 ad n = strtol(sig, &sig, 0);
664 1.21 ad if ((unsigned)n >= NSIG)
665 1.21 ad return (-1);
666 1.21 ad return (n);
667 1.21 ad }
668 1.21 ad
669 1.21 ad if (!strncasecmp(sig, "sig", 3))
670 1.21 ad sig += 3;
671 1.21 ad for (n = 1; n < NSIG; n++) {
672 1.21 ad if (!strcasecmp(sys_signame[n], sig))
673 1.21 ad return (n);
674 1.21 ad }
675 1.21 ad return (-1);
676 1.1 cgd }
677