~ubuntu-branches/ubuntu/edgy/logrotate/edgy

« back to all changes in this revision

Viewing changes to config.c

  • Committer: Bazaar Package Importer
  • Author(s): Paul Martin
  • Date: 2004-06-11 13:51:34 UTC
  • mfrom: (1.1.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20040611135134-xwwlztb186794ikt
Tags: 3.7-2
* Added commented out stuff in debian/rules to build a 
  logrotate-selinux package should Russell's move to get libselinux1 
  made "base" fail.
* Patch: 21-taboo-to-debug, reduces the "Ignoring..." messages of
  the taboo filter from ERROR to DEBUG. (Closes: #249073)
* Patch: 30-config-h, changed to fix upstream bug with mailing
  logs. (Closes: #253837)

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
#include <sys/stat.h>
14
14
#include <time.h>
15
15
#include <unistd.h>
 
16
#include <assert.h>
16
17
 
17
18
#include "basenames.h"
18
19
#include "log.h"
22
23
#define GLOB_ABORTED GLOB_ABEND
23
24
#endif
24
25
 
 
26
#define REALLOC_STEP    10
 
27
 
 
28
#if defined(SunOS) && !defined(isblank)
 
29
#define isblank(c)      ( (c) == ' ' || (c) == '\t' ) ? 1 : 0
 
30
#endif
 
31
 
25
32
static char * defTabooExts[] = { ".rpmsave", ".rpmorig", "~", ",v",
26
 
                                 ".disabled", ".dpkg-old", ".dpkg-dist",
27
 
                                 ".dpkg-new",
28
33
                                 ".rpmnew", ".swp" };
29
34
static int defTabooCount = sizeof(defTabooExts) / sizeof(char *);
30
35
 
35
40
static int readConfigFile(const char * configFile, logInfo * defConfig, 
36
41
                          logInfo ** logsPtr, int * numLogsPtr);
37
42
static int globerr(const char * pathname, int theerr);
 
43
static struct rotatePatternElement * parsePattern(const char * pattern,
 
44
                                        const char * configFile, int lineNum);
38
45
 
39
46
static int isolateValue(const char * fileName, int lineNum, char * key, 
40
47
                        char ** startPtr, char ** endPtr) {
127
134
        return NULL;
128
135
}
129
136
 
 
137
static int checkFile(const char * fname) {
 
138
    int i;
 
139
 
 
140
    /* Check if fname is '.' or '..'; if so, return false */
 
141
    if (fname[0] == '.' &&
 
142
        (!fname[1] || (fname[1] == '.' && !fname[2])))
 
143
        return 0;
 
144
 
 
145
    /* Check if fname is ending in a taboo-extension; if so, return
 
146
       false */
 
147
    for (i = 0; i < tabooCount; i++) {
 
148
        if (!strcmp(fname + strlen(fname) - strlen(tabooExts[i]),
 
149
            tabooExts[i])) {
 
150
            message(MESS_ERROR, "Ignoring %s, because of %s "
 
151
                    "ending\n", fname, tabooExts[i]);
 
152
 
 
153
            return 0;
 
154
        }
 
155
    }
 
156
 
 
157
      /* All checks have been passed; return true */
 
158
    return 1;
 
159
}
 
160
 
 
161
/* Used by qsort to sort filelist */
 
162
static int compar(const void *p, const void *q) {
 
163
        return  strcoll(*((char **)p), *((char **)q));
 
164
}
 
165
 
 
166
/* Free memory blocks pointed to by pointers in namelist and namelist itself */
 
167
static void free_namelist (char **namelist, int files_count)
 
168
{
 
169
    int i;
 
170
    for (i=0; i<files_count; ++i)
 
171
        free(namelist[i]);
 
172
    free(namelist);
 
173
}
 
174
 
 
175
static struct rotatePatternElement * parsePattern(const char * pattern,
 
176
                                        const char * configFile, int lineNum) {
 
177
    struct rotatePatternElement * head, * item;
 
178
    struct rotatePatternElement new;
 
179
    const char * field;
 
180
    const char * start;
 
181
 
 
182
    /* dummy head node; we build off of it */
 
183
    head = alloca(sizeof(*head));
 
184
    item = head;
 
185
 
 
186
    start = field = pattern;
 
187
    memset(&new, 0, sizeof(new));
 
188
    while (*field) {
 
189
        if (*field != '%') {
 
190
            field++;
 
191
            continue;
 
192
        }
 
193
 
 
194
        switch (*field) {
 
195
          case '%':
 
196
            break;
 
197
          case 'f':
 
198
            new.type = RP_FILENAME;
 
199
            break;
 
200
          case 'c':
 
201
            new.type = RP_COUNT;
 
202
            break;
 
203
          default:
 
204
            message(MESS_ERROR, "%s:%d unknown element %c in pattern %s",
 
205
                    configFile, lineNum, *field, pattern);
 
206
            return NULL;
 
207
        }
 
208
 
 
209
        if (new.type != RP_NONE) {
 
210
            if (start != field) {
 
211
                /* fixed string */
 
212
                item->next = malloc(sizeof(*item->next));
 
213
                item->type = RP_STRING;
 
214
                item->arg = malloc(field - start + 1);
 
215
                strncpy(item->arg, start, field - start);
 
216
                item->arg[field-start] = '\0';
 
217
                item = item->next;
 
218
            }
 
219
 
 
220
            item->next = malloc(sizeof(*item->next));
 
221
            *item->next = new;
 
222
            item = item->next;
 
223
 
 
224
            memset(&new, 0, sizeof(new));
 
225
        }
 
226
 
 
227
        field++;
 
228
    }
 
229
 
 
230
    if (start != field) {
 
231
        /* fixed string */
 
232
        item->next = malloc(sizeof(*item->next));
 
233
        item->type = RP_STRING;
 
234
        item->arg = malloc(field - start + 1);
 
235
        strncpy(item->arg, start, field-start);
 
236
        item->arg[field-start] = '\0';
 
237
        item = item->next;
 
238
    }
 
239
    
 
240
    return NULL;
 
241
}
 
242
 
130
243
int readConfigPath(const char * path, logInfo * defConfig, 
131
244
                          logInfo ** logsPtr, int * numLogsPtr) {
132
245
    struct stat sb;
133
 
    DIR * dir;
134
 
    struct dirent * ent;
135
246
    int here;
136
 
    int i;
137
247
 
138
248
    if (!tabooExts) {
139
249
        tabooExts = malloc(sizeof(*tabooExts) * defTabooCount);
147
257
    }
148
258
 
149
259
    if (S_ISDIR(sb.st_mode)) {
150
 
        dir = opendir(path);
151
 
        if (!dir) {
152
 
            message(MESS_ERROR, "failed to open directory %s: %s\n", path,
153
 
                        strerror(errno));
154
 
            return 1;
155
 
        }
 
260
        char            **namelist, **p;
 
261
        struct dirent   *dp;
 
262
        int             files_count,i;
 
263
        DIR             *dirp;
156
264
 
157
265
        here = open(".", O_RDONLY);
158
266
        if (here < 0) {
159
267
            message(MESS_ERROR, "cannot open current directory: %s\n", 
160
268
                    strerror(errno));
161
 
            closedir(dir);
162
 
            return 1;
 
269
            return 1;
 
270
        }
 
271
 
 
272
        if ( (dirp = opendir(path)) == NULL) {
 
273
            message(MESS_ERROR, "cannot open directory %s: %s\n", path,
 
274
                    strerror(errno));
 
275
            return 1;
 
276
        }
 
277
        files_count = 0;
 
278
        namelist = NULL;
 
279
        while ((dp = readdir(dirp)) != NULL) {
 
280
            if (checkFile(dp->d_name)) {
 
281
                /* Realloc memory for namelist array if necessary */
 
282
                if (files_count % REALLOC_STEP == 0) {
 
283
                    p = (char **) realloc(namelist, (files_count + REALLOC_STEP) * sizeof(char *));
 
284
                    if (p) {
 
285
                        namelist = p;
 
286
                        memset(namelist + files_count, '\0', REALLOC_STEP * sizeof(char *));
 
287
                    } else {
 
288
                        free_namelist(namelist, files_count);
 
289
                        message(MESS_ERROR, "cannot realloc: %s\n", strerror(errno));
 
290
                        return 1;
 
291
                    }
 
292
                }
 
293
                /* Alloc memory for file name */
 
294
                if ( (namelist[files_count] = (char *) malloc( strlen(dp->d_name) + 1)) ) {
 
295
                    strcpy(namelist[files_count], dp->d_name);
 
296
                    files_count++;
 
297
                } else {
 
298
                    free_namelist(namelist, files_count);
 
299
                    message(MESS_ERROR, "cannot realloc: %s\n", strerror(errno));
 
300
                    return 1;
 
301
                }
 
302
            }
 
303
        }
 
304
        closedir( dirp );
 
305
 
 
306
        if (files_count > 0) {
 
307
            qsort(namelist, files_count, sizeof(char *), compar);
 
308
        } else {
 
309
            return 0;
163
310
        }
164
311
 
165
312
        if (chdir(path)) {
166
313
            message(MESS_ERROR, "error in chdir(\"%s\"): %s\n", path,
167
314
                    strerror(errno));
168
315
            close(here);
169
 
            closedir(dir);
 
316
            free_namelist(namelist, files_count);
170
317
            return 1;
171
318
        }
172
319
 
173
 
        do {
174
 
            errno = 0;
175
 
            ent = readdir(dir);
176
 
            if (errno) {
177
 
                message(MESS_ERROR, "readdir() from %s failed: %s\n", path,
178
 
                        strerror(errno));
179
 
                fchdir(here);
180
 
                close(here);
181
 
                closedir(dir);
182
 
                return 1;
183
 
            } else if (ent && ent->d_name[0] == '.' && (!ent->d_name[1] || 
184
 
                (ent->d_name[1] == '.' && !ent->d_name[2]))) {
185
 
                /* noop */
186
 
            } else if (ent) {
187
 
                for (i = 0; i < tabooCount; i++) {
188
 
                    if (!strcmp(ent->d_name + strlen(ent->d_name) -
189
 
                                strlen(tabooExts[i]), tabooExts[i])) {
190
 
                        message(MESS_DEBUG, "Ignoring %s, because of %s "
191
 
                                "ending\n", ent->d_name, tabooExts[i]);
192
 
                        break;
193
 
                    }
194
 
                }
195
 
 
196
 
                if (i == tabooCount) {
197
 
                    if (readConfigFile(ent->d_name, defConfig, logsPtr, 
198
 
                                       numLogsPtr)) {
199
 
                        fchdir(here);
200
 
                        close(here);
201
 
                        return 1;
202
 
                    }
203
 
                }
204
 
            }
205
 
        } while (ent);
206
 
 
207
 
        closedir(dir);
 
320
        for (i=0; i<files_count; ++i) {
 
321
          assert(namelist[i] != NULL);
 
322
          
 
323
          if (readConfigFile(namelist[i], defConfig, logsPtr, 
 
324
                             numLogsPtr)) {
 
325
            fchdir(here);
 
326
            close(here);
 
327
            free_namelist(namelist, files_count);
 
328
            return 1;
 
329
          }
 
330
        };
208
331
 
209
332
        fchdir(here);
210
333
        close(here);
 
334
        free_namelist(namelist, files_count);
211
335
    } else {
212
336
        return readConfigFile(path, defConfig, logsPtr, numLogsPtr);
213
337
    }
217
341
 
218
342
static int globerr(const char * pathname, int theerr) {
219
343
    message(MESS_ERROR, "error accessing %s: %s\n", pathname, 
220
 
            strerror(theerr));
 
344
            strerror(theerr));
221
345
 
222
 
    /* We want the glob operation to continue, so return 0 */
 
346
    /* We want the glob operation to abort on error, so return 1 */
223
347
    return 1;
224
348
}
225
349
 
371
495
                newlog->flags &= ~LOG_FLAG_COPYTRUNCATE;
372
496
 
373
497
                *endtag = oldchar, start = endtag;
 
498
            } else if (!strcmp(start, "copy")) {
 
499
                newlog->flags |= LOG_FLAG_COPY;
 
500
 
 
501
                *endtag = oldchar, start = endtag;
 
502
            } else if (!strcmp(start, "nocopy")) {
 
503
                newlog->flags &= ~LOG_FLAG_COPY;
 
504
 
 
505
                *endtag = oldchar, start = endtag;
374
506
            } else if (!strcmp(start, "ifempty")) {
375
507
                newlog->flags |= LOG_FLAG_IFEMPTY;
376
508
 
453
585
                    } else if (start[length] == 'M') {
454
586
                        start[length] = '\0';
455
587
                        multiplier = 1024 * 1024;
 
588
                    } else if (start[length] == 'G') {
 
589
                        start[length] = '\0';
 
590
                        multiplier = 1024 * 1024 * 1024;
456
591
                    } else if (!isdigit(start[length])) {
457
592
                        message(MESS_ERROR, "%s:%d unknown unit '%c'\n",
458
593
                                    configFile, lineNum, start[length]);
520
655
                    }
521
656
                    *endtag = oldchar, start = endtag;
522
657
                }
 
658
            } else if (!strcmp(start, "start")) {
 
659
                *endtag = oldchar, start = endtag;
 
660
 
 
661
                if (!isolateValue(configFile, lineNum, "start count", &start,
 
662
                                  &endtag)) {
 
663
                    oldchar = *endtag, *endtag = '\0';
 
664
 
 
665
                    newlog->logStart = strtoul(start, &chptr, 0);
 
666
                    if (*chptr || newlog->logStart < 0) {
 
667
                      message(MESS_ERROR, "%s:%d bad start count '%s'\n",
 
668
                              configFile, lineNum, start);
 
669
                      return 1;
 
670
                    }
 
671
                    *endtag = oldchar, start = endtag;
 
672
                }
523
673
            } else if (!strcmp(start, "errors")) {
524
674
                message(MESS_DEBUG, "%s: %d: the errors directive is deprecated and no longer used.\n",
525
675
                        configFile, lineNum);
526
676
            } else if (!strcmp(start, "mail")) {
527
677
                *endtag = oldchar, start = endtag;
528
678
                if (!(newlog->logAddress = readAddress(configFile, lineNum, 
529
 
                                                        "mail", &start))) {
 
679
                                                        "mail", &start))) {
530
680
                    return 1;
531
681
                }
