22
#include "basenames.h"
24
#include "logrotate.h"
26
#if !defined(GLOB_ABORTED) && defined(GLOB_ABEND)
27
#define GLOB_ABORTED GLOB_ABEND
30
#define REALLOC_STEP 10
32
#if defined(SunOS) && !defined(isblank)
33
#define isblank(c) ( (c) == ' ' || (c) == '\t' ) ? 1 : 0
36
static char *defTabooExts[] = { ".rpmsave", ".rpmorig", "~", ",v",
37
".disabled", ".dpkg-old", ".dpkg-dist", ".dpkg-new", ".cfsaved",
38
".rpmnew", ".swp", ".cfsaved", ".rhn-cfg-tmp-*"
40
static int defTabooCount = sizeof(defTabooExts) / sizeof(char *);
42
/* I shouldn't use globals here :-( */
43
static char **tabooExts = NULL;
46
static int readConfigFile(const char *configFile, struct logInfo *defConfig);
47
static int globerr(const char *pathname, int theerr);
49
static int isolateValue(const char *fileName, int lineNum, char *key,
50
char **startPtr, char **endPtr)
52
char *chptr = *startPtr;
54
while (isblank(*chptr))
58
while (*chptr && isblank(*chptr))
63
message(MESS_ERROR, "%s:%d argument expected after %s\n",
64
fileName, lineNum, key);
70
while (*chptr != '\n')
73
while (isspace(*chptr))
81
static char *readPath(const char *configFile, int lineNum, char *key,
86
char *start = *startPtr;
92
if (!isolateValue(configFile, lineNum, key, &start, &endtag)) {
93
oldchar = *endtag, *endtag = '\0';
97
while( (len = mbrtowc(&pwc, chptr, strlen(chptr), NULL)) != 0 ) {
98
if( len == (size_t)(-1) || len == (size_t)(-2) || !iswprint(pwc) || iswblank(pwc) ) {
99
message(MESS_ERROR, "%s:%d bad %s path %s\n",
100
configFile, lineNum, key, start);
107
while (*chptr && isprint(*chptr) && *chptr != ' ')
110
message(MESS_ERROR, "%s:%d bad %s path %s\n",
111
configFile, lineNum, key, start);
116
path = strdup(start);
119
*endtag = oldchar, start = endtag;
128
static char *readAddress(const char *configFile, int lineNum, char *key,
132
char *endtag, *chptr;
133
char *start = *startPtr;
136
if (!isolateValue(configFile, lineNum, key, &start, &endtag)) {
137
oldchar = *endtag, *endtag = '\0';
140
while (*chptr && isprint(*chptr) && *chptr != ' ')
143
message(MESS_ERROR, "%s:%d bad %s address %s\n",
144
configFile, lineNum, key, start);
148
address = strdup(start);
150
*endtag = oldchar, start = endtag;
159
static int checkFile(const char *fname)
162
char pattern[PATH_MAX];
164
/* Check if fname is '.' or '..'; if so, return false */
165
if (fname[0] == '.' && (!fname[1] || (fname[1] == '.' && !fname[2])))
168
/* Check if fname is ending in a taboo-extension; if so, return false */
169
for (i = 0; i < tabooCount; i++) {
170
snprintf(pattern, sizeof(pattern), "*%s", tabooExts[i]);
171
if (!fnmatch(pattern, fname, 0))
173
message(MESS_DEBUG, "Ignoring %s, because of %s ending\n",
174
fname, tabooExts[i]);
179
/* All checks have been passed; return true */
183
/* Used by qsort to sort filelist */
184
static int compar(const void *p, const void *q)
186
return strcoll(*((char **) p), *((char **) q));
189
/* Free memory blocks pointed to by pointers in a 2d array and the array itself */
190
static void free_2d_array(char **array, int lines_count)
193
for (i = 0; i < lines_count; ++i)
198
static void copyLogInfo(struct logInfo *to, struct logInfo *from)
200
memset(to, 0, sizeof(*to));
202
to->oldDir = strdup(from->oldDir);
203
to->criterium = from->criterium;
204
to->threshhold = from->threshhold;
205
to->minsize = from->minsize;
206
to->rotateCount = from->rotateCount;
207
to->rotateAge = from->rotateAge;
208
to->logStart = from->logStart;
210
to->pre = strdup(from->pre);
212
to->post = strdup(from->post);
214
to->first = strdup(from->first);
216
to->last = strdup(from->last);
217
if (from->logAddress)
218
to->logAddress = strdup(from->logAddress);
220
to->extension = strdup(from->extension);
221
if (from->compress_prog)
222
to->compress_prog = strdup(from->compress_prog);
223
if (from->uncompress_prog)
224
to->uncompress_prog = strdup(from->uncompress_prog);
225
if (from->compress_ext)
226
to->compress_ext = strdup(from->compress_ext);
227
to->flags = from->flags;
228
to->createMode = from->createMode;
229
to->createUid = from->createUid;
230
to->createGid = from->createGid;
231
if (from->compress_options_count) {
232
poptDupArgv(from->compress_options_count, from->compress_options_list,
233
&to->compress_options_count, &to->compress_options_list);
235
if (from->dateformat)
236
to->dateformat = strdup(from->dateformat);
239
static void freeLogInfo(struct logInfo *log)
242
free_2d_array(log->files, log->numFiles);
248
free(log->logAddress);
249
free(log->extension);
250
free(log->compress_prog);
251
free(log->uncompress_prog);
252
free(log->compress_ext);
253
free(log->compress_options_list);
254
free(log->dateformat);
257
static struct logInfo *newLogInfo(struct logInfo *template)
261
if ((new = malloc(sizeof(*new))) == NULL)
264
copyLogInfo(new, template);
265
TAILQ_INSERT_TAIL(&logs, new, list);
271
static void removeLogInfo(struct logInfo *log)
277
TAILQ_REMOVE(&logs, log, list);
281
static void freeTailLogs(int num)
283
message(MESS_DEBUG, "removing last %d log configs\n", num);
286
removeLogInfo(*(logs.tqh_last));
289
static int readConfigPath(const char *path, struct logInfo *defConfig)
292
int here, oldnumlogs, result = 1;
293
struct logInfo defConfigBackup;
295
if (stat(path, &sb)) {
296
message(MESS_ERROR, "cannot stat %s: %s\n", path, strerror(errno));
300
if (S_ISDIR(sb.st_mode)) {
301
char **namelist, **p;
306
here = open(".", O_RDONLY);
308
message(MESS_ERROR, "cannot open current directory: %s\n",
313
if ((dirp = opendir(path)) == NULL) {
314
message(MESS_ERROR, "cannot open directory %s: %s\n", path,
321
while ((dp = readdir(dirp)) != NULL) {
322
if (checkFile(dp->d_name)) {
323
/* Realloc memory for namelist array if necessary */
324
if (files_count % REALLOC_STEP == 0) {
325
p = (char **) realloc(namelist,
327
REALLOC_STEP) * sizeof(char *));
330
memset(namelist + files_count, '\0',
331
REALLOC_STEP * sizeof(char *));
333
free_2d_array(namelist, files_count);
336
message(MESS_ERROR, "cannot realloc: %s\n",
341
/* Alloc memory for file name */
342
if ((namelist[files_count] =
343
(char *) malloc(strlen(dp->d_name) + 1))) {
344
strcpy(namelist[files_count], dp->d_name);
347
free_2d_array(namelist, files_count);
350
message(MESS_ERROR, "cannot realloc: %s\n",
358
if (files_count > 0) {
359
qsort(namelist, files_count, sizeof(char *), compar);
366
message(MESS_ERROR, "error in chdir(\"%s\"): %s\n", path,
369
free_2d_array(namelist, files_count);
373
for (i = 0; i < files_count; ++i) {
374
assert(namelist[i] != NULL);
375
oldnumlogs = numLogs;
376
copyLogInfo(&defConfigBackup, defConfig);
377
if (readConfigFile(namelist[i], defConfig)) {
378
message(MESS_ERROR, "found error in file %s, skipping\n", namelist[i]);
379
freeTailLogs(numLogs - oldnumlogs);
380
freeLogInfo(defConfig);
381
copyLogInfo(defConfig, &defConfigBackup);
382
freeLogInfo(&defConfigBackup);
387
freeLogInfo(&defConfigBackup);
390
if (fchdir(here) < 0) {
391
message(MESS_ERROR, "could not change directory to '.'");
394
free_2d_array(namelist, files_count);
396
oldnumlogs = numLogs;
397
copyLogInfo(&defConfigBackup, defConfig);
398
if (readConfigFile(path, defConfig)) {
399
freeTailLogs(numLogs - oldnumlogs);
400
freeLogInfo(defConfig);
401
copyLogInfo(defConfig, &defConfigBackup);
405
freeLogInfo(&defConfigBackup);
411
int readAllConfigPaths(const char **paths)
415
struct logInfo defConfig = {
420
.criterium = ROT_SIZE,
421
.threshhold = 1024 * 1024,
432
.compress_prog = NULL,
433
.uncompress_prog = NULL,
434
.compress_ext = NULL,
436
.flags = LOG_FLAG_IFEMPTY,
438
.createMode = NO_MODE,
441
.compress_options_list = NULL,
442
.compress_options_count = 0
445
tabooExts = malloc(sizeof(*tabooExts) * defTabooCount);
446
for (i = 0; i < defTabooCount; i++) {
447
if ((tabooExts[i] = (char *) malloc(strlen(defTabooExts[i]) + 1))) {
448
strcpy(tabooExts[i], defTabooExts[i]);
451
free_2d_array(tabooExts, tabooCount);
452
message(MESS_ERROR, "cannot malloc: %s\n", strerror(errno));
457
for (file = paths; *file; file++) {
458
if (readConfigPath(*file, &defConfig)) {
463
free_2d_array(tabooExts, tabooCount);
464
freeLogInfo(&defConfig);
468
static int globerr(const char *pathname, int theerr)
470
message(MESS_ERROR, "error accessing %s: %s\n", pathname,
473
/* We want the glob operation to abort on error, so return 1 */
477
#define freeLogItem(what) \
479
free(newlog->what); \
480
newlog->what = NULL; \
482
#define MAX_NESTING 16U
484
static int readConfigFile(const char *configFile, struct logInfo *defConfig)
493
char *scriptStart = NULL;
494
char **scriptDest = NULL;
495
struct logInfo *newlog = defConfig;
501
char createOwner[200], createGroup[200];
509
static unsigned recursion_depth = 0U;
511
/* FIXME: createOwner and createGroup probably shouldn't be fixed
512
length arrays -- of course, if we aren't run setuid it doesn't
515
fd = open(configFile, O_RDONLY);
517
message(MESS_ERROR, "failed to open config file %s: %s\n",
518
configFile, strerror(errno));
522
if (fstat(fd, &sb)) {
523
message(MESS_ERROR, "fstat of %s failed: %s\n", configFile,
528
if (!S_ISREG(sb.st_mode)) {
530
"Ignoring %s because it's not a regular file.\n",
538
buf = alloca(length + 2);
540
message(MESS_ERROR, "alloca() of %d bytes failed\n", (int) length);
545
if (read(fd, buf, length) != length) {
546
message(MESS_ERROR, "failed to read %s: %s\n", configFile,
554
/* knowing the buffer ends with a newline makes things (a bit) cleaner */
555
buf[length + 1] = '\0';
558
message(MESS_DEBUG, "reading config file %s\n", configFile);
563
assert(newlog != defConfig);
565
message(MESS_ERROR, "found error in %s, skipping\n",
566
newlog->pattern ? newlog->pattern : "log config");
568
while (*start != '}') {
570
message(MESS_ERROR, "%s:%d } expected \n",
571
configFile, lineNum);
573
} else if (*start == '\n') {
584
while (isblank(*start) && (*start))
587
while (*start != '\n')
591
if (*start == '\n') {
598
if (!strncmp(start, "endscript", 9)) {
600
while (isblank(*chptr))
602
if (*chptr == '\n') {
604
while (*endtag != '\n')
607
*scriptDest = malloc(endtag - scriptStart + 1);
608
strncpy(*scriptDest, scriptStart,
609
endtag - scriptStart);
610
(*scriptDest)[endtag - scriptStart] = '\0';
620
while (*start != '\n')
625
} else if (isalpha(*start)) {
627
while (isalpha(*endtag))
632
if (!strcmp(start, "compress")) {
633
newlog->flags |= LOG_FLAG_COMPRESS;
635
*endtag = oldchar, start = endtag;
636
} else if (!strcmp(start, "nocompress")) {
637
newlog->flags &= ~LOG_FLAG_COMPRESS;
639
*endtag = oldchar, start = endtag;
640
} else if (!strcmp(start, "delaycompress")) {
641
newlog->flags |= LOG_FLAG_DELAYCOMPRESS;
643
*endtag = oldchar, start = endtag;
644
} else if (!strcmp(start, "nodelaycompress")) {
645
newlog->flags &= ~LOG_FLAG_DELAYCOMPRESS;
647
*endtag = oldchar, start = endtag;
648
} else if (!strcmp(start, "shred")) {
649
newlog->flags |= LOG_FLAG_SHRED;
651
*endtag = oldchar, start = endtag;
652
} else if (!strcmp(start, "noshred")) {
653
newlog->flags &= ~LOG_FLAG_SHRED;
655
*endtag = oldchar, start = endtag;
656
} else if (!strcmp(start, "sharedscripts")) {
657
newlog->flags |= LOG_FLAG_SHAREDSCRIPTS;
659
*endtag = oldchar, start = endtag;
660
} else if (!strcmp(start, "nosharedscripts")) {
661
newlog->flags &= ~LOG_FLAG_SHAREDSCRIPTS;
663
*endtag = oldchar, start = endtag;
664
} else if (!strcmp(start, "copytruncate")) {
665
newlog->flags |= LOG_FLAG_COPYTRUNCATE;
667
*endtag = oldchar, start = endtag;
668
} else if (!strcmp(start, "nocopytruncate")) {
669
newlog->flags &= ~LOG_FLAG_COPYTRUNCATE;
671
*endtag = oldchar, start = endtag;
672
} else if (!strcmp(start, "copy")) {
673
newlog->flags |= LOG_FLAG_COPY;
675
*endtag = oldchar, start = endtag;
676
} else if (!strcmp(start, "nocopy")) {
677
newlog->flags &= ~LOG_FLAG_COPY;
679
*endtag = oldchar, start = endtag;
680
} else if (!strcmp(start, "ifempty")) {
681
newlog->flags |= LOG_FLAG_IFEMPTY;
683
*endtag = oldchar, start = endtag;
684
} else if (!strcmp(start, "notifempty")) {
685
newlog->flags &= ~LOG_FLAG_IFEMPTY;
687
*endtag = oldchar, start = endtag;
688
} else if (!strcmp(start, "dateext")) {
689
newlog->flags |= LOG_FLAG_DATEEXT;
691
*endtag = oldchar, start = endtag;
692
} else if (!strcmp(start, "nodateext")) {
693
newlog->flags &= ~LOG_FLAG_DATEEXT;
695
*endtag = oldchar, start = endtag;
696
} else if (!strcmp(start, "dateformat")) {
697
*endtag = oldchar, start = endtag;
700
while (*endtag != '\n')
702
while (isspace(*endtag))
705
oldchar = *endtag, *endtag = '\0';
707
freeLogItem(dateformat);
708
newlog->dateformat = strdup(start);
710
*endtag = oldchar, start = endtag;
711
} else if (!strcmp(start, "noolddir")) {
712
newlog->oldDir = NULL;
714
*endtag = oldchar, start = endtag;
715
} else if (!strcmp(start, "mailfirst")) {
716
newlog->flags |= LOG_FLAG_MAILFIRST;
718
*endtag = oldchar, start = endtag;
719
} else if (!strcmp(start, "maillast")) {
720
newlog->flags &= ~LOG_FLAG_MAILFIRST;
722
*endtag = oldchar, start = endtag;
723
} else if (!strcmp(start, "create")) {
724
*endtag = oldchar, start = endtag;
727
while (*endtag != '\n')
729
while (isspace(*endtag))
732
oldchar = *endtag, *endtag = '\0';
734
rc = sscanf(start, "%o %s %s%c", &createMode,
735
createOwner, createGroup, &foo);
737
message(MESS_ERROR, "%s:%d extra arguments for "
738
"create\n", configFile, lineNum);
739
if (newlog != defConfig) {
740
*endtag = oldchar, start = endtag;
749
newlog->createMode = createMode;
752
pw = getpwnam(createOwner);
754
message(MESS_ERROR, "%s:%d unknown user '%s'\n",
755
configFile, lineNum, createOwner);
756
if (newlog != defConfig) {
757
*endtag = oldchar, start = endtag;
764
newlog->createUid = pw->pw_uid;
768
group = getgrnam(createGroup);
770
message(MESS_ERROR, "%s:%d unknown group '%s'\n",
771
configFile, lineNum, createGroup);
772
if (newlog != defConfig) {
773
*endtag = oldchar, start = endtag;
780
newlog->createGid = group->gr_gid;
784
newlog->flags |= LOG_FLAG_CREATE;
786
*endtag = oldchar, start = endtag;
787
} else if (!strcmp(start, "nocreate")) {
788
newlog->flags &= ~LOG_FLAG_CREATE;
790
*endtag = oldchar, start = endtag;
791
} else if (!strcmp(start, "size") || !strcmp(start, "minsize")) {
792
unsigned int size = 0;
794
*endtag = oldchar, start = endtag;
796
if (!isolateValue(configFile, lineNum, opt, &start,
798
oldchar = *endtag, *endtag = '\0';
800
length = strlen(start) - 1;
801
if (start[length] == 'k') {
802
start[length] = '\0';
804
} else if (start[length] == 'M') {
805
start[length] = '\0';
806
multiplier = 1024 * 1024;
807
} else if (start[length] == 'G') {
808
start[length] = '\0';
809
multiplier = 1024 * 1024 * 1024;
810
} else if (!isdigit(start[length])) {
811
message(MESS_ERROR, "%s:%d unknown unit '%c'\n",
812
configFile, lineNum, start[length]);
813
if (newlog != defConfig) {
814
*endtag = oldchar, start = endtag;
824
size = multiplier * strtoul(start, &chptr, 0);
826
message(MESS_ERROR, "%s:%d bad size '%s'\n",
827
configFile, lineNum, start);
828
if (newlog != defConfig) {
829
*endtag = oldchar, start = endtag;
837
if (!strncmp(opt, "size", 4)) {
838
newlog->criterium = ROT_SIZE;
839
newlog->threshhold = size;
841
newlog->minsize = size;
843
*endtag = oldchar, start = endtag;
845
#if 0 /* this seems like such a good idea :-( */
846
} else if (!strcmp(start, "days")) {
847
*endtag = oldchar, start = endtag;
849
if (!isolateValue(configFile, lineNum, "size", &start,
851
oldchar = *endtag, *endtag = '\0';
853
newlog->threshhold = strtoul(start, &chptr, 0);
856
"%s:%d bad number of days'%s'\n",
857
configFile, lineNum, start);
861
newlog->criterium = ROT_DAYS;
863
*endtag = oldchar, start = endtag;
866
} else if (!strcmp(start, "shredcycles")) {
867
*endtag = oldchar, start = endtag;
869
if (!isolateValue(configFile, lineNum, "shred cycles",
871
oldchar = *endtag, *endtag = '\0';
873
newlog->shred_cycles = strtoul(start, &chptr, 0);
874
if (*chptr || newlog->shred_cycles < 0) {
875
message(MESS_ERROR, "%s:%d bad shred cycles '%s'\n",
876
configFile, lineNum, start);
879
*endtag = oldchar, start = endtag;
881
} else if (!strcmp(start, "daily")) {
882
*endtag = oldchar, start = endtag;
884
newlog->criterium = ROT_DAYS;
885
newlog->threshhold = 1;
886
} else if (!strcmp(start, "monthly")) {
887
*endtag = oldchar, start = endtag;
889
newlog->criterium = ROT_MONTHLY;
890
} else if (!strcmp(start, "weekly")) {
891
*endtag = oldchar, start = endtag;
893
newlog->criterium = ROT_WEEKLY;
894
} else if (!strcmp(start, "yearly")) {
895
*endtag = oldchar, start = endtag;
897
newlog->criterium = ROT_YEARLY;
898
} else if (!strcmp(start, "rotate")) {
899
*endtag = oldchar, start = endtag;
902
(configFile, lineNum, "rotate count", &start,
904
oldchar = *endtag, *endtag = '\0';
906
newlog->rotateCount = strtoul(start, &chptr, 0);
907
if (*chptr || newlog->rotateCount < 0) {
909
"%s:%d bad rotation count '%s'\n",
910
configFile, lineNum, start);
911
if (newlog != defConfig) {
912
*endtag = oldchar, start = endtag;
919
*endtag = oldchar, start = endtag;
921
} else if (!strcmp(start, "start")) {
922
*endtag = oldchar, start = endtag;
925
(configFile, lineNum, "start count", &start,
927
oldchar = *endtag, *endtag = '\0';
929
newlog->logStart = strtoul(start, &chptr, 0);
930
if (*chptr || newlog->logStart < 0) {
931
message(MESS_ERROR, "%s:%d bad start count '%s'\n",
932
configFile, lineNum, start);
933
if (newlog != defConfig) {
934
*endtag = oldchar, start = endtag;
941
*endtag = oldchar, start = endtag;
943
} else if (!strcmp(start, "maxage")) {
944
*endtag = oldchar, start = endtag;
947
(configFile, lineNum, "maxage count", &start,
949
oldchar = *endtag, *endtag = '\0';
951
newlog->rotateAge = strtoul(start, &chptr, 0);
952
if (*chptr || newlog->rotateAge < 0) {
953
message(MESS_ERROR, "%s:%d bad maximum age '%s'\n",
954
configFile, lineNum, start);
955
if (newlog != defConfig) {
956
*endtag = oldchar, start = endtag;
963
*endtag = oldchar, start = endtag;
965
} else if (!strcmp(start, "errors")) {
967
"%s: %d: the errors directive is deprecated and no longer used.\n",
968
configFile, lineNum);
969
} else if (!strcmp(start, "mail")) {
970
*endtag = oldchar, start = endtag;
971
freeLogItem(logAddress);
972
if (!(newlog->logAddress = readAddress(configFile, lineNum,
974
if (newlog != defConfig) {
981
} else if (!strcmp(start, "nomail")) {
982
freeLogItem(logAddress);
984
*endtag = oldchar, start = endtag;
985
} else if (!strcmp(start, "missingok")) {
986
newlog->flags |= LOG_FLAG_MISSINGOK;
988
*endtag = oldchar, start = endtag;
989
} else if (!strcmp(start, "nomissingok")) {
990
newlog->flags &= ~LOG_FLAG_MISSINGOK;
992
*endtag = oldchar, start = endtag;
993
} else if (!strcmp(start, "prerotate")) {
994
*endtag = oldchar, start = endtag;
999
scriptDest = &newlog->pre;
1001
while (*start != '\n')
1003
} else if (!strcmp(start, "firstaction")) {
1004
*endtag = oldchar, start = endtag;
1006
freeLogItem (first);
1008
scriptStart = start;
1009
scriptDest = &newlog->first;
1011
while (*start != '\n')
1013
} else if (!strcmp(start, "postrotate")) {
1014
*endtag = oldchar, start = endtag;
1018
scriptStart = start;
1019
scriptDest = &newlog->post;
1021
while (*start != '\n')
1023
} else if (!strcmp(start, "lastaction")) {
1024
*endtag = oldchar, start = endtag;
1028
scriptStart = start;
1029
scriptDest = &newlog->last;
1031
while (*start != '\n')
1033
} else if (!strcmp(start, "tabooext")) {
1034
if (newlog != defConfig) {
1036
"%s:%d tabooext may not appear inside "
1037
"of log file definition\n", configFile,
1039
*endtag = oldchar, start = endtag;
1044
*endtag = oldchar, start = endtag;
1045
if (!isolateValue(configFile, lineNum, "tabooext", &start,
1047
oldchar = *endtag, *endtag = '\0';
1049
if (*start == '+') {
1051
while (isspace(*start) && *start)
1054
free_2d_array(tabooExts, tabooCount);
1056
tabooExts = malloc(1);
1061
while (!isspace(*chptr) && *chptr != ',' && *chptr)
1064
tabooExts = realloc(tabooExts, sizeof(*tabooExts) *
1066
tabooExts[tabooCount] = malloc(chptr - start + 1);
1067
strncpy(tabooExts[tabooCount], start,
1069
tabooExts[tabooCount][chptr - start] = '\0';
1075
while (isspace(*start) && *start)
1079
*endtag = oldchar, start = endtag;
1081
} else if (!strcmp(start, "include")) {
1082
if (newlog != defConfig) {
1084
"%s:%d include may not appear inside "
1085
"of log file definition\n", configFile,
1087
*endtag = oldchar, start = endtag;
1092
*endtag = oldchar, start = endtag;
1093
if (!isolateValue(configFile, lineNum, "include", &start,
1095
oldchar = *endtag, *endtag = '\0';
1097
message(MESS_DEBUG, "including %s\n", start);
1098
if (++recursion_depth > MAX_NESTING) {
1099
message(MESS_ERROR, "%s:%d include nesting too deep\n",
1100
configFile, lineNum);
1104
if (readConfigPath(start, defConfig)) {
1110
*endtag = oldchar, start = endtag;
1112
} else if (!strcmp(start, "olddir")) {
1113
*endtag = oldchar, start = endtag;
1115
freeLogItem (oldDir);
1117
if (!(newlog->oldDir = readPath(configFile, lineNum,
1118
"olddir", &start))) {
1119
if (newlog != defConfig) {
1127
if (stat(newlog->oldDir, &sb)) {
1128
message(MESS_ERROR, "%s:%d error verifying olddir "
1129
"path %s: %s\n", configFile, lineNum,
1130
newlog->oldDir, strerror(errno));
1131
free(newlog->oldDir);
1135
if (!S_ISDIR(sb.st_mode)) {
1136
message(MESS_ERROR, "%s:%d olddir path %s is not a "
1137
"directory\n", configFile, lineNum,
1139
free(newlog->oldDir);
1144
message(MESS_DEBUG, "olddir is now %s\n", newlog->oldDir);
1145
} else if (!strcmp(start, "extension")) {
1146
*endtag = oldchar, start = endtag;
1149
(configFile, lineNum, "extension name", &start,
1151
oldchar = *endtag, *endtag = '\0';
1153
freeLogItem (extension);
1154
newlog->extension = strdup(start);
1156
*endtag = oldchar, start = endtag;
1159
message(MESS_DEBUG, "extension is now %s\n",
1162
} else if (!strcmp(start, "compresscmd")) {
1163
*endtag = oldchar, start = endtag;
1165
freeLogItem (compress_prog);
1168
(newlog->compress_prog =
1169
readPath(configFile, lineNum, "compress", &start))) {
1170
if (newlog != defConfig) {
1178
if (access(newlog->compress_prog, X_OK)) {
1180
"%s:%d compression program %s is not an executable file\n",
1181
configFile, lineNum, newlog->compress_prog);
1182
if (newlog != defConfig) {
1190
message(MESS_DEBUG, "compress_prog is now %s\n",
1191
newlog->compress_prog);
1193
} else if (!strcmp(start, "uncompresscmd")) {
1194
*endtag = oldchar, start = endtag;
1196
freeLogItem (uncompress_prog);
1199
(newlog->uncompress_prog =
1200
readPath(configFile, lineNum, "uncompress",
1202
if (newlog != defConfig) {
1210
if (access(newlog->uncompress_prog, X_OK)) {
1212
"%s:%d uncompression program %s is not an executable file\n",
1213
configFile, lineNum, newlog->uncompress_prog);
1214
if (newlog != defConfig) {
1222
message(MESS_DEBUG, "uncompress_prog is now %s\n",
1223
newlog->uncompress_prog);
1225
} else if (!strcmp(start, "compressoptions")) {
1228
if (newlog->compress_options_list) {
1229
free(newlog->compress_options_list);
1230
newlog->compress_options_list = NULL;
1231
newlog->compress_options_count = 0;
1234
*endtag = oldchar, start = endtag;
1237
readPath(configFile, lineNum, "compressoptions",
1239
if (newlog != defConfig) {
1247
if (poptParseArgvString(options,
1248
&newlog->compress_options_count,
1249
&newlog->compress_options_list)) {
1251
"%s:%d invalid compression options\n",
1252
configFile, lineNum);
1254
if (newlog != defConfig) {
1262
message(MESS_DEBUG, "compress_options is now %s\n",
1265
} else if (!strcmp(start, "compressext")) {
1266
*endtag = oldchar, start = endtag;
1268
freeLogItem (compress_ext);
1271
(newlog->compress_ext =
1272
readPath(configFile, lineNum, "compress-ext",
1274
if (newlog != defConfig) {
1282
message(MESS_DEBUG, "compress_ext is now %s\n",
1283
newlog->compress_ext);
1285
message(MESS_ERROR, "%s:%d unknown option '%s' "
1286
"-- ignoring line\n", configFile, lineNum, start);
1288
*endtag = oldchar, start = endtag;
1291
while (isblank(*start))
1294
if (*start != '\n') {
1295
message(MESS_ERROR, "%s:%d unexpected text\n", configFile,
1297
while (*start != '\n')
1303
} else if (*start == '/' || *start == '"' || *start == '\'') {
1304
if (newlog != defConfig) {
1305
message(MESS_ERROR, "%s:%d unexpected log filename\n",
1306
configFile, lineNum);
1311
/* If no compression options were found in config file, set
1313
if (!newlog->compress_prog)
1314
newlog->compress_prog = strdup(COMPRESS_COMMAND);
1315
if (!newlog->uncompress_prog)
1316
newlog->uncompress_prog = strdup(UNCOMPRESS_COMMAND);
1317
if (!newlog->compress_ext)
1318
newlog->compress_ext = strdup(COMPRESS_EXT);
1320
/* Allocate a new logInfo structure and insert it into the logs
1321
queue, copying the actual values from defConfig */
1322
if ((newlog = newLogInfo(defConfig)) == NULL)
1326
while (*endtag != '{' && *endtag != '\0')
1328
if (*endtag != '{') {
1329
message(MESS_ERROR, "%s:%d missing end of line\n",
1330
configFile, lineNum);
1334
if (poptParseArgvString(start, &argc, &argv)) {
1335
message(MESS_ERROR, "%s:%d error parsing filename\n",
1336
configFile, lineNum);
1338
} else if (argc < 1) {
1340
"%s:%d { expected after log file name(s)\n",
1341
configFile, lineNum);
1345
newlog->files = NULL;
1346
newlog->numFiles = 0;
1347
for (argNum = 0; argNum < argc && logerror != 1; argNum++) {
1348
rc = glob(argv[argNum], GLOB_NOCHECK, globerr,
1350
if (rc == GLOB_ABORTED) {
1351
if (newlog->flags & LOG_FLAG_MISSINGOK)
1354
message(MESS_ERROR, "%s:%d glob failed for %s\n",
1355
configFile, lineNum, argv[argNum]);
1361
realloc(newlog->files,
1362
sizeof(*newlog->files) * (newlog->numFiles +
1366
for (i = 0; i < globResult.gl_pathc; i++) {
1367
/* if we glob directories we can get false matches */
1368
if (!lstat(globResult.gl_pathv[i], &sb) &&
1369
S_ISDIR(sb.st_mode))
1372
for (log = logs.tqh_first; log != NULL;
1373
log = log->list.tqe_next) {
1374
for (k = 0; k < log->numFiles; k++) {
1375
if (!strcmp(log->files[k],
1376
globResult.gl_pathv[i])) {
1378
"%s:%d duplicate log entry for %s\n",
1379
configFile, lineNum,
1380
globResult.gl_pathv[i]);
1387
newlog->files[newlog->numFiles] =
1388
strdup(globResult.gl_pathv[i]);
1392
globfree(&globResult);
1395
newlog->pattern = strdup(start);
1398
message(MESS_DEBUG, "reading config info for %s\n", start);
1403
} else if (*start == '}') {
1404
if (newlog == defConfig) {
1405
message(MESS_ERROR, "%s:%d unexpected }\n", configFile,
1410
if (newlog->oldDir) {
1411
for (i = 0; i < newlog->numFiles; i++) {
1413
dirName = ourDirName(newlog->files[i]);
1414
if (stat(dirName, &sb2)) {
1416
"%s:%d error verifying log file "
1417
"path %s: %s\n", configFile, lineNum,
1418
dirName, strerror(errno));
1422
ld = alloca(strlen(dirName) + strlen(newlog->oldDir) +
1424
sprintf(ld, "%s/%s", dirName, newlog->oldDir);
1427
if (newlog->oldDir[0] != '/')
1430
dirName = newlog->oldDir;
1431
if (stat(dirName, &sb)) {
1432
message(MESS_ERROR, "%s:%d error verifying olddir "
1433
"path %s: %s\n", configFile, lineNum,
1434
dirName, strerror(errno));
1438
if (sb.st_dev != sb2.st_dev) {
1440
"%s:%d olddir %s and log file %s "
1441
"are on different devices\n", configFile,
1442
lineNum, newlog->oldDir, newlog->files[i]);
1451
while (isblank(*start))
1454
if (*start != '\n') {
1455
message(MESS_ERROR, "%s:%d, unexpected text after {\n",
1456
configFile, lineNum);
1459
message(MESS_ERROR, "%s:%d lines must begin with a keyword "
1460
"or a filename (possibly in double quotes)\n",
1461
configFile, lineNum);
1463
while (*start != '\n')
1472
"%s:prerotate or postrotate without endscript\n",