184
450
char * compext = "";
185
451
char * fileext = "";
186
452
int hasErrors = 0;
190
logState * state = NULL;
193
457
mode_t createMode;
196
460
char * firstRotated;
197
462
int rotateCount = log->rotateCount ? log->rotateCount : 1;
199
/* Logs with rotateCounts of 0 are rotated to .1, then removed. This
463
int logStart = (log->logStart == -1) ? 1 : log->logStart;
465
if (!state->doRotate) return 0;
467
/* Logs with rotateCounts of 0 are rotated once, then removed. This
200
468
lets scripts run properly, and everything gets mailed properly. */
202
message(MESS_DEBUG, "rotating file %s\n", log->files[logNum]);
470
message(MESS_DEBUG, "rotating log %s, log->rotateCount is %d\n", log->files[logNum], log->rotateCount);
204
472
if (log->flags & LOG_FLAG_COMPRESS) compext = log->compress_ext;
206
if (stat(log->files[logNum], &sb)) {
207
if ((log->flags & LOG_FLAG_MISSINGOK) && (errno == ENOENT)) {
208
message(MESS_DEBUG, "file %s does not exist -- skipping\n",
212
fprintf(errorFile, "stat of %s failed: %s\n", log->files[logNum],
474
state->lastRotated = now;
477
if (log->oldDir[0] != '/') {
478
char *ld = ourDirName(log->files[logNum]);
479
dirName = malloc(strlen(ld) + strlen(log->oldDir) + 2);
480
sprintf(dirName, "%s/%s", ld, log->oldDir);
483
dirName = strdup(log->oldDir);
485
dirName = ourDirName(log->files[logNum]);
487
baseName = strdup(ourBaseName(log->files[logNum]));
489
alloc_size = strlen(dirName) + strlen(baseName) +
490
strlen(log->files[logNum]) + strlen(fileext) +
491
strlen(compext) + 10;
493
oldName = alloca(alloc_size);
494
newName = alloca(alloc_size);
495
disposeName = alloca(alloc_size);
497
if (log->extension &&
498
strncmp(&baseName[strlen(baseName)-strlen(log->extension)],
499
log->extension, strlen(log->extension)) == 0) {
502
fileext = log->extension;
503
tempstr = calloc(strlen(baseName)-strlen(log->extension)+1, sizeof(char));
504
strncat(tempstr, baseName,
505
strlen(baseName)-strlen(log->extension));
510
/* First compress the previous log when necessary */
511
if (log->flags & LOG_FLAG_COMPRESS &&
512
log->flags & LOG_FLAG_DELAYCOMPRESS) {
515
sprintf(oldName, "%s/%s.%d%s", dirName, baseName, logStart, fileext);
516
if (stat(oldName, &sbprev)) {
517
message(MESS_DEBUG, "previous log %s does not exist\n",
520
hasErrors = compressLogFile(oldName, log);
524
sprintf(oldName, "%s/%s.%d%s%s", dirName, baseName,
525
logStart + rotateCount, fileext, compext);
526
strcpy(newName, oldName);
528
strcpy(disposeName, oldName);
530
firstRotated = alloca(strlen(dirName) + strlen(baseName) +
531
strlen(fileext) + strlen(compext) + 30);
532
sprintf(firstRotated, "%s/%s.%d%s%s", dirName, baseName,
534
(log->flags & LOG_FLAG_DELAYCOMPRESS) ? "" : compext);
537
if ((selinux_enabled=(is_selinux_enabled()>0))) {
538
security_context_t oldContext=NULL;
539
if (getfilecon(log->files[logNum], &oldContext)>0) {
540
if (getfscreatecon(&prev_context) < 0) {
541
message(MESS_ERROR, "error getting default context: %s\n",
546
if (setfscreatecon(oldContext) < 0) {
547
message(MESS_ERROR, "error setting file context %s to %s: %s\n",
548
log->files[logNum], oldContext,strerror(errno));
554
message(MESS_ERROR, "error getting file context %s: %s\n",
213
556
strerror(errno));
561
for (i = rotateCount + logStart - 1; (i >= 0) && !hasErrors; i--) {
565
sprintf(oldName, "%s/%s.%d%s%s", dirName, baseName, i,
568
message(MESS_DEBUG, "renaming %s to %s (rotatecount %d, logstart %d, i %d), \n", oldName, newName,
569
rotateCount, logStart, i);
571
if (!debug && rename(oldName, newName)) {
572
if (errno == ENOENT) {
573
message(MESS_DEBUG, "old log %s does not exist\n",
576
message(MESS_ERROR, "error renaming %s to %s: %s\n",
577
oldName, newName, strerror(errno));
585
/* note: the gzip extension is *not* used here! */
586
sprintf(finalName, "%s/%s.%d%s", dirName, baseName, logStart, fileext);
588
/* if the last rotation doesn't exist, that's okay */
589
if (!debug && access(disposeName, F_OK)) {
590
message(MESS_DEBUG, "log %s doesn't exist -- won't try to "
591
"dispose of it\n", disposeName);
217
598
if (!hasErrors) {
218
state = findState(log->files[logNum], statesPtr, numStatesPtr);
220
if (log->criterium == ROT_SIZE) {
221
doRotate = (sb.st_size >= log->threshhold);
223
else if (log->criterium == ROT_FORCE) {
224
/* user forced rotation of logs from command line */
226
} else if (state->lastRotated.tm_year > now.tm_year ||
227
(state->lastRotated.tm_year == now.tm_year &&
228
(state->lastRotated.tm_mon > now.tm_mon ||
229
(state->lastRotated.tm_mon == now.tm_mon &&
230
state->lastRotated.tm_mday > now.tm_mday)
235
"file %s last rotated in the future -- rotation forced\n",
238
} else if (state->lastRotated.tm_year != now.tm_year ||
239
state->lastRotated.tm_mon != now.tm_mon ||
240
state->lastRotated.tm_mday != now.tm_mday) {
241
switch (log->criterium) {
244
1) the current weekday is before the weekday of the
246
2) more then a week has passed since the last
249
doRotate = ((now.tm_wday < state->lastRotated.tm_wday) ||
250
((mktime(&now) - mktime(&state->lastRotated)) >
254
/* rotate if the logs haven't been rotated this month or
256
doRotate = ((now.tm_mon != state->lastRotated.tm_mon) ||
257
(now.tm_year != state->lastRotated.tm_year));
260
/* FIXME: only days=1 is implemented!! */
273
/* The notifempty flag overrides the normal criteria */
274
if (!(log->flags & LOG_FLAG_IFEMPTY) && !sb.st_size)
277
if (!hasErrors && doRotate) {
278
message(MESS_DEBUG, "log needs rotating\n");
280
state->lastRotated = now;
283
dirName = strdup(log->oldDir);
285
dirName = ourDirName(log->files[logNum]);
286
baseName = strdup(ourBaseName(log->files[logNum]));
288
oldName = alloca(strlen(dirName) + strlen(baseName) +
289
strlen(log->files[logNum]) + 10);
290
newName = alloca(strlen(dirName) + strlen(baseName) +
291
strlen(log->files[logNum]) + 10);
292
disposeName = alloca(strlen(dirName) + strlen(baseName) +
293
strlen(log->files[logNum]) + 10);
297
fileext = log->extension;
299
if (log->extension &&
300
strncmp(&baseName[strlen(baseName)-strlen(log->extension)],
301
log->extension, strlen(log->extension)) == 0) {
303
tempstr = calloc(strlen(baseName)-strlen(log->extension)+1, sizeof(char));
304
strncat(tempstr, baseName,
305
strlen(baseName)-strlen(log->extension));
310
/* First compress the previous log when necessary */
311
if (log->flags & LOG_FLAG_COMPRESS &&
312
log->flags & LOG_FLAG_DELAYCOMPRESS) {
315
sprintf(oldName, "%s/%s.1%s", dirName, baseName, fileext);
316
if (stat(oldName, &sbprev)) {
317
message(MESS_DEBUG, "previous log %s does not exist\n",
322
command = alloca(strlen(oldName) +
323
strlen(log->compress_prog) + 1 + strlen(log->compress_options) + 20);
324
sprintf(command, "%s %s '%s'", log->compress_prog, log->compress_options, oldName);
325
message(MESS_DEBUG, "compressing previous log with: %s\n",
327
if (!debug && system(command)) {
329
"failed to compress previous log %s\n", oldName);
335
sprintf(oldName, "%s/%s.%d%s%s", dirName, baseName,
336
rotateCount + 1, fileext, compext);
338
strcpy(disposeName, oldName);
340
firstRotated = alloca(strlen(dirName) + strlen(baseName) +
341
strlen(fileext) + strlen(compext) + 30);
342
sprintf(firstRotated, "%s/%s.1%s%s", dirName, baseName,
345
for (i = rotateCount; i && !hasErrors; i--) {
349
sprintf(oldName, "%s/%s.%d%s%s", dirName, baseName, i,
352
message(MESS_DEBUG, "renaming %s to %s\n", oldName, newName);
354
if (!debug && rename(oldName, newName)) {
355
if (errno == ENOENT) {
356
message(MESS_DEBUG, "old log %s does not exist\n",
359
fprintf(errorFile, "error renaming %s to %s: %s\n",
360
oldName, newName, strerror(errno));
368
/* note: the gzip extension is *not* used here! */
369
sprintf(finalName, "%s/%s.1%s", dirName, baseName, fileext);
371
/* if the last rotation doesn't exist, that's okay */
372
if (!debug && access(disposeName, F_OK)) {
373
message(MESS_DEBUG, "file %s doesn't exist -- won't try "
374
"dispose of it\n", disposeName);
382
if (log->pre && !(log->flags & LOG_FLAG_SHAREDSCRIPTS)) {
383
message(MESS_DEBUG, "running prerotate script\n");
384
if (runScript(log->files[logNum], log->pre)) {
385
fprintf(errorFile, "error running prerotate script --
386
leaving old log in place\n");
391
if (!(log->flags & LOG_FLAG_COPYTRUNCATE)) {
392
message(MESS_DEBUG, "renaming %s to %s\n", log->files[logNum],
599
if (log->pre && !(log->flags & LOG_FLAG_SHAREDSCRIPTS)) {
600
message(MESS_DEBUG, "running prerotate script\n");
601
if (runScript(log->files[logNum], log->pre)) {
602
message(MESS_ERROR, "error running prerotate script, "
603
"leaving old log in place\n");
608
if (!(log->flags & (LOG_FLAG_COPYTRUNCATE|LOG_FLAG_COPY))) {
609
message(MESS_DEBUG, "renaming %s to %s\n", log->files[logNum],
395
if (!debug && !hasErrors &&
396
rename(log->files[logNum], finalName)) {
397
fprintf(errorFile, "failed to rename %s to %s: %s\n",
612
if (!debug && !hasErrors &&
613
rename(log->files[logNum], finalName)) {
614
message(MESS_ERROR, "failed to rename %s to %s: %s\n",
398
615
log->files[logNum], finalName, strerror(errno));
402
if (!hasErrors && log->flags & LOG_FLAG_CREATE &&
403
!(log->flags & LOG_FLAG_COPYTRUNCATE)) {
404
if (log->createUid == NO_UID)
405
createUid = sb.st_uid;
407
createUid = log->createUid;
409
if (log->createGid == NO_GID)
410
createGid = sb.st_gid;
412
createGid = log->createGid;
414
if (log->createMode == NO_MODE)
415
createMode = sb.st_mode & 0777;
417
createMode = log->createMode;
419
message(MESS_DEBUG, "creating new log mode = 0%o uid = %d "
420
"gid = %d\n", createMode, createUid, createGid);
423
fd = open(log->files[logNum], O_CREAT | O_RDWR, createMode);
425
message(MESS_ERROR, "error creating %s: %s\n",
426
log->files[logNum], strerror(errno));
429
if (fchmod(fd, createMode)) {
430
message(MESS_ERROR, "error setting mode of "
431
"%s: %s\n", log->files[logNum],
435
if (fchown(fd, createUid, createGid)) {
436
message(MESS_ERROR, "error setting owner of "
437
"%s: %s\n", log->files[logNum],
618
if (!log->rotateCount) {
619
disposeName = alloca(strlen(dirName) + strlen(baseName) +
620
strlen(log->files[logNum]) + 10);
621
sprintf(disposeName, "%s%s", finalName, (log->compress_ext && (log->flags & LOG_FLAG_COMPRESS))?log->compress_ext:"");
622
message(MESS_DEBUG, "disposeName will be %s\n", disposeName);
626
if (!hasErrors && log->flags & LOG_FLAG_CREATE &&
627
!(log->flags & (LOG_FLAG_COPYTRUNCATE|LOG_FLAG_COPY))) {
628
if (log->createUid == NO_UID)
629
createUid = state->sb.st_uid;
631
createUid = log->createUid;
633
if (log->createGid == NO_GID)
634
createGid = state->sb.st_gid;
636
createGid = log->createGid;
638
if (log->createMode == NO_MODE)
639
createMode = state->sb.st_mode & 0777;
641
createMode = log->createMode;
643
message(MESS_DEBUG, "creating new log mode = 0%o uid = %d "
644
"gid = %d\n", (unsigned int)createMode, (int)createUid, (int)createGid);
647
fd = open(log->files[logNum], O_CREAT | O_RDWR, createMode);
649
message(MESS_ERROR, "error creating %s: %s\n",
650
log->files[logNum], strerror(errno));
653
if (fchmod(fd, (S_IRUSR | S_IWUSR) & createMode)) {
654
message(MESS_ERROR, "error setting mode of "
655
"%s: %s\n", log->files[logNum],
659
if (fchown(fd, createUid, createGid)) {
660
message(MESS_ERROR, "error setting owner of "
661
"%s: %s\n", log->files[logNum],
447
if (!hasErrors && log->flags & LOG_FLAG_COPYTRUNCATE) {
448
hasErrors = copyTruncate(log->files[logNum], finalName, &sb);
452
if (!hasErrors && log->post &&
453
!(log->flags & LOG_FLAG_SHAREDSCRIPTS)) {
454
message(MESS_DEBUG, "running postrotate script\n");
455
if (runScript(log->files[logNum], log->post)) {
456
fprintf(errorFile, "error running postrotate script\n");
461
if (!hasErrors && !log->rotateCount) {
462
message(MESS_DEBUG, "removing rotated log (rotateCount == 0)");
463
if (unlink(finalName)) {
464
fprintf(errorFile, "Failed to remove old log %s: %s\n",
465
finalName, strerror(errno));
470
if (!hasErrors && log->rotateCount &&
471
(log->flags & LOG_FLAG_COMPRESS) &&
472
!(log->flags & LOG_FLAG_DELAYCOMPRESS)) {
475
command = alloca(strlen(finalName) + strlen(log->compress_prog) + 1 + strlen(log->compress_options) + 20);
477
sprintf(command, "%s %s '%s'", log->compress_prog, log->compress_options, finalName);
478
message(MESS_DEBUG, "compressing new log with: %s\n", command);
479
if (!debug && system(command)) {
480
fprintf(errorFile, "failed to compress log %s\n",
486
if (!hasErrors && log->logAddress) {
490
if (log->flags & LOG_FLAG_MAILFIRST)
491
mailFilename = firstRotated;
493
mailFilename = disposeName;
496
command = alloca(strlen(mailFilename) + 100 +
497
strlen(log->uncompress_prog));
499
if ((log->flags & LOG_FLAG_COMPRESS) &&
500
!((log->flags & LOG_FLAG_DELAYCOMPRESS) &&
501
(log->flags & LOG_FLAG_MAILFIRST)))
502
sprintf(command, "%s < %s | %s '%s' %s",
503
log->uncompress_prog, mailFilename, mailCommand,
507
sprintf(command, "%s '%s' %s < %s", mailCommand,
508
mailFilename, log->logAddress, mailFilename);
510
message(MESS_DEBUG, "executing: \"%s\"\n", command);
512
if (!debug && system(command)) {
513
sprintf(newName, "%s.%d", log->files[logNum], getpid());
514
fprintf(errorFile, "Failed to mail %s to %s!\n",
515
mailFilename, log->logAddress);
522
if (!hasErrors && disposeName) {
523
message(MESS_DEBUG, "removing old log %s\n", disposeName);
525
if (!debug && unlink(disposeName)) {
526
fprintf(errorFile, "Failed to remove old log %s: %s\n",
527
disposeName, strerror(errno));
533
} else if (!doRotate) {
534
message(MESS_DEBUG, "log does not need rotating\n");
665
if (fchmod(fd, createMode)) {
666
message(MESS_ERROR, "error setting mode of "
667
"%s: %s\n", log->files[logNum],
677
if (!hasErrors && log->flags & (LOG_FLAG_COPYTRUNCATE|LOG_FLAG_COPY))
678
hasErrors = copyTruncate(log->files[logNum], finalName,
679
&state->sb, log->flags);
681
if (!hasErrors && log->post &&
682
!(log->flags & LOG_FLAG_SHAREDSCRIPTS)) {
683
message(MESS_DEBUG, "running postrotate script\n");
684
if (runScript(log->files[logNum], log->post)) {
685
message(MESS_ERROR, "error running postrotate script\n");
691
(log->flags & LOG_FLAG_COMPRESS) &&
692
!(log->flags & LOG_FLAG_DELAYCOMPRESS)) {
693
hasErrors = compressLogFile(finalName, log);
696
if (!hasErrors && log->logAddress) {
699
if (log->flags & LOG_FLAG_MAILFIRST)
700
mailFilename = firstRotated;
702
mailFilename = disposeName;
705
/* if the log is compressed (and we're not mailing a
706
file whose compression has been delayed), we need
708
if ((log->flags & LOG_FLAG_COMPRESS) &&
709
!((log->flags & LOG_FLAG_DELAYCOMPRESS) &&
710
(log->flags & LOG_FLAG_MAILFIRST))) {
711
if (mailLog(mailFilename, mailCommand,
712
log->uncompress_prog, log->logAddress,
716
if (mailLog(mailFilename, mailCommand, NULL,
717
log->logAddress, mailFilename))
723
if (!hasErrors && disposeName) {
724
message(MESS_DEBUG, "removing old log %s\n", disposeName);
726
if (!debug && unlink(disposeName)) {
727
message(MESS_ERROR, "Failed to remove old log %s: %s\n",
728
disposeName, strerror(errno));
735
if (selinux_enabled) {
736
setfscreatecon(prev_context);
737
if (prev_context!= NULL) {
738
freecon(prev_context);
537
743
return hasErrors;
540
int rotateLogSet(logInfo * log, logState ** statesPtr, int * numStatesPtr,
746
int rotateLogSet(logInfo * log, struct stateSet * sip, int force) {
543
748
int hasErrors = 0;
546
753
log->criterium = ROT_FORCE;
548
message(MESS_DEBUG, "rotating pattern: %s ", log->pattern);
755
message(MESS_DEBUG, "\nrotating pattern: %s ", log->pattern);
549
756
switch (log->criterium) {
551
758
message(MESS_DEBUG, "after %d days ", log->threshhold);
554
761
message(MESS_DEBUG, "weekly ");
557
764
message(MESS_DEBUG, "monthly ");
560
767
message(MESS_DEBUG, "%d bytes ", log->threshhold);
563
770
message(MESS_DEBUG, "forced from command line ");
567
774
if (log->rotateCount)
568
775
message(MESS_DEBUG, "(%d rotations)\n", log->rotateCount);
570
777
message(MESS_DEBUG, "(no old logs will be kept)\n");
573
message(MESS_DEBUG, "olddir is %s ", log->oldDir);
780
message(MESS_DEBUG, "olddir is %s, ", log->oldDir);
575
782
if (log->flags & LOG_FLAG_IFEMPTY)
576
message(MESS_DEBUG, "empty log files are rotated ");
783
message(MESS_DEBUG, "empty log files are rotated, ");
578
message(MESS_DEBUG, "empty log files are not rotated ");
785
message(MESS_DEBUG, "empty log files are not rotated, ");
580
787
if (log->logAddress) {
581
788
message(MESS_DEBUG, "old logs mailed to %s\n", log->logAddress);
583
790
message(MESS_DEBUG, "old logs are removed\n");
793
for (i = 0; i < log->numFiles; i++) {
794
hasErrors |= findNeedRotating(log, i, sip);
796
/* sure is a lot of findStating going on .. */
797
if ((findState(log->files[i], sip))->doRotate)
803
message(MESS_DEBUG, "not running first action script, "
804
"since no logs will be rotated\n");
806
message(MESS_DEBUG, "running first action script\n");
807
if (runScript(log->pattern, log->first)) {
808
message(MESS_ERROR, "error running first action script "
809
"for %s\n", log->pattern);
586
815
if (log->pre && (log->flags & LOG_FLAG_SHAREDSCRIPTS)) {
587
message(MESS_DEBUG, "running shared prerotate script\n");
588
if (runScript(log->pattern, log->pre)) {
589
fprintf(stderr, "error running shared prerotate script for %s--
590
leaving old logs in place\n", log->pattern);
817
message(MESS_DEBUG, "not running shared prerotate script, "
818
"since no logs will be rotated\n");
820
message(MESS_DEBUG, "running shared prerotate script\n");
821
if (runScript(log->pattern, log->pre)) {
822
message(MESS_ERROR, "error running shared prerotate script "
823
"for %s\n", log->pattern);
595
for (i = 0; i < log->numFiles; i++)
596
hasErrors |= rotateSingleLog(log, i, statesPtr, numStatesPtr,
829
/* should there be an if(!hasErrors) here? */
830
for (i = 0; i < log->numFiles; i++) {
831
state = findState(log->files[i], sip);
833
hasErrors |= rotateSingleLog(log, i, state);
599
836
if (log->post && (log->flags & LOG_FLAG_SHAREDSCRIPTS)) {
600
message(MESS_DEBUG, "running shared postrotate script\n");
601
if (runScript(log->pattern, log->post)) {
603
"error running shared postrotate script for %s\n", log->pattern);
838
message(MESS_DEBUG, "not running shared postrotate script, "
839
"since no logs were rotated\n");
841
message(MESS_DEBUG, "running shared postrotate script\n");
842
if (runScript(log->pattern, log->post)) {
843
message(MESS_ERROR, "error running shared postrotate script "
844
"for %s\n", log->pattern);
852
message(MESS_DEBUG, "not running last action script, "
853
"since no logs will be rotated\n");
855
message(MESS_DEBUG, "running last action script\n");
856
if (runScript(log->pattern, log->last)) {
857
message(MESS_ERROR, "error running last action script "
858
"for %s\n", log->pattern);
608
864
return hasErrors;
611
static int writeState(char * stateFilename, logState * states,
867
static int writeState(char * stateFilename, struct stateSet si) {
617
872
f = fopen(stateFilename, "w");
619
875
message(MESS_ERROR, "error creating state file %s: %s\n",
620
stateFilename, strerror(errno));
876
stateFilename, strerror(errno));
624
880
fprintf(f, "logrotate state -- version 2\n");
626
for (i = 0; i < numStates; i++) {
882
for (i = 0; i < si.numStates; i++) {
628
for (chptr = states[i].fn; *chptr; chptr++) {
884
for (chptr = si.states[i].fn; *chptr; chptr++) {
629
885
switch (*chptr) {
636
890
fputc(*chptr, f);
640
894
fprintf(f, " %d-%d-%d\n",
641
states[i].lastRotated.tm_year + 1900,
642
states[i].lastRotated.tm_mon + 1,
643
states[i].lastRotated.tm_mday);
895
si.states[i].lastRotated.tm_year + 1900,
896
si.states[i].lastRotated.tm_mon + 1,
897
si.states[i].lastRotated.tm_mday);
651
static int readState(char * stateFilename, logState ** statesPtr,
652
int * numStatesPtr) {
905
static int readState(char * stateFilename, struct stateSet * sip) {
655
908
const char ** argv;