Annotation of rpmfind/config.c, revision 1.23
1.1 daniel 1: /*
2: * config.c : handle the configuration file(s).
3: *
4: * See Copyright for the status of this software.
5: *
1.23 ! daniel 6: * $Id: config.c,v 1.22 1999/11/06 10:21:43 daniel Exp $
1.1 daniel 7: */
8:
9: #include <config.h>
10: #include <sys/types.h>
11: #include <sys/stat.h>
12: #include <sys/time.h>
13: #ifdef HAVE_FCNTL_H
14: #include <fcntl.h>
15: #endif
16: #include <stdio.h>
17: #include <stdlib.h>
18: #include <string.h>
19: #ifdef HAVE_UNISTD_H
20: #include <unistd.h>
21: #endif
22: #include <time.h>
1.11 veillard 23: #include <errno.h>
1.1 daniel 24:
25: #include "rpmfind.h"
26: #include "rpmdata.h"
1.5 veillard 27: #include "database.h"
1.8 daniel 28: #include "transport.h"
1.19 daniel 29: #include "hosts.h"
1.5 veillard 30:
31: int configNeedUpdate = 0;
1.1 daniel 32:
1.2 veillard 33: static char *configVersion = NULL;
1.11 veillard 34: static char *userTempDir = NULL;
1.1 daniel 35:
36: #ifdef HAVE_STRNDUP
37: extern char *strndup (const char *source, size_t len);
38: #else /* ! HAVE_STRNDUP */
39: /*
40: *
41: */
42: char *strndup (const char *source, size_t len) {
43: char* tmp = NULL;
44:
45: if ((source == NULL) || (len < 0)) return(NULL);
46: if (len <= strlen(source)) return strdup(source);
47:
48: tmp = malloc(len+1);
49: strncpy(tmp, source, len);
50: tmp[len] = '\0';
51:
52: return(tmp);
53: }
54: #endif /* HAVE_STRNDUP */
55:
56:
57: /*
58: * addConfigEntry : an entry in the config file has just been read.
59: */
60: void addConfigEntry(char *section, char *name, char *value) {
61:
62: if (rpmfindVerbose > 1)
63: printf("addConfigEntry(\"%s\", \"%s\", \"%s\")\n",
64: section, name, value);
65:
66: /*
67: * case of global option for rpmfind.
68: */
69: if (!strcasecmp(section, RPMFIND_NAME)) {
1.2 veillard 70: if (!strcasecmp(name, "version")) {
71: if (configVersion != NULL) free(configVersion);
72: configVersion = strdup(value);
73: } else if (!strcasecmp(name, "server")) {
1.1 daniel 74: myServer = strdup(value);
1.19 daniel 75: } else if (!strcasecmp(name, "country")) {
76: myCountryName = strdup(value);
1.2 veillard 77: } else if (!strcasecmp(name, "downloadDir")) {
78: downloadDir = strdup(value);
1.3 veillard 79: } else if (!strcasecmp(name, "httpProxy")) {
80: myHttpProxy = strdup(value);
81: } else if (!strcasecmp(name, "ftpProxy")) {
82: myFtpProxy = strdup(value);
1.11 veillard 83: } else if (!strcasecmp(name, "tempDir")) {
1.15 daniel 84: if (rpmfindTempDir != NULL) free(rpmfindTempDir);
1.18 daniel 85: userTempDir = strdup(value);
86: rpmfindTempDir = strdup(value);
1.1 daniel 87: } else if (!strcasecmp(name, "prefix")) {
88: myPrefix = strdup(value);
89: } else if (!strcasecmp(name, "verbose")) {
90: int level;
91: int res;
92:
93: res = sscanf(value, "%d", &level);
94: if (res == 1)
95: rpmfindVerbose = level;
96: else
97: printf("Config file : %s global ignored, invalid value %s\n",
98: name, value);
1.7 daniel 99: } else if (!strcasecmp(name, "useOrigin")) {
100: int level;
101: int res;
102:
103: res = sscanf(value, "%d", &level);
104: if (res == 1)
105: rpmfindUseOrigin = level;
106: else
107: printf("Config file : %s global ignored, invalid value %s\n",
108: name, value);
109: } else if (!strcasecmp(name, "mirrorUpgrade")) {
110: int level;
111: int res;
112:
113: res = sscanf(value, "%d", &level);
114: if (res == 1)
115: rpmfindMirrorUpgrade = level;
116: else
117: printf("Config file : %s global ignored, invalid value %s\n",
118: name, value);
1.1 daniel 119: } else if (!strcasecmp(name, "mode")) {
120: if (!strcasecmp(value, "lookup"))
121: rpmfindMode = RPM_FIND_LOOKUP;
122: else if (!strcasecmp(value, "latest"))
123: rpmfindMode = RPM_FIND_LATEST;
124: else if (!strcasecmp(value, "upgrade"))
125: rpmfindMode = RPM_FIND_UPGRADE;
126: else
127: printf("Config file : %s global ignored, invalid value %s\n",
128: name, value);
1.18 daniel 129: } else if (!strcasecmp(name, "auto")) {
130: if ((!strcasecmp(value, "yes")) ||
131: (!strcasecmp(value, "true"))) {
132: rpmfindAutomatic = 1;
133: } else {
134: rpmfindAutomatic = 0;
135: }
1.23 ! daniel 136: } else if (!strcasecmp(name, "overwrite")) {
! 137: if ((!strcasecmp(value, "yes")) ||
! 138: (!strcasecmp(value, "true"))) {
! 139: rpmfindOverwrite = 1;
! 140: } else {
! 141: rpmfindOverwrite = 0;
! 142: }
1.1 daniel 143: } else {
144: printf("Config file : %s global entry ignored\n", name);
145: }
146: return;
147: }
148:
149: /*
1.4 daniel 150: * Options for packages selection.
151: */
152: if (!strcasecmp(section, "packages")) {
153: if (!strcasecmp(name, "no_upgrade")) {
1.5 veillard 154: rpmNoUpgradeListAdd(value);
1.4 daniel 155: } else if (!strcasecmp(name, "no_depend")) {
1.5 veillard 156: rpmNoDependListAdd(value);
1.21 daniel 157: } else if (!strcasecmp(name, "no_distrib")) {
158: rpmNoDistribListAdd(value);
1.4 daniel 159: } else {
160: fprintf(stderr, "Section [packages]: unknown keyword %s, ignored\n",
161: name);
1.9 daniel 162: }
163: return;
164: }
165:
166: /*
167: * Options for the metadata mirrors.
168: */
1.10 veillard 169: if (!strcasecmp(section, "metadata")) {
1.9 daniel 170: if (!strcasecmp(name, "mirror")) {
171: rpmMetadataAddMirror(value);
172: } else {
173: printf("Config file : %s entry for [metadata] ignored\n", name);
1.4 daniel 174: }
175: return;
176: }
177:
178: /*
1.5 veillard 179: * option for a distribution.
1.1 daniel 180: */
1.5 veillard 181: if (!strcasecmp(name, "mirror")) {
182: rpmDistribAddMirror(section, value);
183: } else if (!strcasecmp(name, "name")) {
184: rpmDistribSetName(section, value);
185: } else if (!strcasecmp(name, "origin")) {
186: rpmDistribSetOrigin(section, value);
1.7 daniel 187: } else if (!strcasecmp(name, "myMirror")) {
188: rpmDistribSetMyMirror(section, value);
1.5 veillard 189: } else if (!strcasecmp(name, "rating")) {
190: rpmDistribSetRating(section, value);
1.1 daniel 191: } else {
1.5 veillard 192: fprintf(stderr, "Distribution [%s]: unknown keyword %s, ignored\n",
193: section, name);
1.1 daniel 194: }
195: }
196:
197: /*
198: * writeConfigFile : save the current settings in $HOME/.rpmfind
199: */
200: void writeConfigFile(char *filename) {
201: FILE *output;
202: time_t now;
203: static char buf[500];
204: struct tm * tstruct;
205:
206: if (rpmfindVerbose > 1) printf("writeConfigFile(%s)\n", filename);
207:
208: output = fopen(filename, "w");
209: if (output == NULL) {
210: fprintf(stderr, "Cannot save configuration to %s\n", filename);
211: return;
212: }
213:
1.2 veillard 214: fprintf(output,";\n; Configuration file for %s-%s\n",
215: RPMFIND_NAME, RPMFIND_VER);
1.1 daniel 216: #ifdef HAVE_STRFTIME
217: now = time(NULL);
218: tstruct = localtime(&now);
219: strftime(buf, sizeof(buf) - 1, "%c", tstruct);
220: fprintf(output, "; Last updated : %s\n", buf);
221: #endif
222: fprintf(output, ";\n");
1.7 daniel 223: fprintf(output, "\n;\n; General configuration variables\n;\n\n");
224: fprintf(output, "version=%s\n\n", RPMFIND_VER);
1.6 veillard 225: fprintf(output,
1.21 daniel 226: "; the server to contact, e.g: http://rpmfind.net/linux/RDF\n");
1.7 daniel 227: fprintf(output, "server=%s\n\n", myServer);
1.19 daniel 228: fprintf(output,
229: "; the country of your host, e.g: fr, de, cz\n");
230: fprintf(output,
231: "; Useful only if not guessable from your hostname\n");
232: if (myCountryName != NULL) {
233: fprintf(output, "country=%s\n\n", myCountryName);
234: } else {
235: fprintf(output, "; country=fr\n\n");
236: }
1.6 veillard 237: fprintf(output, "; base for RPM database, / by default\n");
1.7 daniel 238: fprintf(output, "prefix=%s\n\n", myPrefix);
1.6 veillard 239: fprintf(output, "; where to save RPMs\n");
1.7 daniel 240: fprintf(output, "downloadDir=%s\n\n", downloadDir);
1.11 veillard 241: fprintf(output,
242: "; Where rpmfind stores temporary files, ~/.rpmfinddir by default\n");
243: if (userTempDir != NULL)
244: fprintf(output, "tempDir=%s\n\n", userTempDir);
245: else
246: fprintf(output, "tempDir=\n\n");
1.6 veillard 247: fprintf(output, "; your HTTP proxy/cache if any: http://myhttpproxy/\n");
1.7 daniel 248: fprintf(output, "httpProxy=%s\n\n", myHttpProxy);
1.6 veillard 249: fprintf(output, "; your FTP proxy/cache if any: ftp://myftpproxy/\n");
1.7 daniel 250: fprintf(output, "ftpProxy=%s\n\n", myFtpProxy);
1.13 veillard 251: /****** Don't save the verbosity level anymore *****
1.6 veillard 252: fprintf(output, "; Verbosity level: 0 quiet, 1 normal, >1 debug\n");
1.7 daniel 253: fprintf(output, "verbose=%d\n\n", rpmfindVerbose);
1.13 veillard 254: ***************************************************/
1.7 daniel 255: fprintf(output, "; Default mode upgrade, latest or lookup (default)\n");
1.1 daniel 256: switch (rpmfindMode) {
257: case RPM_FIND_LOOKUP:
1.7 daniel 258: fprintf(output, "mode=lookup\n\n");
1.1 daniel 259: break;
260: case RPM_FIND_LATEST:
1.7 daniel 261: fprintf(output, "mode=latest\n\n");
1.1 daniel 262: break;
263: case RPM_FIND_UPGRADE:
1.7 daniel 264: fprintf(output, "mode=upgrade\n\n");
1.1 daniel 265: break;
266: }
1.18 daniel 267: fprintf(output, "; Run in automatic mode: yes or no (default)\n");
268: if (rpmfindAutomatic)
269: fprintf(output, "auto=yes\n\n");
270: else
271: fprintf(output, "auto=no\n\n");
1.23 ! daniel 272: fprintf(output, "; Run in overwrite mode: yes or no (default)\n");
! 273: if (rpmfindOverwrite)
! 274: fprintf(output, "overwrite=yes\n\n");
! 275: else
! 276: fprintf(output, "overwrite=no\n\n");
1.7 daniel 277: fprintf(output,
278: "; Always use origin server: 0 no (default), 1 yes (paranoid)\n");
279: fprintf(output, "useOrigin=%d\n\n", rpmfindUseOrigin);
280: fprintf(output, "; Auto upgrade the mirror lists: 0 no, 1 yes (default)\n");
281: fprintf(output, "mirrorUpgrade=%d\n\n", rpmfindMirrorUpgrade);
1.1 daniel 282: fprintf(output, "\n");
283:
1.5 veillard 284: rpmFindWriteDatabase(output);
1.4 daniel 285:
1.1 daniel 286: fclose(output);
287: }
288: /****************************************************************
289: * *
290: * The configuration file parser *
291: * *
292: ****************************************************************/
293:
294: /*
295: * A few macro needed to help building the parser
296: */
297:
298: #define IS_BLANK(ptr) \
299: (((*(ptr)) == ' ') || ((*(ptr)) == '\b') || \
300: ((*(ptr)) == '\n') || ((*(ptr)) == '\r'))
301: #define SKIP_BLANK(ptr) \
302: { while (((*(ptr)) == ' ') || ((*(ptr)) == '\b') || \
303: ((*(ptr)) == '\n') || ((*(ptr)) == '\r')) ptr++; }
304: #define GOTO_EQL(ptr) \
305: { while (((*(ptr)) != '\0') && ((*(ptr)) != '=') && \
306: ((*(ptr)) != '\n') && ((*(ptr)) != '\r')) ptr++; }
307: #define GOTO_EOL(ptr) \
308: { while (((*(ptr)) != '\0') && \
309: ((*(ptr)) != '\n') && ((*(ptr)) != '\r')) ptr++; }
310:
311:
312: /*
313: * read config file: parse a configuration file.
314: */
315: int readConfigFile(char *filename)
316: {
317: FILE *input;
318: char *str, *base;
319: char string[1000];
320: char section[1000] = "rpmfind";
321: char *name;
322: char *value;
323: int errors = 0;
324:
325: input = fopen (filename, "r");
326: if (input == NULL)
327: {
328: fprintf (stderr, "Cannot read config from %s :\n", filename);
329: perror ("fopen failed");
330: return -1;
331: }
332:
333: if (rpmfindVerbose > 1) printf("readConfigFile(%s)\n", filename);
334:
335: while (1)
336: {
337: /*
338: * read one line in string buffer.
339: */
340: if (fgets (&string[0], sizeof (string) - 1, input) == NULL)
341: break;
342:
343: str = &string[0];
344: SKIP_BLANK (str)
345: string[sizeof (string) - 1] = '\0';
346:
347: /*
348: * Comment starts with a semicolumn.
349: */
350: if (*str == ';')
351: continue;
352: if (*str == '\0')
353: continue;
354:
355: /*
356: * sections are indicated between brackets, e.g. [amaya]
357: */
358: if (*str == '[')
359: {
360: str++;
361: SKIP_BLANK (str)
362: base = str;
363: while ((*str != '\0') && (*str != ']'))
364: str++;
365: if (*str == '\0')
366: {
367: fprintf (stderr, "config file %s corrupted :\n\t\"%s\"\n",
368: filename, string);
369: break;
370: }
371: *str = '\0';
372: strcpy (§ion[0], base);
373:
374: if (rpmfindVerbose > 1)
375: fprintf (stderr, "readConfigFile section [%s]\n", section);
376:
377: continue;
378: }
379:
380: /*
381: * entries have the following form :
382: * name=value
383: */
384: name = str;
385: GOTO_EQL (str)
386: if (*str != '=') {
387: errors++;
388: if (errors >= 30) {
389: fprintf (stderr, "config file %s seems invalid\n", filename);
390: break;
391: }
392: continue;
393: }
394: *str++ = '\0';
395: SKIP_BLANK (str)
396: value = str;
397: GOTO_EOL (str)
398: *str = '\0';
399: addConfigEntry(section, name, value);
400: }
401:
402: fclose (input);
403: return(0);
404: }
405:
406: /*
407: * Save the current config in $HOME/.rpmfind
408: */
409:
410: void rpmFindWriteConfigFile(void) {
411: char path[1000];
412: char *home;
413:
414: home = getenv("HOME");
415: if (home != NULL) {
1.22 daniel 416: snprintf(path, sizeof(path), "%s/.%s", home, RPMFIND_NAME);
1.1 daniel 417: writeConfigFile(path);
418: }
419: }
420: /*
421: * Read the /etc/rpmfind.conf and/or $HOME/.rpmfind
422: */
423:
424: void rpmFindReadConfigFiles(void) {
425: char path[1000];
426: struct stat buf;
427: char *home;
428: int has_config_file = 0;
1.16 daniel 429: char *proxy;
1.1 daniel 430:
1.16 daniel 431: /*
432: * Check environment variables indicating an HTTP proxy
433: */
434: proxy = getenv("HTTP_PROXY");
435: if (proxy != NULL) {
1.17 daniel 436: if (strncmp(proxy, "http://", 8)) {
437: char buf[1000];
438:
439: snprintf(buf, 1000, "http://%s/", proxy);
440: myHttpProxy = strdup(buf);
441: } else
442: myHttpProxy = strdup(proxy);
1.16 daniel 443: /*
444: * Remove the env since it's confusing libWWW
445: */
446: putenv("HTTP_PROXY=");
447: #ifdef HAVE_UNSETENV
448: unsetenv("HTTP_PROXY");
449: #endif
450: }
1.17 daniel 451: proxy = getenv("http_proxy");
452: if (proxy != NULL) {
1.20 daniel 453: if (strncmp(proxy, "http://", 7)) {
1.17 daniel 454: char buf[1000];
455:
456: snprintf(buf, 1000, "http://%s/", proxy);
457: myHttpProxy = strdup(buf);
458: } else
459: myHttpProxy = strdup(proxy);
460: /*
461: * Remove the env since it's confusing libWWW
462: */
463: putenv("http_proxy=");
464: #ifdef HAVE_UNSETENV
465: unsetenv("http_proxy");
466: #endif
467: }
1.16 daniel 468:
469: /*
1.17 daniel 470: * Check environment variables indicating an FTP proxy
471: */
472: proxy = getenv("FTP_PROXY");
473: if (proxy != NULL) {
474: if (strncmp(proxy, "ftp://", 8)) {
475: char buf[1000];
476:
477: snprintf(buf, 1000, "ftp://%s/", proxy);
478: myHttpProxy = strdup(buf);
479: } else
480: myHttpProxy = strdup(proxy);
481: /*
482: * Remove the env since it's confusing libWWW
483: */
484: putenv("FTP_PROXY=");
485: #ifdef HAVE_UNSETENV
486: unsetenv("FTP_PROXY");
487: #endif
488: }
489: proxy = getenv("ftp_proxy");
490: if (proxy != NULL) {
491: if (strncmp(proxy, "ftp://", 8)) {
492: char buf[1000];
493:
494: snprintf(buf, 1000, "ftp://%s/", proxy);
495: myHttpProxy = strdup(buf);
496: } else
497: myHttpProxy = strdup(proxy);
498: /*
499: * Remove the env since it's confusing libWWW
500: */
501: putenv("ftp_proxy=");
502: #ifdef HAVE_UNSETENV
503: unsetenv("ftp_proxy");
504: #endif
505: }
506:
507: /*
508: * Try to read configuration files
1.16 daniel 509: */
1.12 veillard 510: rpmfindTempDir = strdup("/tmp");
511:
1.22 daniel 512: snprintf(path, sizeof(path), "/etc/%s.conf", RPMFIND_NAME);
1.1 daniel 513: if (!stat(path, &buf)) {
514: readConfigFile(path);
515: has_config_file++;
516: }
517:
518: home = getenv("HOME");
519: if (home != NULL) {
1.22 daniel 520: snprintf(path, sizeof(path), "%s/.%s", home, RPMFIND_NAME);
1.1 daniel 521: if (!stat(path, &buf)) {
522: readConfigFile(path);
523: has_config_file++;
524: }
1.4 daniel 525: }
1.5 veillard 526: configNeedUpdate = 0;
1.17 daniel 527:
528: /*
529: * If no configuration file was found, save one before attempting
530: * any network access.
531: */
532: if (!has_config_file)
533: rpmFindWriteConfigFile();
1.4 daniel 534:
1.12 veillard 535: /*
536: * Check the temp dir.
537: */
538: if (rpmfindTempDir != NULL) {
539: int uid = getuid();
540: int gid = getgid();
541: int ok = 0;
542:
543: if (stat(rpmfindTempDir, &buf)) {
544: free(rpmfindTempDir);
545: rpmfindTempDir = NULL;
546: } else if (!S_ISDIR(buf.st_mode)) {
547: free(rpmfindTempDir);
548: rpmfindTempDir = NULL;
549: } else if ((buf.st_uid == uid) && (buf.st_mode & S_IWUSR)) {
550: ok = 1;
551: } else if ((buf.st_gid == gid) && (buf.st_mode & S_IWGRP)) {
552: ok = 1;
553: } else if (buf.st_mode & S_IWOTH) {
554: ok = 1;
555: } else {
556: fprintf(stderr, "Check permissions on %s\n", rpmfindTempDir);
557: }
1.11 veillard 558: }
559: if (rpmfindTempDir == NULL) {
560: if (home == NULL)
561: rpmfindTempDir = "/tmp";
562: else {
1.22 daniel 563: snprintf(path, sizeof(path), "%s/.%sdir", home, RPMFIND_NAME);
1.11 veillard 564: if (!stat(path, &buf)) {
565: rpmfindTempDir = strdup(path);
1.22 daniel 566: snprintf(path, sizeof(path), "rm -f %s/.%sdir/%s*", home,
1.11 veillard 567: RPMFIND_NAME, RPMFIND_NAME);
568: system(path);
569: } else {
570: if ((mkdir(path, 0700) < 0) && (errno != EEXIST)) {
571: rpmfindTempDir = "/tmp";
572: } else
573: rpmfindTempDir = strdup(path);
574: }
575: }
1.1 daniel 576: }
1.14 daniel 577: mkdir(rpmfindTempDir, 0700);
1.1 daniel 578:
1.18 daniel 579: /*
580: * Update the distribution lists and metadata lists when changing
581: * the version number or running it for the first time.
582: * Then save the user's config file.
583: */
584: if ((configVersion == NULL) || (strcmp(configVersion, RPMFIND_VER))) {
585: rpmNoUpgradeListAdd("glibc");
586: rpmNoUpgradeListAdd("glibc.so.*");
587: rpmNoUpgradeListAdd("libc");
588: rpmNoUpgradeListAdd("libc.so.*");
589: rpmNoDependListAdd("libc.so.3");
590: rpmFetchDistribList();
591: rpmFetchMetadataList();
592: } else if (nb_metadata_mirrors == 0) {
593: rpmFetchMetadataList();
594: }
1.2 veillard 595: if ((configVersion == NULL) || (strcmp(configVersion, RPMFIND_VER)))
596: rpmFindWriteConfigFile();
1.1 daniel 597: }
Webmaster