532
682
            } else if (!strcmp(start, "nomail")) {
549
699
                scriptDest = &newlog->pre;
550
700
 
551
701
                while (*start != '\n') start++;
 
702
            } else if (!strcmp(start, "firstaction")) {
 
703
                *endtag = oldchar, start = endtag;
 
704
 
 
705
                scriptStart = start;
 
706
                scriptDest = &newlog->first;
 
707
 
 
708
                while (*start != '\n') start++;
552
709
            } else if (!strcmp(start, "postrotate")) {
553
710
                *endtag = oldchar, start = endtag;
554
711
 
556
713
                scriptDest = &newlog->post;
557
714
 
558
715
                while (*start != '\n') start++;
 
716
            } else if (!strcmp(start, "lastaction")) {
 
717
                *endtag = oldchar, start = endtag;
 
718
 
 
719
                scriptStart = start;
 
720
                scriptDest = &newlog->last;
 
721
 
 
722
                while (*start != '\n') start++;
559
723
            } else if (!strcmp(start, "tabooext")) {
560
724
                if (newlog != defConfig) {
561
725
                    message(MESS_ERROR, "%s:%d tabooext may not appear inside "
564
728
                }
565
729
 
566
730
                *endtag = oldchar, start = endtag;
567
 
                if (!isolateValue(configFile, lineNum, "size", &start, 
 
731
                if (!isolateValue(configFile, lineNum, "tabooext", &start, 
568
732
                                  &endtag)) {
569
733
                    oldchar = *endtag, *endtag = '\0';
570
734
 
579
743
 
580
744
                    while (*start) {
581
745
                        chptr = start;
582
 
                        while (!isspace(*chptr) && /* *chptr != ',' && */ *chptr)
 
746
                        while (!isspace(*chptr) && *chptr != ',' && *chptr)
583
747
                            chptr++;
584
748
 
585
749
                        tabooExts = realloc(tabooExts, sizeof(*tabooExts) * 
591
755
                        tabooCount++;
592
756
 
593
757
                        start = chptr;
594
 
                        /* if (*start == ',') start++; */
 
758
                        if (*start == ',') start++;
595
759
                        while (isspace(*start) && *start) start++;
596
760
                    }
597
761
 
605
769
                }
606
770
 
607
771
                *endtag = oldchar, start = endtag;
608
 
                if (!isolateValue(configFile, lineNum, "size", &start, 
 
772
                if (!isolateValue(configFile, lineNum, "include", &start, 
609
773
                                  &endtag)) {
610
774
                    oldchar = *endtag, *endtag = '\0';
611
775
 
617
781
 
618
782
                    *endtag = oldchar, start = endtag;
619
783
                }
 
784
            } else if (!strcmp(start, "pattern")) {
 
785
                char * patternString;
 
786
 
 
787
                *endtag = oldchar, start = endtag;
 
788
                if (!(patternString = readPath(configFile, lineNum,
 
789
                                                "pattern", &start))) {
 
790
                    return 1;
 
791
                }
 
792
 
 
793
                newlog->rotatePattern = parsePattern(patternString,
 
794
                                            configFile, lineNum);
 
795
                if (!newlog->rotatePattern) return 1;
 
796
 
 
797
                message(MESS_DEBUG, "pattern is now %s\n", patternString);
620
798
            } else if (!strcmp(start, "olddir")) {
621
799
                *endtag = oldchar, start = endtag;
622
800
                if (!(newlog->oldDir = readPath(configFile, lineNum,
624
802
                    return 1;
625
803
                }
626
804
 
 
805
#if 0
627
806
                if (stat(newlog->oldDir, &sb)) {
628
807
                    message(MESS_ERROR, "%s:%d error verifying olddir "
629
808
                                "path %s: %s\n", configFile, lineNum, 
637
816
                                newlog->oldDir);
638
817
                    return 1;
639
818
                }
 
819
#endif
640
820
 
641
821
                message(MESS_DEBUG, "olddir is now %s\n", newlog->oldDir);
642
822
            } else if (!strcmp(start, "extension")) {
682
862
                message(MESS_DEBUG, "uncompress_prog is now %s\n", newlog->uncompress_prog);
683
863
 
684
864
            } else if (!strcmp(start, "compressoptions")) {
 
865
                char * options;
 
866
 
685
867
                *endtag = oldchar, start = endtag;
686
 
                if (!(newlog->compress_options = readPath(configFile, lineNum, "compressoptions", &start))) {
687
 
                    return 1;
688
 
                }
689
 
 
690
 
                message(MESS_DEBUG, "compress_options is now %s\n", newlog->compress_options);
691
 
 
 
868
                if (!(options = readPath(configFile, lineNum, "compressoptions", &start))) {
 
869
                    return 1;
 
870
                }
 
871
 
 
872
                if (poptParseArgvString(options, 
 
873
                                        &newlog->compress_options_count,
 
874
                                        &newlog->compress_options_list)) {
 
875
                    message(MESS_ERROR, "%s:%d invalid compression options\n", 
 
876
                            configFile, lineNum);
 
877
                    return 1;
 
878
                }
 
879
 
 
880
                message(MESS_DEBUG, "compress_options is now %s\n", options);
692
881
            } else if (!strcmp(start, "compressext")) {
693
882
                *endtag = oldchar, start = endtag;
694
883
                if (!(newlog->compress_ext = readPath(configFile, lineNum, "compress-ext", &start))) {
749
938
            for (argNum = 0; argNum < argc; argNum++) {
750
939
                rc = glob(argv[argNum], GLOB_NOCHECK, globerr, &globResult);
751
940
                if (rc == GLOB_ABORTED) {
 
941
                    if(newlog->flags & LOG_FLAG_MISSINGOK)
 
942
                        continue;
 
943
 
752
944
                    message(MESS_ERROR, "%s:%d glob failed for %s\n",
753
945
                            configFile, lineNum, argv[argNum]);
754
946
                    return 1;
796
988
            }
797
989
 
798
990
            if (newlog->oldDir) {
799
 
                if (stat(newlog->oldDir, &sb)) {
800
 
                    message(MESS_ERROR, "%s:%d error verifying olddir "
801
 
                                "path %s: %s\n", configFile, lineNum, 
802
 
                                newlog->oldDir, strerror(errno));
803
 
                    return 1;
804
 
                }
805
 
 
806
991
                for (i = 0; i < newlog->numFiles; i++) {
 
992
                    char *ld;
807
993
                    dirName = ourDirName(newlog->files[i]);
808
994
                    if (stat(dirName, &sb2)) {
809
995
                        message(MESS_ERROR, "%s:%d error verifying log file "
812
998
                        free(dirName);
813
999
                        return 1;
814
1000
                    }
815
 
 
 
1001
                    ld = alloca(strlen(dirName) + strlen(newlog->oldDir) + 2);
 
1002
                    sprintf(ld, "%s/%s", dirName, newlog->oldDir);
816
1003
                    free(dirName);
817
1004
 
 
1005
                    if(newlog->oldDir[0] != '/') dirName = ld;
 
1006
                    else dirName = newlog->oldDir;
 
1007
                    if(stat(dirName, &sb)) {
 
1008
                        message(MESS_ERROR, "%s:%d error verifying olddir "
 
1009
                                "path %s: %s\n", configFile, lineNum,
 
1010
                                dirName, strerror(errno));
 
1011
                                return 1;
 
1012
                    }
 
1013
 
818
1014
                    if (sb.st_dev != sb2.st_dev) {
819
1015
                        message(MESS_ERROR, "%s:%d olddir %s and log file %s "
820
1016
                                    "are on different devices\n", configFile,
844
1040
        }
845
1041
    }
846
1042
 
 
1043
    if(scriptStart) {
 
1044
      message(MESS_ERROR, "%s:prerotate or postrotate without endscript\n",
 
1045
              configFile);
 
1046
      return 1;
 
1047
    }
 
1048
 
847
1049
    return 0;
848
1050
}
849
1051