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->shred_cycles = from->shred_cycles;
229
to->createMode = from->createMode;
230
to->createUid = from->createUid;
231
to->createGid = from->createGid;
232
if (from->compress_options_count) {
233
poptDupArgv(from->compress_options_count, from->compress_options_list,
234
&to->compress_options_count, &to->compress_options_list);
236
if (from->dateformat)
237
to->dateformat = strdup(from->dateformat);
240
static void freeLogInfo(struct logInfo *log)
243
free_2d_array(log->files, log->numFiles);
249
free(log->logAddress);
250
free(log->extension);
251
free(log->compress_prog);
252
free(log->uncompress_prog);
253
free(log->compress_ext);
254
free(log->compress_options_list);
255
free(log->dateformat);
258
static struct logInfo *newLogInfo(struct logInfo *template)
262
if ((new = malloc(sizeof(*new))) == NULL)
265
copyLogInfo(new, template);
266
TAILQ_INSERT_TAIL(&logs, new, list);
272
static void removeLogInfo(struct logInfo *log)
278
TAILQ_REMOVE(&logs, log, list);
282
static void freeTailLogs(int num)
284
message(MESS_DEBUG, "removing last %d log configs\n", num);
287
removeLogInfo(*(logs.tqh_last));
290
static int readConfigPath(const char *path, struct logInfo *defConfig)
293
int here, oldnumlogs, result = 1;
294
struct logInfo defConfigBackup;
296
if (stat(path, &sb)) {
297
message(MESS_ERROR, "cannot stat %s: %s\n", path, strerror(errno));
301
if (S_ISDIR(sb.st_mode)) {
302
char **namelist, **p;
307
here = open(".", O_RDONLY);
309
if ((dirp = opendir(path)) == NULL) {
310
message(MESS_ERROR, "cannot open directory %s: %s\n", path,
317
while ((dp = readdir(dirp)) != NULL) {
318
if (checkFile(dp->d_name)) {
319
/* Realloc memory for namelist array if necessary */
320
if (files_count % REALLOC_STEP == 0) {
321
p = (char **) realloc(namelist,
323
REALLOC_STEP) * sizeof(char *));
326
memset(namelist + files_count, '\0',
327
REALLOC_STEP * sizeof(char *));
329
free_2d_array(namelist, files_count);
332
message(MESS_ERROR, "cannot realloc: %s\n",
337
/* Alloc memory for file name */
338
if ((namelist[files_count] =
339
(char *) malloc(strlen(dp->d_name) + 1))) {
340
strcpy(namelist[files_count], dp->d_name);
343
free_2d_array(namelist, files_count);
346
message(MESS_ERROR, "cannot realloc: %s\n",
354
if (files_count > 0) {
355
qsort(namelist, files_count, sizeof(char *), compar);
362
message(MESS_ERROR, "error in chdir(\"%s\"): %s\n", path,
365
free_2d_array(namelist, files_count);
369
for (i = 0; i < files_count; ++i) {
370
assert(namelist[i] != NULL);
371
oldnumlogs = numLogs;
372
copyLogInfo(&defConfigBackup, defConfig);
373
if (readConfigFile(namelist[i], defConfig)) {
374
message(MESS_ERROR, "found error in file %s, skipping\n", namelist[i]);
375
freeTailLogs(numLogs - oldnumlogs);
376
freeLogInfo(defConfig);
377
copyLogInfo(defConfig, &defConfigBackup);
378
freeLogInfo(&defConfigBackup);
383
freeLogInfo(&defConfigBackup);
386
if (fchdir(here) < 0) {
387
message(MESS_ERROR, "could not change directory to '.'");
390
free_2d_array(namelist, files_count);
392
oldnumlogs = numLogs;
393
copyLogInfo(&defConfigBackup, defConfig);
394
if (readConfigFile(path, defConfig)) {
395
freeTailLogs(numLogs - oldnumlogs);
396
freeLogInfo(defConfig);
397
copyLogInfo(defConfig, &defConfigBackup);
401
freeLogInfo(&defConfigBackup);
407
int readAllConfigPaths(const char **paths)
411
struct logInfo defConfig = {
416
.criterium = ROT_SIZE,
417
.threshhold = 1024 * 1024,
428
.compress_prog = NULL,
429
.uncompress_prog = NULL,
430
.compress_ext = NULL,
432
.flags = LOG_FLAG_IFEMPTY,
434
.createMode = NO_MODE,
437
.compress_options_list = NULL,
438
.compress_options_count = 0
441
tabooExts = malloc(sizeof(*tabooExts) * defTabooCount);
442
for (i = 0; i < defTabooCount; i++) {
443
if ((tabooExts[i] = (char *) malloc(strlen(defTabooExts[i]) + 1))) {
444
strcpy(tabooExts[i], defTabooExts[i]);
447
free_2d_array(tabooExts, tabooCount);
448
message(MESS_ERROR, "cannot malloc: %s\n", strerror(errno));
453
for (file = paths; *file; file++) {
454
if (readConfigPath(*file, &defConfig)) {
459
free_2d_array(tabooExts, tabooCount);
460
freeLogInfo(&defConfig);
464
static int globerr(const char *pathname, int theerr)
466
message(MESS_ERROR, "error accessing %s: %s\n", pathname,
469
/* We want the glob operation to abort on error, so return 1 */
473
#define freeLogItem(what) \
475
free(newlog->what); \
476
newlog->what = NULL; \
478
#define MAX_NESTING 16U
480
static int readConfigFile(const char *configFile, struct logInfo *defConfig)
489
char *scriptStart = NULL;
490
char **scriptDest = NULL;
491
struct logInfo *newlog = defConfig;
497
char createOwner[200], createGroup[200];
505
static unsigned recursion_depth = 0U;
507
/* FIXME: createOwner and createGroup probably shouldn't be fixed
508
length arrays -- of course, if we aren't run setuid it doesn't
511
fd = open(configFile, O_RDONLY);
513
message(MESS_ERROR, "failed to open config file %s: %s\n",
514
configFile, strerror(errno));
518
if (fstat(fd, &sb)) {
519
message(MESS_ERROR, "fstat of %s failed: %s\n", configFile,
524
if (!S_ISREG(sb.st_mode)) {
526
"Ignoring %s because it's not a regular file.\n",
534
if (length > 0xffffff) {
535
message(MESS_ERROR, "file %s too large, probably not a config file.\n",
541
buf = alloca(length + 2);
543
message(MESS_ERROR, "alloca() of %d bytes failed\n", (int) length);
548
if (read(fd, buf, length) != length) {
549
message(MESS_ERROR, "failed to read %s: %s\n", configFile,
557
/* knowing the buffer ends with a newline makes things (a bit) cleaner */
558
buf[length + 1] = '\0';
561
message(MESS_DEBUG, "reading config file %s\n", configFile);
566
assert(newlog != defConfig);
568
message(MESS_ERROR, "found error in %s, skipping\n",
569
newlog->pattern ? newlog->pattern : "log config");
571
while (*start != '}') {
573
message(MESS_ERROR, "%s:%d } expected \n",
574
configFile, lineNum);
576
} else if (*start == '\n') {
587
while (isblank(*start) && (*start))
590
while (*start != '\n')
594
if (*start == '\n') {
601
if (!strncmp(start, "endscript", 9)) {
603
while (isblank(*chptr))
605
if (*chptr == '\n') {
607
while (*endtag != '\n')
610
*scriptDest = malloc(endtag - scriptStart + 1);
611
strncpy(*scriptDest, scriptStart,
612
endtag - scriptStart);
613
(*scriptDest)[endtag - scriptStart] = '\0';
623
while (*start != '\n')
628
} else if (isalpha(*start)) {
630
while (isalpha(*endtag))
635
if (!strcmp(start, "compress")) {
636
newlog->flags |= LOG_FLAG_COMPRESS;
638
*endtag = oldchar, start = endtag;
639
} else if (!strcmp(start, "nocompress")) {
640
newlog->flags &= ~LOG_FLAG_COMPRESS;
642
*endtag = oldchar, start = endtag;
643
} else if (!strcmp(start, "delaycompress")) {
644
newlog->flags |= LOG_FLAG_DELAYCOMPRESS;
646
*endtag = oldchar, start = endtag;
647
} else if (!strcmp(start, "nodelaycompress")) {
648
newlog->flags &= ~LOG_FLAG_DELAYCOMPRESS;
650
*endtag = oldchar, start = endtag;
651
} else if (!strcmp(start, "shred")) {
652
newlog->flags |= LOG_FLAG_SHRED;
654
*endtag = oldchar, start = endtag;
655
} else if (!strcmp(start, "noshred")) {
656
newlog->flags &= ~LOG_FLAG_SHRED;
658
*endtag = oldchar, start = endtag;
659
} else if (!strcmp(start, "sharedscripts")) {
660
newlog->flags |= LOG_FLAG_SHAREDSCRIPTS;
662
*endtag = oldchar, start = endtag;
663
} else if (!strcmp(start, "nosharedscripts")) {
664
newlog->flags &= ~LOG_FLAG_SHAREDSCRIPTS;
666
*endtag = oldchar, start = endtag;
667
} else if (!strcmp(start, "copytruncate")) {
668
newlog->flags |= LOG_FLAG_COPYTRUNCATE;
670
*endtag = oldchar, start = endtag;
671
} else if (!strcmp(start, "nocopytruncate")) {
672
newlog->flags &= ~LOG_FLAG_COPYTRUNCATE;
674
*endtag = oldchar, start = endtag;
675
} else if (!strcmp(start, "copy")) {
676
newlog->flags |= LOG_FLAG_COPY;
678
*endtag = oldchar, start = endtag;
679
} else if (!strcmp(start, "nocopy")) {
680
newlog->flags &= ~LOG_FLAG_COPY;
682
*endtag = oldchar, start = endtag;
683
} else if (!strcmp(start, "ifempty")) {
684
newlog->flags |= LOG_FLAG_IFEMPTY;
686
*endtag = oldchar, start = endtag;
687
} else if (!strcmp(start, "notifempty")) {
688
newlog->flags &= ~LOG_FLAG_IFEMPTY;
690
*endtag = oldchar, start = endtag;
691
} else if (!strcmp(start, "dateext")) {
692
newlog->flags |= LOG_FLAG_DATEEXT;
694
*endtag = oldchar, start = endtag;
695
} else if (!strcmp(start, "nodateext")) {
696
newlog->flags &= ~LOG_FLAG_DATEEXT;
698
*endtag = oldchar, start = endtag;
699
} else if (!strcmp(start, "dateformat")) {
700
*endtag = oldchar, start = endtag;
703
while (*endtag != '\n')
705
while (isspace(*endtag))
708
oldchar = *endtag, *endtag = '\0';
710
freeLogItem(dateformat);
711
newlog->dateformat = strdup(start);
713
*endtag = oldchar, start = endtag;
714
} else if (!strcmp(start, "noolddir")) {
715
newlog->oldDir = NULL;
717
*endtag = oldchar, start = endtag;
718
} else if (!strcmp(start, "mailfirst")) {
719
newlog->flags |= LOG_FLAG_MAILFIRST;
721
*endtag = oldchar, start = endtag;
722
} else if (!strcmp(start, "maillast")) {
723
newlog->flags &= ~LOG_FLAG_MAILFIRST;
725
*endtag = oldchar, start = endtag;
726
} else if (!strcmp(start, "create")) {
727
*endtag = oldchar, start = endtag;
730
while (*endtag != '\n')
732
while (isspace(*endtag))
735
oldchar = *endtag, *endtag = '\0';
737
rc = sscanf(start, "%o %s %s%c", &createMode,
738
createOwner, createGroup, &foo);
740
message(MESS_ERROR, "%s:%d extra arguments for "
741
"create\n", configFile, lineNum);
742
if (newlog != defConfig) {
743
*endtag = oldchar, start = endtag;
752
newlog->createMode = createMode;
755
pw = getpwnam(createOwner);
757
message(MESS_ERROR, "%s:%d unknown user '%s'\n",
758
configFile, lineNum, createOwner);
759
if (newlog != defConfig) {
760
*endtag = oldchar, start = endtag;
767
newlog->createUid = pw->pw_uid;
771
group = getgrnam(createGroup);
773
message(MESS_ERROR, "%s:%d unknown group '%s'\n",
774
configFile, lineNum, createGroup);
775
if (newlog != defConfig) {
776
*endtag = oldchar, start = endtag;
783
newlog->createGid = group->gr_gid;
787
newlog->flags |= LOG_FLAG_CREATE;
789
*endtag = oldchar, start = endtag;
790
} else if (!strcmp(start, "nocreate")) {
791
newlog->flags &= ~LOG_FLAG_CREATE;
793
*endtag = oldchar, start = endtag;
794
} else if (!strcmp(start, "size") || !strcmp(start, "minsize")) {
795
unsigned int size = 0;
797
*endtag = oldchar, start = endtag;
799
if (!isolateValue(configFile, lineNum, opt, &start,
801
oldchar = *endtag, *endtag = '\0';
803
length = strlen(start) - 1;
804
if (start[length] == 'k') {
805
start[length] = '\0';
807
} else if (start[length] == 'M') {
808
start[length] = '\0';
809
multiplier = 1024 * 1024;
810
} else if (start[length] == 'G') {
811
start[length] = '\0';
812
multiplier = 1024 * 1024 * 1024;
813
} else if (!isdigit(start[length])) {
814
message(MESS_ERROR, "%s:%d unknown unit '%c'\n",
815
configFile, lineNum, start[length]);
816
if (newlog != defConfig) {
817
*endtag = oldchar, start = endtag;
827
size = multiplier * strtoul(start, &chptr, 0);
829
message(MESS_ERROR, "%s:%d bad size '%s'\n",
830
configFile, lineNum, start);
831
if (newlog != defConfig) {
832
*endtag = oldchar, start = endtag;
840
if (!strncmp(opt, "size", 4)) {
841
newlog->criterium = ROT_SIZE;
842
newlog->threshhold = size;
844
newlog->minsize = size;
846
*endtag = oldchar, start = endtag;
848
#if 0 /* this seems like such a good idea :-( */
849
} else if (!strcmp(start, "days")) {
850
*endtag = oldchar, start = endtag;
852
if (!isolateValue(configFile, lineNum, "size", &start,
854
oldchar = *endtag, *endtag = '\0';
856
newlog->threshhold = strtoul(start, &chptr, 0);
859
"%s:%d bad number of days'%s'\n",
860
configFile, lineNum, start);
864
newlog->criterium = ROT_DAYS;
866
*endtag = oldchar, start = endtag;
869
} else if (!strcmp(start, "shredcycles")) {
870
*endtag = oldchar, start = endtag;
872
if (!isolateValue(configFile, lineNum, "shred cycles",
874
oldchar = *endtag, *endtag = '\0';
876
newlog->shred_cycles = strtoul(start, &chptr, 0);
877
if (*chptr || newlog->shred_cycles < 0) {
878
message(MESS_ERROR, "%s:%d bad shred cycles '%s'\n",
879
configFile, lineNum, start);
882
*endtag = oldchar, start = endtag;
884
} else if (!strcmp(start, "daily")) {
885
*endtag = oldchar, start = endtag;
887
newlog->criterium = ROT_DAYS;
888
newlog->threshhold = 1;
889
} else if (!strcmp(start, "monthly")) {
890
*endtag = oldchar, start = endtag;
892
newlog->criterium = ROT_MONTHLY;
893
} else if (!strcmp(start, "weekly")) {
894
*endtag = oldchar, start = endtag;
896
newlog->criterium = ROT_WEEKLY;
897
} else if (!strcmp(start, "yearly")) {
898
*endtag = oldchar, start = endtag;
900
newlog->criterium = ROT_YEARLY;
901
} else if (!strcmp(start, "rotate")) {
902
*endtag = oldchar, start = endtag;
905
(configFile, lineNum, "rotate count", &start,
907
oldchar = *endtag, *endtag = '\0';
909
newlog->rotateCount = strtoul(start, &chptr, 0);
910
if (*chptr || newlog->rotateCount < 0) {
912
"%s:%d bad rotation count '%s'\n",
913
configFile, lineNum, start);
914
if (newlog != defConfig) {
915
*endtag = oldchar, start = endtag;
922
*endtag = oldchar, start = endtag;
924
} else if (!strcmp(start, "start")) {
925
*endtag = oldchar, start = endtag;
928
(configFile, lineNum, "start count", &start,
930
oldchar = *endtag, *endtag = '\0';
932
newlog->logStart = strtoul(start, &chptr, 0);
933
if (*chptr || newlog->logStart < 0) {
934
message(MESS_ERROR, "%s:%d bad start count '%s'\n",
935
configFile, lineNum, start);
936
if (newlog != defConfig) {
937
*endtag = oldchar, start = endtag;
944
*endtag = oldchar, start = endtag;
946
} else if (!strcmp(start, "maxage")) {
947
*endtag = oldchar, start = endtag;
950
(configFile, lineNum, "maxage count", &start,
952
oldchar = *endtag, *endtag = '\0';
954
newlog->rotateAge = strtoul(start, &chptr, 0);
955
if (*chptr || newlog->rotateAge < 0) {
956
message(MESS_ERROR, "%s:%d bad maximum age '%s'\n",
957
configFile, lineNum, start);
958
if (newlog != defConfig) {
959
*endtag = oldchar, start = endtag;
966
*endtag = oldchar, start = endtag;
968
} else if (!strcmp(start, "errors")) {
970
"%s: %d: the errors directive is deprecated and no longer used.\n",
971
configFile, lineNum);
972
} else if (!strcmp(start, "mail")) {
973
*endtag = oldchar, start = endtag;
974
freeLogItem(logAddress);
975
if (!(newlog->logAddress = readAddress(configFile, lineNum,
977
if (newlog != defConfig) {
984
} else if (!strcmp(start, "nomail")) {
985
freeLogItem(logAddress);
987
*endtag = oldchar, start = endtag;
988
} else if (!strcmp(start, "missingok")) {
989
newlog->flags |= LOG_FLAG_MISSINGOK;
991
*endtag = oldchar, start = endtag;
992
} else if (!strcmp(start, "nomissingok")) {
993
newlog->flags &= ~LOG_FLAG_MISSINGOK;
995
*endtag = oldchar, start = endtag;
996
} else if (!strcmp(start, "prerotate")) {
997
*endtag = oldchar, start = endtag;
1001
scriptStart = start;
1002
scriptDest = &newlog->pre;
1004
while (*start != '\n')
1006
} else if (!strcmp(start, "firstaction")) {
1007
*endtag = oldchar, start = endtag;
1009
freeLogItem (first);
1011
scriptStart = start;
1012
scriptDest = &newlog->first;
1014
while (*start != '\n')
1016
} else if (!strcmp(start, "postrotate")) {
1017
*endtag = oldchar, start = endtag;
1021
scriptStart = start;
1022
scriptDest = &newlog->post;
1024
while (*start != '\n')
1026
} else if (!strcmp(start, "lastaction")) {
1027
*endtag = oldchar, start = endtag;
1031
scriptStart = start;
1032
scriptDest = &newlog->last;
1034
while (*start != '\n')
1036
} else if (!strcmp(start, "tabooext")) {
1037
if (newlog != defConfig) {
1039
"%s:%d tabooext may not appear inside "
1040
"of log file definition\n", configFile,
1042
*endtag = oldchar, start = endtag;
1047
*endtag = oldchar, start = endtag;
1048
if (!isolateValue(configFile, lineNum, "tabooext", &start,
1050
oldchar = *endtag, *endtag = '\0';
1052
if (*start == '+') {
1054
while (isspace(*start) && *start)
1057
free_2d_array(tabooExts, tabooCount);
1059
tabooExts = malloc(1);
1064
while (!isspace(*chptr) && /* *chptr != ',' && */ *chptr)
1067
tabooExts = realloc(tabooExts, sizeof(*tabooExts) *
1069
tabooExts[tabooCount] = malloc(chptr - start + 1);
1070
strncpy(tabooExts[tabooCount], start,
1072
tabooExts[tabooCount][chptr - start] = '\0';
1080
while (isspace(*start) && *start)
1084
*endtag = oldchar, start = endtag;
1086
} else if (!strcmp(start, "include")) {
1087
if (newlog != defConfig) {
1089
"%s:%d include may not appear inside "
1090
"of log file definition\n", configFile,
1092
*endtag = oldchar, start = endtag;
1097
*endtag = oldchar, start = endtag;
1098
if (!isolateValue(configFile, lineNum, "include", &start,
1100
oldchar = *endtag, *endtag = '\0';
1102
message(MESS_DEBUG, "including %s\n", start);
1103
if (++recursion_depth > MAX_NESTING) {
1104
message(MESS_ERROR, "%s:%d include nesting too deep\n",
1105
configFile, lineNum);
1109
if (readConfigPath(start, defConfig)) {
1115
*endtag = oldchar, start = endtag;
1117
} else if (!strcmp(start, "olddir")) {
1118
*endtag = oldchar, start = endtag;
1120
freeLogItem (oldDir);
1122
if (!(newlog->oldDir = readPath(configFile, lineNum,
1123
"olddir", &start))) {
1124
if (newlog != defConfig) {
1132
if (stat(newlog->oldDir, &sb)) {
1133
message(MESS_ERROR, "%s:%d error verifying olddir "
1134
"path %s: %s\n", configFile, lineNum,
1135
newlog->oldDir, strerror(errno));
1136
free(newlog->oldDir);
1140
if (!S_ISDIR(sb.st_mode)) {
1141
message(MESS_ERROR, "%s:%d olddir path %s is not a "
1142
"directory\n", configFile, lineNum,
1144
free(newlog->oldDir);
1149
message(MESS_DEBUG, "olddir is now %s\n", newlog->oldDir);
1150
} else if (!strcmp(start, "extension")) {
1151
*endtag = oldchar, start = endtag;
1154
(configFile, lineNum, "extension name", &start,
1156
oldchar = *endtag, *endtag = '\0';
1158
freeLogItem (extension);
1159
newlog->extension = strdup(start);
1161
*endtag = oldchar, start = endtag;
1164
message(MESS_DEBUG, "extension is now %s\n",
1167
} else if (!strcmp(start, "compresscmd")) {
1168
*endtag = oldchar, start = endtag;
1170
freeLogItem (compress_prog);
1173
(newlog->compress_prog =
1174
readPath(configFile, lineNum, "compress", &start))) {
1175
if (newlog != defConfig) {
1183
if (access(newlog->compress_prog, X_OK)) {
1185
"%s:%d compression program %s is not an executable file\n",
1186
configFile, lineNum, newlog->compress_prog);
1187
if (newlog != defConfig) {
1195
message(MESS_DEBUG, "compress_prog is now %s\n",
1196
newlog->compress_prog);
1198
} else if (!strcmp(start, "uncompresscmd")) {
1199
*endtag = oldchar, start = endtag;
1201
freeLogItem (uncompress_prog);
1204
(newlog->uncompress_prog =
1205
readPath(configFile, lineNum, "uncompress",
1207
if (newlog != defConfig) {
1215
if (access(newlog->uncompress_prog, X_OK)) {
1217
"%s:%d uncompression program %s is not an executable file\n",
1218
configFile, lineNum, newlog->uncompress_prog);
1219
if (newlog != defConfig) {
1227
message(MESS_DEBUG, "uncompress_prog is now %s\n",
1228
newlog->uncompress_prog);
1230
} else if (!strcmp(start, "compressoptions")) {
1233
if (newlog->compress_options_list) {
1234
free(newlog->compress_options_list);
1235
newlog->compress_options_list = NULL;
1236
newlog->compress_options_count = 0;
1239
*endtag = oldchar, start = endtag;
1242
readPath(configFile, lineNum, "compressoptions",
1244
if (newlog != defConfig) {
1252
if (poptParseArgvString(options,
1253
&newlog->compress_options_count,
1254
&newlog->compress_options_list)) {
1256
"%s:%d invalid compression options\n",
1257
configFile, lineNum);
1259
if (newlog != defConfig) {
1267
message(MESS_DEBUG, "compress_options is now %s\n",
1270
} else if (!strcmp(start, "compressext")) {
1271
*endtag = oldchar, start = endtag;
1273
freeLogItem (compress_ext);
1276
(newlog->compress_ext =
1277
readPath(configFile, lineNum, "compress-ext",
1279
if (newlog != defConfig) {
1287
message(MESS_DEBUG, "compress_ext is now %s\n",
1288
newlog->compress_ext);
1290
message(MESS_ERROR, "%s:%d unknown option '%s' "
1291
"-- ignoring line\n", configFile, lineNum, start);
1293
*endtag = oldchar, start = endtag;
1296
while (isblank(*start))
1299
if (*start != '\n') {
1300
message(MESS_ERROR, "%s:%d unexpected text\n", configFile,
1302
while (*start != '\n')
1308
} else if (*start == '/' || *start == '"' || *start == '\'') {
1309
if (newlog != defConfig) {
1310
message(MESS_ERROR, "%s:%d unexpected log filename\n",
1311
configFile, lineNum);
1316
/* If no compression options were found in config file, set
1318
if (!newlog->compress_prog)
1319
newlog->compress_prog = strdup(COMPRESS_COMMAND);
1320
if (!newlog->uncompress_prog)
1321
newlog->uncompress_prog = strdup(UNCOMPRESS_COMMAND);
1322
if (!newlog->compress_ext)
1323
newlog->compress_ext = strdup(COMPRESS_EXT);
1325
/* Allocate a new logInfo structure and insert it into the logs
1326
queue, copying the actual values from defConfig */
1327
if ((newlog = newLogInfo(defConfig)) == NULL)
1331
while (*endtag != '{' && *endtag != '\0')
1333
if (*endtag != '{') {
1334
message(MESS_ERROR, "%s:%d missing end of line\n",
1335
configFile, lineNum);
1339
if (poptParseArgvString(start, &argc, &argv)) {
1340
message(MESS_ERROR, "%s:%d error parsing filename\n",
1341
configFile, lineNum);
1343
} else if (argc < 1) {
1345
"%s:%d { expected after log file name(s)\n",
1346
configFile, lineNum);
1350
newlog->files = NULL;
1351
newlog->numFiles = 0;
1352
for (argNum = 0; argNum < argc && logerror != 1; argNum++) {
1353
rc = glob(argv[argNum], GLOB_NOCHECK, globerr,
1355
if (rc == GLOB_ABORTED) {
1356
if (newlog->flags & LOG_FLAG_MISSINGOK)
1359
message(MESS_ERROR, "%s:%d glob failed for %s\n",
1360
configFile, lineNum, argv[argNum]);
1366
realloc(newlog->files,
1367
sizeof(*newlog->files) * (newlog->numFiles +
1371
for (i = 0; i < globResult.gl_pathc; i++) {
1372
/* if we glob directories we can get false matches */
1373
if (!lstat(globResult.gl_pathv[i], &sb) &&
1374
S_ISDIR(sb.st_mode))
1377
for (log = logs.tqh_first; log != NULL;
1378
log = log->list.tqe_next) {
1379
for (k = 0; k < log->numFiles; k++) {
1380
if (!strcmp(log->files[k],
1381
globResult.gl_pathv[i])) {
1383
"%s:%d duplicate log entry for %s\n",
1384
configFile, lineNum,
1385
globResult.gl_pathv[i]);
1392
newlog->files[newlog->numFiles] =
1393
strdup(globResult.gl_pathv[i]);
1397
globfree(&globResult);
1400
newlog->pattern = strdup(start);
1403
message(MESS_DEBUG, "reading config info for %s\n", start);
1408
} else if (*start == '}') {
1409
if (newlog == defConfig) {
1410
message(MESS_ERROR, "%s:%d unexpected }\n", configFile,
1415
if (newlog->oldDir) {
1416
for (i = 0; i < newlog->numFiles; i++) {
1418
dirName = ourDirName(newlog->files[i]);
1419
if (stat(dirName, &sb2)) {
1421
"%s:%d error verifying log file "
1422
"path %s: %s\n", configFile, lineNum,
1423
dirName, strerror(errno));
1427
ld = alloca(strlen(dirName) + strlen(newlog->oldDir) +
1429
sprintf(ld, "%s/%s", dirName, newlog->oldDir);
1432
if (newlog->oldDir[0] != '/')
1435
dirName = newlog->oldDir;
1436
if (stat(dirName, &sb)) {
1437
message(MESS_ERROR, "%s:%d error verifying olddir "
1438
"path %s: %s\n", configFile, lineNum,
1439
dirName, strerror(errno));
1443
if (sb.st_dev != sb2.st_dev) {
1445
"%s:%d olddir %s and log file %s "
1446
"are on different devices\n", configFile,
1447
lineNum, newlog->oldDir, newlog->files[i]);
1456
while (isblank(*start))
1459
if (*start != '\n') {
1460
message(MESS_ERROR, "%s:%d, unexpected text after {\n",
1461
configFile, lineNum);
1464
message(MESS_ERROR, "%s:%d lines must begin with a keyword "
1465
"or a filename (possibly in double quotes)\n",
1466
configFile, lineNum);
1468
while (*start != '\n')
1477
"%s:prerotate or postrotate without endscript\n",