Subversion Repositories SvarDOS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
219 mateuszvis 1
/*
2
 * This file is part of FDNPKG.
3
 *
4
 * Loads the list of repositories from the config file specified in %FDNPKG%.
5
 * Returns the amount of repositories found (and loaded) on success, or -1 on failure.
6
 *
7
 * Copyright (C) 2012-2016 Mateusz Viste
8
 */
9
 
10
#include <stdio.h>  /* printf(), fclose(), fopen()... */
11
#include <string.h> /* strcasecmp() */
12
#include <stdlib.h> /* malloc(), free() */
13
 
14
#include "crc32.h"  /* crc32() */
15
#include "fdnpkg.h" /* PKGINST_NOSOURCE, PKGINST_SKIPLINKS... */
16
#include "helpers.h" /* slash2backslash(), removeDoubleBackslashes()... */
17
#include "kprintf.h"
18
#include "loadconf.h"
19
#include "parsecmd.h"
20
#include "version.h"
21
 
22
 
23
void freeconf(char **repolist, int repscount, struct customdirs **dirlist) {
24
  int x;
25
  struct customdirs *curpos;
26
  /* free repolist */
27
  for (x = 0; x < repscount; x++) free(repolist[x]);
28
  /* free the linked list of custom dirs */
29
  while (*dirlist != NULL) {
30
    curpos = *dirlist;
31
    if (curpos->name != NULL) free(curpos->name);
32
    if (curpos->location != NULL) free(curpos->location);
33
    *dirlist = (*dirlist)->next;
34
    free(curpos);
35
  }
36
  *dirlist = NULL;
37
}
38
 
39
 
40
static int checkfordoubledrepos(char **repolist, int repocount) {
41
  int x, y;
42
  for (x = 0; x < (repocount - 1); x++) {
43
    for (y = x + 1; y < repocount; y++) {
44
      if (strcmp(repolist[x], repolist[y]) == 0) {
45
        kitten_printf(7, 14, "Error: repository '%s' is listed twice!", repolist[x]);
46
        puts("");
47
        return(-1);
48
      }
49
    }
50
  }
51
  return(0);
52
}
53
 
54
 
55
static int checkfordoubledirlist(struct customdirs *dirlist) {
56
  struct customdirs *curpos;
57
  for (; dirlist != NULL; dirlist = dirlist->next) {
58
    for (curpos = dirlist->next; curpos != NULL; curpos = curpos->next) {
59
      if (strcasecmp(curpos->name, dirlist->name) == 0) {
60
        kitten_printf(7, 0, "Error: custom dir '%s' is listed twice!", curpos->name);
61
        puts("");
62
        return(-1);
63
      }
64
    }
65
  }
66
  return(0);
67
}
68
 
69
 
70
/* validates dirlist entries: check that they are absolute paths and are not using restricted names */
71
static int validatedirlist(struct customdirs *dirlist) {
72
  for (; dirlist != NULL; dirlist = dirlist->next) {
73
    /* the location must be at least 3 characters long to be a valid absolute path (like 'c:\')*/
74
    if (strlen(dirlist->location) < 3) {
75
      kitten_printf(7, 15, "Error: custom dir '%s' is not a valid absolute path!", dirlist->name);
76
      puts("");
77
      return(-1);
78
    }
79
    /* is it a valid absolute path? should start with [a..Z]:\ */
80
    if ((dirlist->location[1] != ':') ||
81
       ((dirlist->location[2] != '/') && (dirlist->location[2] != '\\')) ||
82
       (((dirlist->location[0] < 'a') || (dirlist->location[0] > 'z')) && ((dirlist->location[0] < 'A') || (dirlist->location[0] > 'Z')))) {
83
      kitten_printf(7, 15, "Error: custom dir '%s' is not a valid absolute path!", dirlist->name);
84
      puts("");
85
      return(-1);
86
    }
87
    /* check for forbidden names */
88
    if ((strcasecmp(dirlist->name, "appinfo") == 0) ||
89
        (strcasecmp(dirlist->name, "bin") == 0) ||
90
        (strcasecmp(dirlist->name, "doc") == 0) ||
91
        (strcasecmp(dirlist->name, "help") == 0) ||
92
        (strcasecmp(dirlist->name, "nls") == 0) ||
93
        (strcasecmp(dirlist->name, "packages") == 0)) {
94
      kitten_printf(7, 16, "Error: custom dir '%s' is a reserved name!", dirlist->name);
95
      puts("");
96
      return(-1);
97
    }
98
  }
99
  return(0);
100
}
101
 
102
 
103
/* add (and allocates) a new custom dir entry to dirlist. Returns 0 on success,
104
   or non-zero on failure (failures happen on out of memory events). */
