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
if ((dirp = opendir(path)) == NULL) {
309
message(MESS_ERROR, "cannot open directory %s: %s\n", path,
316
while ((dp = readdir(dirp)) != NULL) {
317
if (checkFile(dp->d_name)) {
318
/* Realloc memory for namelist array if necessary */
319
if (files_count % REALLOC_STEP == 0) {
320
p = (char **) realloc(namelist,
322
REALLOC_STEP) * sizeof(char *));
325
memset(namelist + files_count, '\0',
326
REALLOC_STEP * sizeof(char *));
328
free_2d_array(namelist, files_count);
331
message(MESS_ERROR, "cannot realloc: %s\n",
336
/* Alloc memory for file name */
337
if ((namelist[files_count] =
338
(char *) malloc(strlen(dp->d_name) + 1))) {
339
strcpy(namelist[files_count], dp->d_name);
342
free_2d_array(namelist, files_count);
345
message(MESS_ERROR, "cannot realloc: %s\n",
353
if (files_count > 0) {
354
qsort(namelist, files_count, sizeof(char *), compar);
361
message(MESS_ERROR, "error in chdir(\"%s\"): %s\n", path,
364
free_2d_array(namelist, files_count);
368
for (i = 0; i < files_count; ++i) {
369
assert(namelist[i] != NULL);
370
oldnumlogs = numLogs;
371
copyLogInfo(&defConfigBackup, defConfig);
372
if (readConfigFile(namelist[i], defConfig)) {
373
message(MESS_ERROR, "found error in file %s, skipping\n", namelist[i]);
374
freeTailLogs(numLogs - oldnumlogs);
375
freeLogInfo(defConfig);
376
copyLogInfo(defConfig, &defConfigBackup);
377
freeLogInfo(&defConfigBackup);
382
freeLogInfo(&defConfigBackup);
385
if (fchdir(here) < 0) {
386
message(MESS_ERROR, "could not change directory to '.'");
389
free_2d_array(namelist, files_count);
391
oldnumlogs = numLogs;
392
copyLogInfo(&defConfigBackup, defConfig);
393
if (readConfigFile(path, defConfig)) {
394
freeTailLogs(numLogs - oldnumlogs);
395
freeLogInfo(defConfig);
396
copyLogInfo(defConfig, &defConfigBackup);
400
freeLogInfo(&defConfigBackup);
406
int readAllConfigPaths(const char **paths)
410
struct logInfo defConfig = {
415
.criterium = ROT_SIZE,
416
.threshhold = 1024 * 1024,
427
.compress_prog = NULL,
428
.uncompress_prog = NULL,
429
.compress_ext = NULL,
431
.flags = LOG_FLAG_IFEMPTY,
433
.createMode = NO_MODE,
436
.compress_options_list = NULL,
437
.compress_options_count = 0
440
tabooExts = malloc(sizeof(*tabooExts) * defTabooCount);
441
for (i = 0; i < defTabooCount; i++) {
442
if ((tabooExts[i] = (char *) malloc(strlen(defTabooExts[i]) + 1))) {
443
strcpy(tabooExts[i], defTabooExts[i]);
446
free_2d_array(tabooExts, tabooCount);
447
message(MESS_ERROR, "cannot malloc: %s\n", strerror(errno));
452
for (file = paths; *file; file++) {
453
if (readConfigPath(*file, &defConfig)) {
458
free_2d_array(tabooExts, tabooCount);
459
freeLogInfo(&defConfig);
463
static int globerr(const char *pathname, int theerr)
465
message(MESS_ERROR, "error accessing %s: %s\n", pathname,
468
/* We want the glob operation to abort on error, so return 1 */
472
#define freeLogItem(what) \
474
free(newlog->what); \
475
newlog->what = NULL; \
477
#define MAX_NESTING 16U
479
static int readConfigFile(const char *configFile, struct logInfo *defConfig)
488
char *scriptStart = NULL;
489
char **scriptDest = NULL;
490
struct logInfo *newlog = defConfig;
496
char createOwner[200], createGroup[200];
504
static unsigned recursion_depth = 0U;
506
/* FIXME: createOwner and createGroup probably shouldn't be fixed
507
length arrays -- of course, if we aren't run setuid it doesn't
510
fd = open(configFile, O_RDONLY);
512
message(MESS_ERROR, "failed to open config file %s: %s\n",
513
configFile, strerror(errno));
517
if (fstat(fd, &sb)) {
518
message(MESS_ERROR, "fstat of %s failed: %s\n", configFile,
523
if (!S_ISREG(sb.st_mode)) {
525
"Ignoring %s because it's not a regular file.\n",
533
if (length > 0xffffff) {
534
message(MESS_ERROR, "file %s too large, probably not a config file.\n",
540
buf = alloca(length + 2);
542
message(MESS_ERROR, "alloca() of %d bytes failed\n", (int) length);
547
if (read(fd, buf, length) != length) {
548
message(MESS_ERROR, "failed to read %s: %s\n", configFile,
556
/* knowing the buffer ends with a newline makes things (a bit) cleaner */
557
buf[length + 1] = '\0';
560
message(MESS_DEBUG, "reading config file %s\n", configFile);
565
assert(newlog != defConfig);
567
message(MESS_ERROR, "found error in %s, skipping\n",
568
newlog->pattern ? newlog->pattern : "log config");
570
while (*start != '}') {
572
message(MESS_ERROR, "%s:%d } expected \n",
573
configFile, lineNum);
575
} else if (*start == '\n') {
586
while (isblank(*start) && (*start))
589
while (*start != '\n')
593
if (*start == '\n') {
600
if (!strncmp(start, "endscript", 9)) {
602
while (isblank(*chptr))
604
if (*chptr == '\n') {
606
while (*endtag != '\n')
609
*scriptDest = malloc(endtag - scriptStart + 1);
610
strncpy(*scriptDest, scriptStart,
611
endtag - scriptStart);
612
(*scriptDest)[endtag - scriptStart] = '\0';
622
while (*start != '\n')
627
} else if (isalpha(*start)) {
629
while (isalpha(*endtag))
634
if (!strcmp(start, "compress")) {
635
newlog->flags |= LOG_FLAG_COMPRESS;
637
*endtag = oldchar, start = endtag;
638
} else if (!strcmp(start, "nocompress")) {
639
newlog->flags &= ~LOG_FLAG_COMPRESS;
641
*endtag = oldchar, start = endtag;
642
} else if (!strcmp(start, "delaycompress")) {
643
newlog->flags |= LOG_FLAG_DELAYCOMPRESS;
645
*endtag = oldchar, start = endtag;
646
} else if (!strcmp(start, "nodelaycompress")) {
647
newlog->flags &= ~LOG_FLAG_DELAYCOMPRESS;
649
*endtag = oldchar, start = endtag;
650
} else if (!strcmp(start, "shred")) {
651
newlog->flags |= LOG_FLAG_SHRED;
653
*endtag = oldchar, start = endtag;
654
} else if (!strcmp(start, "noshred")) {
655
newlog->flags &= ~LOG_FLAG_SHRED;
657
*endtag = oldchar, start = endtag;
658
} else if (!strcmp(start, "sharedscripts")) {
659
newlog->flags |= LOG_FLAG_SHAREDSCRIPTS;
661
*endtag = oldchar, start = endtag;
662
} else if (!strcmp(start, "nosharedscripts")) {
663
newlog->flags &= ~LOG_FLAG_SHAREDSCRIPTS;
665
*endtag = oldchar, start = endtag;
666
} else if (!strcmp(start, "copytruncate")) {
667
newlog->flags |= LOG_FLAG_COPYTRUNCATE;
669
*endtag = oldchar, start = endtag;
670
} else if (!strcmp(start, "nocopytruncate")) {
671
newlog->flags &= ~LOG_FLAG_COPYTRUNCATE;
673
*endtag = oldchar, start = endtag;
674
} else if (!strcmp(start, "copy")) {
675
newlog->flags |= LOG_FLAG_COPY;
677
*endtag = oldchar, start = endtag;
678
} else if (!strcmp(start, "nocopy")) {
679
newlog->flags &= ~LOG_FLAG_COPY;
681
*endtag = oldchar, start = endtag;
682
} else if (!strcmp(start, "ifempty")) {
683
newlog->flags |= LOG_FLAG_IFEMPTY;
685
*endtag = oldchar, start = endtag;
686
} else if (!strcmp(start, "notifempty")) {
687
newlog->flags &= ~LOG_FLAG_IFEMPTY;
689
*endtag = oldchar, start = endtag;
690
} else if (!strcmp(start, "dateext")) {
691
newlog->flags |= LOG_FLAG_DATEEXT;
693
*endtag = oldchar, start = endtag;
694
} else if (!strcmp(start, "nodateext")) {
695
newlog->flags &= ~LOG_FLAG_DATEEXT;
697
*endtag = oldchar, start = endtag;
698
} else if (!strcmp(start, "dateformat")) {
699
*endtag = oldchar, start = endtag;
702
while (*endtag != '\n')
704
while (isspace(*endtag))
707
oldchar = *endtag, *endtag = '\0';
709
freeLogItem(dateformat);
710
newlog->dateformat = strdup(start);
712
*endtag = oldchar, start = endtag;
713
} else if (!strcmp(start, "noolddir")) {
714
newlog->oldDir = NULL;
716
*endtag = oldchar, start = endtag;
717
} else if (!strcmp(start, "mailfirst")) {
718
newlog->flags |= LOG_FLAG_MAILFIRST;
720
*endtag = oldchar, start = endtag;
721
} else if (!strcmp(start, "maillast")) {
722
newlog->flags &= ~LOG_FLAG_MAILFIRST;
724
*endtag = oldchar, start = endtag;
725
} else if (!strcmp(start, "create")) {
726
*endtag = oldchar, start = endtag;
729
while (*endtag != '\n')
731
while (isspace(*endtag))
734
oldchar = *endtag, *endtag = '\0';
736
rc = sscanf(start, "%o %s %s%c", &createMode,
737
createOwner, createGroup, &foo);
739
message(MESS_ERROR, "%s:%d extra arguments for "
740
"create\n", configFile, lineNum);
741
if (newlog != defConfig) {
742
*endtag = oldchar, start = endtag;
751
newlog->createMode = createMode;
754
pw = getpwnam(createOwner);
756
message(MESS_ERROR, "%s:%d unknown user '%s'\n",
757
configFile, lineNum, createOwner);
758
if (newlog != defConfig) {
759
*endtag = oldchar, start = endtag;
766
newlog->createUid = pw->pw_uid;
770
group = getgrnam(createGroup);
772
message(MESS_ERROR, "%s:%d unknown group '%s'\n",
773
configFile, lineNum, createGroup);
774
if (newlog != defConfig) {
775
*endtag = oldchar, start = endtag;
782
newlog->createGid = group->gr_gid;
786
newlog->flags |= LOG_FLAG_CREATE;
788
*endtag = oldchar, start = endtag;
789
} else if (!strcmp(start, "nocreate")) {
790
newlog->flags &= ~LOG_FLAG_CREATE;
792
*endtag = oldchar, start = endtag;
793
} else if (!strcmp(start, "size") || !strcmp(start, "minsize")) {
794
unsigned int size = 0;
796
*endtag = oldchar, start = endtag;
798
if (!isolateValue(configFile, lineNum, opt, &start,
800
oldchar = *endtag, *endtag = '\0';
802
length = strlen(start) - 1;
803
if (start[length] == 'k') {
804
start[length] = '\0';
806
} else if (start[length] == 'M') {
807
start[length] = '\0';
808
multiplier = 1024 * 1024;
809
} else if (start[length] == 'G') {
810
start[length] = '\0';
811
multiplier = 1024 * 1024 * 1024;
812
} else if (!isdigit(start[length])) {
813
message(MESS_ERROR, "%s:%d unknown unit '%c'\n",
814
configFile, lineNum, start[length]);
815
if (newlog != defConfig) {
816
*endtag = oldchar, start = endtag;
826
size = multiplier * strtoul(start, &chptr, 0);
828
message(MESS_ERROR, "%s:%d bad size '%s'\n",
829
configFile, lineNum, start);
830
if (newlog != defConfig) {
831
*endtag = oldchar, start = endtag;
839
if (!strncmp(opt, "size", 4)) {
840
newlog->criterium = ROT_SIZE;
841
newlog->threshhold = size;
843
newlog->minsize = size;
845
*endtag = oldchar, start = endtag;
847
#if 0 /* this seems like such a good idea :-( */
848
} else if (!strcmp(start, "days")) {
849
*endtag = oldchar, start = endtag;
851
if (!isolateValue(configFile, lineNum, "size", &start,
853
oldchar = *endtag, *endtag = '\0';
855
newlog->threshhold = strtoul(start, &chptr, 0);
858
"%s:%d bad number of days'%s'\n",
859
configFile, lineNum, start);
863
newlog->criterium = ROT_DAYS;
865
*endtag = oldchar, start = endtag;
868
} else if (!strcmp(start, "shredcycles")) {
869
*endtag = oldchar, start = endtag;
871
if (!isolateValue(configFile, lineNum, "shred cycles",
873
oldchar = *endtag, *endtag = '\0';
875
newlog->shred_cycles = strtoul(start, &chptr, 0);
876
if (*chptr || newlog->shred_cycles < 0) {
877
message(MESS_ERROR, "%s:%d bad shred cycles '%s'\n",
878
configFile, lineNum, start);
881
*endtag = oldchar, start = endtag;
883
} else if (!strcmp(start, "daily")) {
884
*endtag = oldchar, start = endtag;
886
newlog->criterium = ROT_DAYS;
887
newlog->threshhold = 1;
888
} else if (!strcmp(start, "monthly")) {
889
*endtag = oldchar, start = endtag;
891
newlog->criterium = ROT_MONTHLY;
892
} else if (!strcmp(start, "weekly")) {
893
*endtag = oldchar, start = endtag;
895
newlog->criterium = ROT_WEEKLY;
896
} else if (!strcmp(start, "yearly")) {
897
*endtag = oldchar, start = endtag;
899
newlog->criterium = ROT_YEARLY;
900
} else if (!strcmp(start, "rotate")) {
901
*endtag = oldchar, start = endtag;
904
(configFile, lineNum, "rotate count", &start,
906
oldchar = *endtag, *endtag = '\0';
908
newlog->rotateCount = strtoul(start, &chptr, 0);
909
if (*chptr || newlog->rotateCount < 0) {
911
"%s:%d bad rotation count '%s'\n",
912
configFile, lineNum, start);
913
if (newlog != defConfig) {
914
*endtag = oldchar, start = endtag;
921
*endtag = oldchar, start = endtag;
923
} else if (!strcmp(start, "start")) {
924
*endtag = oldchar, start = endtag;
927
(configFile, lineNum, "start count", &start,
929
oldchar = *endtag, *endtag = '\0';
931
newlog->logStart = strtoul(start, &chptr, 0);
932
if (*chptr || newlog->logStart < 0) {
933
message(MESS_ERROR, "%s:%d bad start count '%s'\n",
934
configFile, lineNum, start);
935
if (newlog != defConfig) {
936
*endtag = oldchar, start = endtag;
943
*endtag = oldchar, start = endtag;
945
} else if (!strcmp(start, "maxage")) {
946
*endtag = oldchar, start = endtag;
949
(configFile, lineNum, "maxage count", &start,
951
oldchar = *endtag, *endtag = '\0';
953
newlog->rotateAge = strtoul(start, &chptr, 0);
954
if (*chptr || newlog->rotateAge < 0) {
955
message(MESS_ERROR, "%s:%d bad maximum age '%s'\n",
956
configFile, lineNum, start);
957
if (newlog != defConfig) {
958
*endtag = oldchar, start = endtag;
965
*endtag = oldchar, start = endtag;
967
} else if (!strcmp(start, "errors")) {
969
"%s: %d: the errors directive is deprecated and no longer used.\n",
970
configFile, lineNum);
971
} else if (!strcmp(start, "mail")) {
972
*endtag = oldchar, start = endtag;
973
freeLogItem(logAddress);
974
if (!(newlog->logAddress = readAddress(configFile, lineNum,
976
if (newlog != defConfig) {
983
} else if (!strcmp(start, "nomail")) {
984
freeLogItem(logAddress);
986
*endtag = oldchar, start = endtag;
987
} else if (!strcmp(start, "missingok")) {
988
newlog->flags |= LOG_FLAG_MISSINGOK;
990
*endtag = oldchar, start = endtag;
991
} else if (!strcmp(start, "nomissingok")) {
992
newlog->flags &= ~LOG_FLAG_MISSINGOK;
994
*endtag = oldchar, start = endtag;
995
} else if (!strcmp(start, "prerotate")) {
996
*endtag = oldchar, start = endtag;
1000
scriptStart = start;
1001
scriptDest = &newlog->pre;
1003
while (*start != '\n')
1005
} else if (!strcmp(start, "firstaction")) {
1006
*endtag = oldchar, start = endtag;
1008
freeLogItem (first);
1010
scriptStart = start;
1011
scriptDest = &newlog->first;
1013
while (*start != '\n')
1015
} else if (!strcmp(start, "postrotate")) {
1016
*endtag = oldchar, start = endtag;
1020
scriptStart = start;
1021
scriptDest = &newlog->post;
1023
while (*start != '\n')
1025
} else if (!strcmp(start, "lastaction")) {
1026
*endtag = oldchar, start = endtag;
1030
scriptStart = start;
1031
scriptDest = &newlog->last;
1033
while (*start != '\n')
1035
} else if (!strcmp(start, "tabooext")) {
1036
if (newlog != defConfig) {
1038
"%s:%d tabooext may not appear inside "
1039
"of log file definition\n", configFile,
1041
*endtag = oldchar, start = endtag;
1046
*endtag = oldchar, start = endtag;
1047
if (!isolateValue(configFile, lineNum, "tabooext", &start,
1049
oldchar = *endtag, *endtag = '\0';
1051
if (*start == '+') {
1053
while (isspace(*start) && *start)
1056
free_2d_array(tabooExts, tabooCount);
1058
tabooExts = malloc(1);
1063
while (!isspace(*chptr) && /* *chptr != ',' && */ *chptr)
1066
tabooExts = realloc(tabooExts, sizeof(*tabooExts) *
1068
tabooExts[tabooCount] = malloc(chptr - start + 1);
1069
strncpy(tabooExts[tabooCount], start,
1071
tabooExts[tabooCount][chptr - start] = '\0';
1079
while (isspace(*start) && *start)
1083
*endtag = oldchar, start = endtag;
1085
} else if (!strcmp(start, "include")) {
1086
if (newlog != defConfig) {
1088
"%s:%d include may not appear inside "
1089
"of log file definition\n", configFile,
1091
*endtag = oldchar, start = endtag;
1096
*endtag = oldchar, start = endtag;
1097
if (!isolateValue(configFile, lineNum, "include", &start,
1099
oldchar = *endtag, *endtag = '\0';
1101
message(MESS_DEBUG, "including %s\n", start);
1102
if (++recursion_depth > MAX_NESTING) {
1103
message(MESS_ERROR, "%s:%d include nesting too deep\n",
1104
configFile, lineNum);
1108
if (readConfigPath(start, defConfig)) {
1114
*endtag = oldchar, start = endtag;
1116
} else if (!strcmp(start, "olddir")) {
1117
*endtag = oldchar, start = endtag;
1119
freeLogItem (oldDir);
1121
if (!(newlog->oldDir = readPath(configFile, lineNum,
1122
"olddir", &start))) {
1123
if (newlog != defConfig) {
1131
if (stat(newlog->oldDir, &sb)) {
1132
message(MESS_ERROR, "%s:%d error verifying olddir "
1133
"path %s: %s\n", configFile, lineNum,
1134
newlog->oldDir, strerror(errno));
1135
free(newlog->oldDir);
1139
if (!S_ISDIR(sb.st_mode)) {
1140
message(MESS_ERROR, "%s:%d olddir path %s is not a "
1141
"directory\n", configFile, lineNum,
1143
free(newlog->oldDir);
1148
message(MESS_DEBUG, "olddir is now %s\n", newlog->oldDir);
1149
} else if (!strcmp(start, "extension")) {
1150
*endtag = oldchar, start = endtag;
1153
(configFile, lineNum, "extension name", &start,
1155
oldchar = *endtag, *endtag = '\0';
1157
freeLogItem (extension);
1158
newlog->extension = strdup(start);
1160
*endtag = oldchar, start = endtag;
1163
message(MESS_DEBUG, "extension is now %s\n",
1166
} else if (!strcmp(start, "compresscmd")) {
1167
*endtag = oldchar, start = endtag;
1169
freeLogItem (compress_prog);
1172
(newlog->compress_prog =
1173
readPath(configFile, lineNum, "compress", &start))) {
1174
if (newlog != defConfig) {
1182
if (access(newlog->compress_prog, X_OK)) {
1184
"%s:%d compression program %s is not an executable file\n",
1185
configFile, lineNum, newlog->compress_prog);
1186
if (newlog != defConfig) {
1194
message(MESS_DEBUG, "compress_prog is now %s\n",
1195
newlog->compress_prog);
1197
} else if (!strcmp(start, "uncompresscmd")) {
1198
*endtag = oldchar, start = endtag;
1200
freeLogItem (uncompress_prog);
1203
(newlog->uncompress_prog =
1204
readPath(configFile, lineNum, "uncompress",
1206
if (newlog != defConfig) {
1214
if (access(newlog->uncompress_prog, X_OK)) {
1216
"%s:%d uncompression program %s is not an executable file\n",
1217
configFile, lineNum, newlog->uncompress_prog);
1218
if (newlog != defConfig) {
1226
message(MESS_DEBUG, "uncompress_prog is now %s\n",
1227
newlog->uncompress_prog);
1229
} else if (!strcmp(start, "compressoptions")) {
1232
if (newlog->compress_options_list) {
1233
free(newlog->compress_options_list);
1234
newlog->compress_options_list = NULL;
1235
newlog->compress_options_count = 0;
1238
*endtag = oldchar, start = endtag;
1241
readPath(configFile, lineNum, "compressoptions",
1243
if (newlog != defConfig) {
1251
if (poptParseArgvString(options,
1252
&newlog->compress_options_count,
1253
&newlog->compress_options_list)) {
1255
"%s:%d invalid compression options\n",
1256
configFile, lineNum);
1258
if (newlog != defConfig) {
1266
message(MESS_DEBUG, "compress_options is now %s\n",
1269
} else if (!strcmp(start, "compressext")) {
1270
*endtag = oldchar, start = endtag;
1272
freeLogItem (compress_ext);
1275
(newlog->compress_ext =
1276
readPath(configFile, lineNum, "compress-ext",
1278
if (newlog != defConfig) {
1286
message(MESS_DEBUG, "compress_ext is now %s\n",
1287
newlog->compress_ext);
1289
message(MESS_ERROR, "%s:%d unknown option '%s' "
1290
"-- ignoring line\n", configFile, lineNum, start);
1292
*endtag = oldchar, start = endtag;
1295
while (isblank(*start))
1298
if (*start != '\n') {
1299
message(MESS_ERROR, "%s:%d unexpected text\n", configFile,
1301
while (*start != '\n')
1307
} else if (*start == '/' || *start == '"' || *start == '\'') {
1308
if (newlog != defConfig) {
1309
message(MESS_ERROR, "%s:%d unexpected log filename\n",
1310
configFile, lineNum);
1315
/* If no compression options were found in config file, set
1317
if (!newlog->compress_prog)
1318
newlog->compress_prog = strdup(COMPRESS_COMMAND);
1319
if (!newlog->uncompress_prog)
1320
newlog->uncompress_prog = strdup(UNCOMPRESS_COMMAND);
1321
if (!newlog->compress_ext)
1322
newlog->compress_ext = strdup(COMPRESS_EXT);
1324
/* Allocate a new logInfo structure and insert it into the logs
1325
queue, copying the actual values from defConfig */
1326
if ((newlog = newLogInfo(defConfig)) == NULL)
1330
while (*endtag != '{' && *endtag != '\0')
1332
if (*endtag != '{') {
1333
message(MESS_ERROR, "%s:%d missing end of line\n",
1334
configFile, lineNum);
1338
if (poptParseArgvString(start, &argc, &argv)) {
1339
message(MESS_ERROR, "%s:%d error parsing filename\n",
1340
configFile, lineNum);
1342
} else if (argc < 1) {
1344
"%s:%d { expected after log file name(s)\n",
1345
configFile, lineNum);
1349
newlog->files = NULL;
1350
newlog->numFiles = 0;
1351
for (argNum = 0; argNum < argc && logerror != 1; argNum++) {
1352
rc = glob(argv[argNum], GLOB_NOCHECK, globerr,
1354
if (rc == GLOB_ABORTED) {
1355
if (newlog->flags & LOG_FLAG_MISSINGOK)
1358
message(MESS_ERROR, "%s:%d glob failed for %s\n",
1359
configFile, lineNum, argv[argNum]);
1365
realloc(newlog->files,
1366
sizeof(*newlog->files) * (newlog->numFiles +
1370
for (i = 0; i < globResult.gl_pathc; i++) {
1371
/* if we glob directories we can get false matches */
1372
if (!lstat(globResult.gl_pathv[i], &sb) &&
1373
S_ISDIR(sb.st_mode))
1376
for (log = logs.tqh_first; log != NULL;
1377
log = log->list.tqe_next) {
1378
for (k = 0; k < log->numFiles; k++) {
1379
if (!strcmp(log->files[k],
1380
globResult.gl_pathv[i])) {
1382
"%s:%d duplicate log entry for %s\n",
1383
configFile, lineNum,
1384
globResult.gl_pathv[i]);
1391
newlog->files[newlog->numFiles] =
1392
strdup(globResult.gl_pathv[i]);
1396
globfree(&globResult);
1399
newlog->pattern = strdup(start);
1402
message(MESS_DEBUG, "reading config info for %s\n", start);
1407
} else if (*start == '}') {
1408
if (newlog == defConfig) {
1409
message(MESS_ERROR, "%s:%d unexpected }\n", configFile,
1414
if (newlog->oldDir) {
1415
for (i = 0; i < newlog->numFiles; i++) {
1417
dirName = ourDirName(newlog->files[i]);
1418
if (stat(dirName, &sb2)) {
1420
"%s:%d error verifying log file "
1421
"path %s: %s\n", configFile, lineNum,
1422
dirName, strerror(errno));
1426
ld = alloca(strlen(dirName) + strlen(newlog->oldDir) +
1428
sprintf(ld, "%s/%s", dirName, newlog->oldDir);
1431
if (newlog->oldDir[0] != '/')
1434
dirName = newlog->oldDir;
1435
if (stat(dirName, &sb)) {
1436
message(MESS_ERROR, "%s:%d error verifying olddir "
1437
"path %s: %s\n", configFile, lineNum,
1438
dirName, strerror(errno));
1442
if (sb.st_dev != sb2.st_dev) {
1444
"%s:%d olddir %s and log file %s "
1445
"are on different devices\n", configFile,
1446
lineNum, newlog->oldDir, newlog->files[i]);
1455
while (isblank(*start))
1458
if (*start != '\n') {
1459
message(MESS_ERROR, "%s:%d, unexpected text after {\n",
1460
configFile, lineNum);
1463
message(MESS_ERROR, "%s:%d lines must begin with a keyword "
1464
"or a filename (possibly in double quotes)\n",
1465
configFile, lineNum);
1467
while (*start != '\n')
1476
"%s:prerotate or postrotate without endscript\n",