105
static int addnewdir(struct customdirs **dirlist, char *name, char *location) {
106
  struct customdirs *newentry;
107
  newentry = malloc(sizeof(struct customdirs));
108
  if (newentry == NULL) return(-1);
109
  newentry->name = malloc(strlen(name) + 1);
110
  if (newentry->name == NULL) {
111
    free(newentry);
112
    return(-1);
113
  }
114
  newentry->location = malloc(strlen(location) + 1);
115
  if (newentry->location == NULL) {
116
    free(newentry->name);
117
    free(newentry);
118
    return(-1);
119
  }
120
  strcpy(newentry->name, name);
121
  strcpy(newentry->location, location);
122
  newentry->next = *dirlist;
123
  *dirlist = newentry;
124
  return(0);
125
}
126
 
127
 
128
int loadconf(char *cfgfile, char **repolist, int maxreps, unsigned long *crc32val, long *maxcachetime, struct customdirs **dirlist, int *flags, char **proxy, int *proxyport, char **mapdrv) {
129
  int bytebuff, parserstate = 0;
130
  FILE *fd;
131
  #define BUFFSIZE 1024
132
  unsigned char *fbuff;
133
  #define maxtok 16
134
  char token[maxtok];
135
  #define maxval 1024
136
  char value[maxval];
137
  int curtok = 0, curval = 0, nline = 1;
138
  int repocount = 0;
139
  int buffread;
140
 
141
  fd = fopen(cfgfile, "r");
142
  if (fd == NULL) {
143
    kitten_printf(7, 1, "Error: Could not open config file '%s'!", cfgfile);
144
    puts("");
145
    return(-1);
146
  }
147
 
148
  /* compute the CRC32 of the configuration file (if crc32val not NULL) */
149
  if (crc32val != NULL) {
150
    fbuff = malloc(BUFFSIZE);
151
    if (fbuff == NULL) {
152
      fclose(fd);
153
      kitten_printf(2, 14, "Out of memory! (%s)", "fbuff malloc");
154
      puts("");
155
      puts("");
156
      return(-1);
157
    }
158
    *crc32val = crc32_init();
159
    while ((buffread = fread(fbuff, sizeof(char), BUFFSIZE, fd)) > 0) {
160
      if (buffread > 0) crc32_feed(crc32val, fbuff, buffread);
161
    }
162
    crc32_finish(crc32val);
163
    free(fbuff);
164
  }
165
  /* rewind the file, to start reading it again */
166
  rewind(fd);
167
 
168
  /* read the config file line by line */
169
  do {
170
    bytebuff = fgetc(fd);
171
    if (bytebuff != '\r') {
172
      switch (parserstate) {
173
        case 0: /* Looking for start of line */
174
          if ((bytebuff == EOF) || (bytebuff == ' ') || (bytebuff == '\t')) break;
175
          if (bytebuff == '\n') {
176
            nline += 1;
177
            break;
178
          }
179
          if (bytebuff == '#') {
180
              parserstate = 9;
181
            } else {
182
              token[0] = bytebuff;
183
              curtok = 1;
184
              parserstate = 1;
185
          }
186
          break;
187
        case 1: /* Looking for token end */
188
          if ((bytebuff == EOF) || (bytebuff == '\n')) {
189
            kitten_printf(7, 2, "Warning: token without value on line #%d", nline);
190
            puts("");
191
            if (bytebuff == '\n') nline += 1;
192
            parserstate = 0;
193
            break;
194
          }
195
          if ((bytebuff == ' ') || (bytebuff == '\t')) {
196
              token[curtok] = 0;
197
              parserstate = 2;
198
            } else {
199
              token[curtok] = bytebuff;
200
              curtok += 1;
201
              if (curtok >= maxtok) {
202
                parserstate = 9; /* ignore the line */
203
                kitten_printf(7, 3, "Warning: Config file token overflow on line #%d", nline);
204
                puts("");
205
              }
206
          }
207
          break;
208
        case 2: /* Looking for value start */
209
          if ((bytebuff == EOF) || (bytebuff == '\n')) {
210
            kitten_printf(7, 4, "Warning: token with empty value on line #%d", nline);
211
            puts("");
212
            if (bytebuff == '\n') nline += 1;
213
            parserstate = 0;
214
            break;
215
          }
216
          if ((bytebuff != ' ') && (bytebuff != '\t')) {
217
            value[0] = bytebuff;
218
            curval = 1;
219
            parserstate = 3;
220
          }
221
          break;
222
        case 3: /* Looking for value end */
223
          if ((bytebuff == EOF) || (bytebuff == '\n')) {
224
              parserstate = 0;
225
              value[curval] = 0;
226
              if ((value[curval - 1] == ' ') || (value[curval - 1] == '\t')) {
227
                kitten_printf(7, 5, "Warning: trailing white-space(s) after value on line #%d", nline);
228
                puts("");
229
                while ((value[curval - 1] == ' ') || (value[curval - 1] == '\t')) value[--curval] = 0;
230
              }
231
              /* Interpret the token/value pair now! */
232
              /* printf("token='%s' ; value = '%s'\n", token, value); */
233
              if (strcasecmp(token, "REPO") == 0) { /* Repository declaration */
234
                  if (maxreps == 0) {
235
                      /* simply ignore if the app explicitely wishes to load no repositories */
236
                    } else if (repocount >= maxreps) {
237
                      kitten_printf(7, 6, "Dropped a repository: too many configured (max=%d)", maxreps);
238
                      puts("");
239
                    } else {
240
                      char pathdelimchar;
241
                      /* add a trailing path delimiter (slash or backslash) to the url if not there already */
242
                      if (detect_localpath(value) != 0) {
243
                          pathdelimchar = '\\';
244
                        } else {
245
                          pathdelimchar = '/';
246
                      }
247
                      if ((value[curval - 1] != '/') && (value[curval - 1] != '\\')) {
248
                        value[curval++] = pathdelimchar;
249
                        value[curval] = 0;
250
                      }
251
                      /* copy the value into the repository list */
252
                      repolist[repocount] = strdup(value);
253
                      if (repolist[repocount] == NULL) {
254
                        kitten_printf(2, 14, "Out of memory! (%s)", "repolist malloc");
255
                        puts("");
256
                        freeconf(repolist, repocount, dirlist);
257
                        fclose(fd);
258
                        return(-1);
259
                      }
260
                      repocount += 1;
261
                  }
262
                } else if (strcasecmp(token, "MAPDRIVES") == 0) {
263
                  *mapdrv = strdup(value);
264
                  if ((*mapdrv != NULL) && strlen(*mapdrv) & 1) {
265
                    free(*mapdrv);
266
                    *mapdrv = NULL;
267
                  }
268
                  if (*mapdrv == NULL) *mapdrv = "";
269
                } else if (strcasecmp(token, "MAXCACHETIME") == 0) {
270
                  long tmpint = atol(value);
271
                  if ((tmpint >= 0) && (tmpint < 1209600l)) { /* min 0s / max 2 weeks */
272
                      if (maxcachetime != NULL) *maxcachetime = tmpint;
273
                    } else {
274
                      kitten_printf(7, 10, "Warning: Ignored an illegal '%s' value at line #%d", "maxcachetime", nline);
275
                      puts("");
276
                  }
277
                } else if (strcasecmp(token, "INSTALLSOURCES") == 0) {
278
                  int tmpint = atoi(value); /* must be 0/1 */
279
                  if (tmpint == 0) {
280
                    *flags |= PKGINST_NOSOURCE;
281
                  } else if (tmpint == 1) {
282
                    /* do nothing */
283
                  } else {
284
                    kitten_printf(7, 10, "Warning: Ignored an illegal '%s' value at line #%d", "installsources", nline);
285
                    puts("");
286
                  }
287
                } else if (strcasecmp(token, "SKIPLINKS") == 0) {
288
                  int tmpint = atoi(value); /* must be 0/1 */
289
                  if (tmpint == 0) {
290
                    /* do nothing */
291
                  } else if (tmpint == 1) {
292
                    *flags |= PKGINST_SKIPLINKS;
293
                  } else {
294
                    kitten_printf(7, 10, "Warning: Ignored an illegal '%s' value at line #%d", "skiplinks", nline);
295
                    puts("");
296
                  }
297
                } else if (strcasecmp(token, "HTTP_PROXY") == 0) {
298
                  if (value[0] != 0) {
299
                      if (proxy != NULL) *proxy = strdup(value);
300
                    } else {
301
                      kitten_printf(7, 10, "Warning: Ignored an illegal '%s' value at line #%d", "http_proxy", nline);
302
                      puts("");
303
                  }
304
                } else if (strcasecmp(token, "HTTP_PROXYPORT") == 0) {
305
                  int tmpint = atoi(value);
306
                  if (tmpint != 0) {
307
                      if (proxyport != NULL) *proxyport = tmpint;
308
                    } else {
309
                      kitten_printf(7, 10, "Warning: Ignored an illegal '%s' value at line #%d", "http_proxyport", nline);
310
                      puts("");
311
                  }
312
                } else if (strcasecmp(token, "DIR") == 0) { /* custom repository entry */
313
                  char *argv[2], *evar, *evar_content, *realLocation;
314
                  #define realLocation_len 512
315
                  int x, y;
316
                  if (parsecmd(value, argv, 2) != 2) {
317
                    kitten_printf(7, 11, "Warning: Invalid 'DIR' directive found at line #%d", nline);
318
                    puts("");
319
                  }
320
                  realLocation = malloc(realLocation_len);
321
                  if (realLocation == NULL) {
322
                    kitten_printf(2, 14, "Out of memory! (%s)", "malloc realLocation");
323
                    puts("");
324
                    freeconf(repolist, repocount, dirlist);
325
                    fclose(fd);
326
                    return(-1);
327
                  }
328
                  realLocation[0] = 0; /* force it to be empty, since we might use strcat() on this later! */
329
                  /* resolve possible env variables */
330
                  evar = NULL;
331
                  y = 0;
332
                  for (x = 0; argv[1][x] != 0; x++) {
333
                    if (evar == NULL) { /* searching for % and copying */
334
                        if (argv[1][x] == '%') {
335
                            evar = &argv[1][x+1];
336
                          } else {
337
                            if (y + 1 > realLocation_len) {
338
                              kitten_printf(7, 12, "Error: DIR path too long at line #%d", nline);
339
                              puts("");
340
                              freeconf(repolist, repocount, dirlist);
341
                              free(realLocation);
342
                              fclose(fd);
343
                              return(-1);
344
                            }
345
                            realLocation[y] = argv[1][x]; /* copy over */
346
                            y++;
347
                            realLocation[y] = 0; /* make sure to terminate the string at any time */
348
                        }
349
                      } else { /* reading a % variable */
350
                        if (argv[1][x] == '%') {
351
                          argv[1][x] = 0;
352
                          evar_content = getenv(evar);
353
                          if (evar_content == NULL) {
354
                            kitten_printf(7, 13, "Error: Found inexisting environnement variable '%s' at line #%d", evar, nline);
355
                            puts("");
356
                            freeconf(repolist, repocount, dirlist);
357
                            free(realLocation);
358
                            fclose(fd);
359
                            return(-1);
360
                          }
361
                          if (strlen(evar_content) + y + 1 > realLocation_len) {
362
                            kitten_printf(7, 12, "Error: DIR path too long at line #%d", nline);
363
                            puts("");
364
                            freeconf(repolist, repocount, dirlist);
365
                            free(realLocation);
366
                            fclose(fd);
367
                            return(-1);
368
                          }
369
                          strcat(realLocation, evar_content);
370
                          y += strlen(evar_content);
371
                          evar = NULL;
372
                        }
373
                    }
374
                  }
375
                  /* add the entry to the list */
376
                  slash2backslash(realLocation);
377
                  removeDoubleBackslashes(realLocation);
378
                  if (realLocation[strlen(realLocation) - 1] != '\\') strcat(realLocation, "\\"); /* make sure to end dirs with a backslash */
379
                  if (addnewdir(dirlist, argv[0], realLocation) != 0) {
380
                    kitten_printf(2, 14, "Out of memory! (%s)", "addnewdir");
381
                    puts("");
382
                    freeconf(repolist, repocount, dirlist);
383
                    free(realLocation);
384
                    fclose(fd);
385
                    return(-1);
386
                  }
387
                  free(realLocation);
388
                } else { /* unknown token */
389
                  kitten_printf(7, 8, "Warning: Unknown token '%s' at line #%d", token, nline);
390
                  puts("");
391
              }
392
              /* interpretation done */
393
              if (bytebuff == '\n') nline += 1;
394
            } else {
395
              value[curval] = bytebuff;
396
              curval += 1;
397
              if ((curval + 1) >= maxval) {
398
                parserstate = 9; /* ignore the line */
399
                kitten_printf(7, 9, "Warning: Config file value overflow on line #%d", nline);
400
                puts("");
401
              }
402
          }
403
          break;
404
        case 9: /* Got comment, ignoring the rest of line */
405
          if (bytebuff == EOF) break;
406
          if (bytebuff == '\n') {
407
            nline += 1;
408
            parserstate = 0;
409
          }
410
          break;
411
      }
412
    }
413
  } while (bytebuff != EOF);
414
  fclose(fd);
415
 
416
  /* Look out for doubled repositories */
417
  if (checkfordoubledrepos(repolist, repocount) != 0) return(-1);
418
  if (checkfordoubledirlist(*dirlist) != 0) return(-1);
419
  if (validatedirlist(*dirlist) != 0) return(-1);
420
 
421
  return(repocount);
422
}