/[gentoo-projects]/portage-utils/main.c
Gentoo

Contents of /portage-utils/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.225 - (show annotations) (download) (as text)
Sun Oct 28 10:29:38 2012 UTC (21 months, 4 weeks ago) by vapier
Branch: MAIN
Changes since 1.224: +11 -6 lines
File MIME type: text/x-csrc
improve trimming of quotes/whitespace when loading env files

1 /*
2 * Copyright 2005-2008 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/portage-utils/main.c,v 1.224 2012/10/28 10:11:47 vapier Exp $
5 *
6 * Copyright 2005-2008 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2005-2008 Mike Frysinger - <vapier@gentoo.org>
8 */
9
10 #ifdef HAVE_CONFIG_H
11 # include "config.h" /* make sure we have EPREFIX, if set */
12 #endif
13
14 #ifndef _GNU_SOURCE
15 #define _GNU_SOURCE
16 #endif
17 #ifdef _AIX
18 #define _LINUX_SOURCE_COMPAT
19 #endif
20
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <sys/types.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #include <time.h>
30 #include <sys/time.h>
31 #include <ctype.h>
32 #include <dirent.h>
33 #include <getopt.h>
34 #include <regex.h>
35 #include <errno.h>
36 #include <libgen.h>
37 #include <limits.h>
38 #include <assert.h>
39 #include "main.h"
40
41 /* prototypes and such */
42 static char eat_file(const char *file, char *buf, const size_t bufsize);
43 int rematch(const char *, const char *, int);
44 static char *rmspace(char *);
45
46 void initialize_portage_env(void);
47 void initialize_ebuild_flat(void);
48 void reinitialize_ebuild_flat(void);
49 void reinitialize_as_needed(void);
50 void cleanup(void);
51 int lookup_applet_idx(const char *);
52
53 /* variables to control runtime behavior */
54 char *module_name = NULL;
55 char *modpath = NULL;
56 int verbose = 0;
57 int quiet = 0;
58 int portcachedir_type = 0;
59 char pretend = 0;
60 char reinitialize = 0;
61 char reinitialize_metacache = 0;
62 static char *portdir;
63 static char *portarch;
64 static char *portvdb;
65 const char portcachedir_pms[] = "metadata/cache";
66 const char portcachedir_md5[] = "metadata/md5-cache";
67 static char *portroot;
68 static char *eprefix;
69 static char *config_protect, *config_protect_mask;
70
71 static char *pkgdir;
72 static char *port_tmpdir;
73
74 static char *binhost;
75 static char *features;
76 static char *accept_license;
77 static char *install_mask;
78 static char *pkg_install_mask;
79
80 const char err_noapplet[] = "Sorry this applet was disabled at compile time";
81
82 /* helper functions for showing errors */
83 static const char *argv0;
84
85 #ifdef EBUG
86 # include <sys/resource.h>
87 void init_coredumps(void);
88 void init_coredumps(void)
89 {
90 struct rlimit rl;
91 rl.rlim_cur = RLIM_INFINITY;
92 rl.rlim_max = RLIM_INFINITY;
93 setrlimit(RLIMIT_CORE, &rl);
94 }
95 #endif
96
97 /* include common library code */
98 #include "libq/libq.c"
99
100 void no_colors(void);
101 void no_colors()
102 {
103 /* echo $(awk '{print $4,"="}' libq/colors.c | grep ^* |cut -c 2-| grep ^[A-Z] |tr '\n' ' ') = \"\"\; */
104 BOLD = NORM = BLUE = DKBLUE = CYAN = GREEN = DKGREEN = MAGENTA = RED = YELLOW = BRYELLOW = WHITE = "";
105 setenv("NOCOLOR", "true", 1);
106 }
107
108 /* include common applet defs */
109 #include "applets.h"
110
111 /* Common usage for all applets */
112 #define COMMON_FLAGS "vqChV"
113 #define COMMON_LONG_OPTS \
114 {"verbose", no_argument, NULL, 'v'}, \
115 {"quiet", no_argument, NULL, 'q'}, \
116 {"nocolor", no_argument, NULL, 'C'}, \
117 {"help", no_argument, NULL, 'h'}, \
118 {"version", no_argument, NULL, 'V'}, \
119 {NULL, no_argument, NULL, 0x0}
120 #define COMMON_OPTS_HELP \
121 "Make a lot of noise", \
122 "Tighter output; suppress warnings", \
123 "Don't output color", \
124 "Print this help and exit", \
125 "Print version and exit", \
126 NULL
127 #define COMMON_GETOPTS_CASES(applet) \
128 case 'v': ++verbose; break; \
129 case 'q': ++quiet; if (freopen("/dev/null", "w", stderr)) { /* ignore errors */ } break; \
130 case 'V': version_barf( applet ## _rcsid ); break; \
131 case 'h': applet ## _usage(EXIT_SUCCESS); break; \
132 case 'C': no_colors(); break; \
133 default: applet ## _usage(EXIT_FAILURE); break;
134
135 /* display usage and exit */
136 static void usage(int status, const char *flags, struct option const opts[],
137 const char * const help[], int blabber)
138 {
139 unsigned long i;
140 if (blabber == 0) {
141 printf("%sUsage:%s %sq%s %s<applet> <args>%s : %s"
142 "invoke a portage utility applet\n\n", GREEN,
143 NORM, YELLOW, NORM, DKBLUE, RED, NORM);
144 printf("%sCurrently defined applets:%s\n", GREEN, NORM);
145 for (i = 0; applets[i].desc; ++i)
146 if (applets[i].func)
147 printf(" %s%8s%s %s%-16s%s%s:%s %s\n",
148 YELLOW, applets[i].name, NORM,
149 DKBLUE, applets[i].opts, NORM,
150 RED, NORM, _(applets[i].desc));
151 } else if (blabber > 0) {
152 printf("%sUsage:%s %s%s%s <opts> %s%s%s %s:%s %s\n", GREEN, NORM,
153 YELLOW, applets[blabber].name, NORM,
154 DKBLUE, applets[blabber].opts, NORM,
155 RED, NORM, _(applets[blabber].desc));
156 }
157 if (module_name != NULL)
158 printf("%sLoaded module:%s\n%s%8s%s %s<args>%s\n", GREEN, NORM, YELLOW, module_name, NORM, DKBLUE, NORM);
159
160 printf("\n%sOptions:%s -[%s]\n", GREEN, NORM, flags);
161 for (i = 0; opts[i].name; ++i) {
162 /* this assert is a life saver when adding new applets. */
163 assert(help[i] != NULL);
164
165 /* first output the short flag if it has one */
166 if (opts[i].val > '~')
167 printf(" ");
168 else
169 printf(" -%c, ", opts[i].val);
170
171 /* then the long flag + help text */
172 if (opts[i].has_arg == no_argument)
173 printf("--%-15s%s*%s %s\n", opts[i].name,
174 RED, NORM, _(help[i]));
175 else
176 printf("--%-8s %s<arg>%s %s*%s %s\n", opts[i].name,
177 DKBLUE, NORM, RED, NORM, _(help[i]));
178 }
179 exit(status);
180 }
181
182 static void version_barf(const char *Id)
183 {
184 #ifndef VERSION
185 # define VERSION "cvs"
186 #endif
187 printf("portage-utils-%s: compiled on %s\n%s\n"
188 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
189 VERSION, __DATE__, Id, argv0);
190 exit(EXIT_SUCCESS);
191 }
192
193 static char eat_file_fd(int fd, char *buf, const size_t bufsize)
194 {
195 struct stat s;
196
197 buf[0] = '\0';
198 if (fstat(fd, &s) != 0)
199 return 0;
200 if (s.st_size) {
201 if (bufsize < (size_t)s.st_size)
202 return 0;
203 if (read(fd, buf, s.st_size) != (ssize_t)s.st_size)
204 return 0;
205 buf[s.st_size] = '\0';
206 } else {
207 if (read(fd, buf, bufsize) == 0)
208 return 0;
209 buf[bufsize - 1] = '\0';
210 }
211
212 return 1;
213 }
214
215 static char eat_file_at(int dfd, const char *file, char *buf, const size_t bufsize)
216 {
217 int fd;
218 char ret;
219
220 if ((fd = openat(dfd, file, O_CLOEXEC|O_RDONLY)) == -1) {
221 buf[0] = '\0';
222 return 0;
223 }
224
225 ret = eat_file_fd(fd, buf, bufsize);
226
227 close(fd);
228 return ret;
229 }
230
231 static char eat_file(const char *file, char *buf, const size_t bufsize)
232 {
233 return eat_file_at(AT_FDCWD, file, buf, bufsize);
234 }
235
236 static bool prompt(const char *p)
237 {
238 printf("%s? [Y/n] ", p);
239 fflush(stdout);
240 switch (getc(stdin)) {
241 case '\n':
242 case 'y':
243 case 'Y':
244 return true;
245 default:
246 return false;
247 }
248 }
249
250 int rematch(const char *re, const char *match, int cflags)
251 {
252 regex_t preg;
253 int ret;
254
255 if ((match == NULL) || (re == NULL))
256 return EXIT_FAILURE;
257
258 if (wregcomp(&preg, re, cflags))
259 return EXIT_FAILURE;
260 ret = regexec(&preg, match, 0, NULL, 0);
261 regfree(&preg);
262
263 return ret;
264 }
265
266 /* removes adjacent extraneous white space */
267 static char *remove_extra_space(char *str);
268 static char *remove_extra_space(char *str)
269 {
270 char *p, c = ' ';
271 size_t len, pos = 0;
272 char *buf;
273
274 if (str == NULL)
275 return NULL;
276 len = strlen(str);
277 buf = xzalloc(len+1);
278 for (p = str; *p != 0; ++p) {
279 if (!isspace(*p)) c = *p; else {
280 if (c == ' ') continue;
281 c = ' ';
282 }
283 buf[pos] = c;
284 pos++;
285 }
286 if (pos > 0 && buf[pos-1] == ' ') buf[pos-1] = '\0';
287 strcpy(str, buf);
288 free(buf);
289 return str;
290 }
291
292 static void freeargv(int argc, char **argv)
293 {
294 while (argc--)
295 free(argv[argc]);
296 free(argv);
297 }
298
299 static void makeargv(const char *string, int *argc, char ***argv)
300 {
301 int curc = 2;
302 char *q, *p, *str;
303 (*argv) = xmalloc(sizeof(char **) * curc);
304
305 *argc = 1;
306 (*argv)[0] = xstrdup(argv0);
307 q = xstrdup(string);
308 str = q;
309
310 remove_extra_space(str);
311 rmspace(str);
312
313 while (str) {
314 if ((p = strchr(str, ' ')) != NULL)
315 *(p++) = '\0';
316
317 if (*argc == curc) {
318 curc *= 2;
319 (*argv) = xrealloc(*argv, sizeof(char **) * curc);
320 }
321 (*argv)[*argc] = xstrdup(str);
322 (*argc)++;
323 str = p;
324 }
325 free(q);
326 }
327
328 /*
329 * Parse a line of CONTENTS file and provide access to the individual fields
330 */
331 typedef enum {
332 CONTENTS_DIR, CONTENTS_OBJ, CONTENTS_SYM
333 } contents_type;
334 typedef struct {
335 contents_type type;
336 char *_data;
337 char *name;
338 char *sym_target;
339 char *digest;
340 char *mtime_str;
341 long mtime;
342 } contents_entry;
343
344 contents_entry *contents_parse_line(char *line);
345 contents_entry *contents_parse_line(char *line)
346 {
347 static contents_entry e;
348 char *p;
349
350 if (!line || !*line || *line == '\n')
351 return NULL;
352
353 /* chop trailing newline */
354 if ((p = strrchr(line, '\n')) != NULL)
355 *p = '\0';
356
357 /* ferringb wants to break portage/vdb by using tabs vs spaces
358 * so filenames can have lame ass spaces in them..
359 * (I smell Windows near by)
360 * Anyway we just convert that crap to a space so we can still
361 * parse quickly */
362 p = line;
363 while ((p = strchr(p, '\t')) != NULL)
364 *p = ' ';
365
366 memset(&e, 0x00, sizeof(e));
367 e._data = line;
368
369 if (!strncmp(e._data, "obj ", 4))
370 e.type = CONTENTS_OBJ;
371 else if (!strncmp(e._data, "dir ", 4))
372 e.type = CONTENTS_DIR;
373 else if (!strncmp(e._data, "sym ", 4))
374 e.type = CONTENTS_SYM;
375 else
376 return NULL;
377
378 e.name = e._data + 4;
379
380 switch (e.type) {
381 /* dir /bin */
382 case CONTENTS_DIR:
383 break;
384
385 /* obj /bin/bash 62ed51c8b23866777552643ec57614b0 1120707577 */
386 case CONTENTS_OBJ:
387 if ((e.mtime_str = strrchr(e.name, ' ')) == NULL)
388 return NULL;
389 *e.mtime_str++ = '\0';
390 if ((e.digest = strrchr(e.name, ' ')) == NULL)
391 return NULL;
392 *e.digest++ = '\0';
393 break;
394
395 /* sym /bin/sh -> bash 1120707577 */
396 case CONTENTS_SYM:
397 if ((e.mtime_str = strrchr(e.name, ' ')) == NULL)
398 return NULL;
399 *e.mtime_str++ = '\0';
400 if ((e.sym_target = strstr(e.name, " -> ")) == NULL)
401 return NULL;
402 *e.sym_target = '\0';
403 e.sym_target += 4;
404 break;
405 }
406
407 if (e.mtime_str) {
408 e.mtime = strtol(e.mtime_str, NULL, 10);
409 if (e.mtime == LONG_MAX) {
410 e.mtime = 0;
411 e.mtime_str = NULL;
412 }
413 }
414
415 return &e;
416 }
417
418 static void strincr_var(const char *name, const char *s, char **value, size_t *value_len)
419 {
420 size_t len;
421 char *buf, *p, *nv;
422
423 len = strlen(s);
424 *value = xrealloc(*value, *value_len + len + 2);
425 nv = &(*value)[*value_len];
426 if (*value_len)
427 *nv++ = ' ';
428 memcpy(nv, s, len + 1);
429
430 while ((p = strstr(nv, "-*")) != NULL)
431 memset(*value, ' ', p - *value + 2);
432
433 /* This function is mainly used by the startup code for parsing
434 make.conf and stacking variables remove.
435 variables can be in the form of ${v} or $v
436 works:
437 FEATURES="${FEATURES} foo"
438 FEATURES="$FEATURES foo"
439 FEATURES="baz bar -* foo"
440
441 wont work:
442 FEATURES="${OTHERVAR} foo"
443 FEATURES="-nls nls -nls"
444 FEATURES="nls nls nls"
445 */
446
447 len = strlen(name);
448 buf = alloca(len + 3 + 1);
449
450 sprintf(buf, "${%s}", name);
451 if ((p = strstr(nv, buf)) != NULL)
452 memset(p, ' ', len + 3);
453
454 sprintf(buf, "$%s", name);
455 if ((p = strstr(nv, buf)) != NULL)
456 memset(p, ' ', len + 1);
457
458 remove_extra_space(*value);
459 *value_len = strlen(*value);
460 /* we should sort here */
461 }
462
463 typedef enum { _Q_BOOL, _Q_STR, _Q_ISTR } var_types;
464 typedef struct {
465 const char *name;
466 const size_t name_len;
467 const var_types type;
468 union {
469 char **s;
470 bool *b;
471 } value;
472 size_t value_len;
473 const char *default_value;
474 } env_vars;
475
476 _q_static env_vars *get_portage_env_var(env_vars *vars, const char *name)
477 {
478 size_t i;
479
480 for (i = 0; vars[i].name; ++i)
481 if (!strcmp(vars[i].name, name))
482 return &vars[i];
483
484 return NULL;
485 }
486
487 _q_static void set_portage_env_var(env_vars *var, const char *value)
488 {
489 switch (var->type) {
490 case _Q_BOOL:
491 *var->value.b = 1;
492 break;
493 case _Q_STR:
494 free(*var->value.s);
495 *var->value.s = xstrdup_len(value, &var->value_len);
496 break;
497 case _Q_ISTR:
498 strincr_var(var->name, value, var->value.s, &var->value_len);
499 break;
500 }
501 }
502
503 /* Helper to read a portage env file (e.g. make.conf) */
504 _q_static void read_portage_env_file(const char *configroot, const char *file, env_vars vars[])
505 {
506 size_t i, buflen, line, configroot_len, file_len;
507 FILE *fp;
508 char *buf, *s, *p;
509
510 IF_DEBUG(fprintf(stderr, "profile %s\n", file));
511
512 configroot_len = strlen(configroot);
513 file_len = strlen(file);
514 buflen = configroot_len + file_len + 1;
515 buf = xmalloc(buflen);
516
517 memcpy(buf, configroot, configroot_len);
518 memcpy(buf + configroot_len, file, file_len);
519 buf[buflen - 1] = '\0';
520
521 fp = fopen(buf, "r");
522 if (fp == NULL)
523 goto done;
524
525 line = 0;
526 while (getline(&buf, &buflen, fp) != -1) {
527 ++line;
528 rmspace(buf);
529 if (*buf == '#' || *buf == '\0')
530 continue;
531
532 /* Handle "source" keyword */
533 if (!strncmp(buf, "source ", 7)) {
534 const char *sfile = buf + 7;
535
536 if (sfile[0] != '/') {
537 /* handle relative paths */
538 size_t file_path_len, source_len;
539
540 s = strrchr(file, '/');
541 file_path_len = s - file + 1;
542 source_len = strlen(sfile);
543
544 if (buflen <= source_len + file_path_len)
545 buf = xrealloc(buf, buflen = source_len + file_path_len + 1);
546 memmove(buf + file_path_len, buf + 7, source_len + 1);
547 memcpy(buf, file, file_path_len);
548 sfile = buf;
549 }
550
551 read_portage_env_file(configroot, sfile, vars);
552 continue;
553 }
554
555 /* look for our desired variables and grab their value */
556 for (i = 0; vars[i].name; ++i) {
557 if (buf[vars[i].name_len] != '=' && buf[vars[i].name_len] != ' ')
558 continue;
559 if (strncmp(buf, vars[i].name, vars[i].name_len))
560 continue;
561
562 /* make sure we handle spaces between the varname, the =, and the value:
563 * VAR=val VAR = val VAR="val"
564 */
565 s = buf + vars[i].name_len;
566 if ((p = strchr(s, '=')) != NULL)
567 s = p + 1;
568 while (isspace(*s))
569 ++s;
570 if (*s == '"' || *s == '\'') {
571 char *endq;
572 char q = *s;
573
574 /* make sure we handle spacing/comments after the quote */
575 endq = strchr(s + 1, q);
576 if (!endq) {
577 /* If the last char is not a quote, then we span lines */
578 size_t abuflen;
579 char *abuf;
580
581 abuf = NULL;
582 while (getline(&abuf, &abuflen, fp) != -1) {
583 buf = xrealloc(buf, buflen + abuflen);
584 endq = strchr(abuf, q);
585 if (endq)
586 *endq = '\0';
587
588 strcat(buf, abuf);
589 buflen += abuflen;
590
591 if (endq)
592 break;
593 }
594 free(abuf);
595
596 if (!endq)
597 warn("%s:%zu: %s: quote mismatch", file, line, vars[i].name);
598
599 s = buf + vars[i].name_len + 2;
600 } else {
601 *endq = '\0';
602 ++s;
603 }
604 } else {
605 /* no quotes, so chop the spacing/comments ourselves */
606 size_t off = strcspn(s, "# \t\n");
607 s[off] = '\0';
608 }
609
610 set_portage_env_var(&vars[i], s);
611 }
612 }
613
614 fclose(fp);
615 done:
616 free(buf);
617 }
618
619 /* Helper to recursively read stacked make.defaults in profiles */
620 static void read_portage_profile(const char *configroot, const char *profile, env_vars vars[])
621 {
622 size_t configroot_len, profile_len, sub_len;
623 char *profile_file, *sub_file;
624 char buf[BUFSIZE], *s;
625
626 /* initialize the base profile path */
627 configroot_len = strlen(configroot);
628 profile_len = strlen(profile);
629 sub_len = 1024; /* should be big enough for longest line in "parent" */
630 profile_file = xmalloc(configroot_len + profile_len + sub_len + 2);
631
632 memcpy(profile_file, configroot, configroot_len);
633 memcpy(profile_file + configroot_len, profile, profile_len);
634 sub_file = profile_file + configroot_len + profile_len + 1;
635 sub_file[-1] = '/';
636
637 /* first consume the profile's make.defaults */
638 strcpy(sub_file, "make.defaults");
639 read_portage_env_file("", profile_file, vars);
640
641 /* now walk all the parents */
642 strcpy(sub_file, "parent");
643 if (eat_file(profile_file, buf, sizeof(buf)) == 0)
644 goto done;
645 rmspace(buf);
646
647 s = strtok(buf, "\n");
648 while (s) {
649 strncpy(sub_file, s, sub_len);
650 read_portage_profile("", profile_file, vars);
651 s = strtok(NULL, "\n");
652 }
653
654 done:
655 free(profile_file);
656 }
657
658 void initialize_portage_env(void)
659 {
660 size_t i;
661 const char *s;
662
663 bool nocolor = 0;
664
665 env_vars *var;
666 env_vars vars_to_read[] = {
667 #define _Q_EV(t, V, set, lset, d) \
668 { \
669 .name = #V, \
670 .name_len = strlen(#V), \
671 .type = _Q_##t, \
672 set, \
673 lset, \
674 .default_value = d, \
675 },
676 #define _Q_EVS(t, V, v, d) _Q_EV(t, V, .value.s = &v, .value_len = strlen(d), d)
677 #define _Q_EVB(t, V, v, d) _Q_EV(t, V, .value.b = &v, .value_len = 0, d)
678
679 _Q_EVS(STR, ROOT, portroot, "/")
680 _Q_EVS(STR, ACCEPT_LICENSE, accept_license, "")
681 _Q_EVS(ISTR, INSTALL_MASK, install_mask, "")
682 _Q_EVS(ISTR, PKG_INSTALL_MASK, pkg_install_mask, "")
683 _Q_EVS(STR, ARCH, portarch, "")
684 _Q_EVS(ISTR, CONFIG_PROTECT, config_protect, CONFIG_EPREFIX "etc")
685 _Q_EVS(ISTR, CONFIG_PROTECT_MASK, config_protect_mask, "")
686 _Q_EVB(BOOL, NOCOLOR, nocolor, 0)
687 _Q_EVS(ISTR, FEATURES, features, "noman noinfo nodoc")
688 _Q_EVS(STR, EPREFIX, eprefix, CONFIG_EPREFIX)
689 _Q_EVS(STR, PORTDIR, portdir, CONFIG_EPREFIX "usr/portage")
690 _Q_EVS(STR, PORTAGE_BINHOST, binhost, DEFAULT_PORTAGE_BINHOST)
691 _Q_EVS(STR, PORTAGE_TMPDIR, port_tmpdir, CONFIG_EPREFIX "var/tmp/portage/")
692 _Q_EVS(STR, PKGDIR, pkgdir, CONFIG_EPREFIX "usr/portage/packages/")
693 _Q_EVS(STR, Q_VDB, portvdb, CONFIG_EPREFIX "var/db/pkg")
694 { NULL, 0, _Q_BOOL, { NULL }, 0, NULL, }
695
696 #undef _Q_EV
697 };
698
699 /* initialize all the strings with their default value */
700 for (i = 0; vars_to_read[i].name; ++i) {
701 var = &vars_to_read[i];
702 if (var->type != _Q_BOOL)
703 *var->value.s = xstrdup(var->default_value);
704 }
705
706 /* figure out where to find our config files */
707 s = getenv("PORTAGE_CONFIGROOT");
708 if (!s)
709 s = "/";
710
711 /* walk all the stacked profiles */
712 read_portage_profile(s, CONFIG_EPREFIX "etc/make.profile", vars_to_read);
713 read_portage_profile(s, CONFIG_EPREFIX "etc/portage/make.profile", vars_to_read);
714
715 /* now read all the config files */
716 read_portage_env_file("", CONFIG_EPREFIX "usr/share/portage/config/make.globals", vars_to_read);
717 read_portage_env_file(s, CONFIG_EPREFIX "etc/make.conf", vars_to_read);
718 read_portage_env_file(s, CONFIG_EPREFIX "etc/portage/make.conf", vars_to_read);
719
720 /* finally, check the env */
721 for (i = 0; vars_to_read[i].name; ++i) {
722 var = &vars_to_read[i];
723 s = getenv(var->name);
724 if (s != NULL)
725 set_portage_env_var(var, s);
726 }
727
728 /* expand any nested variables e.g. PORTDIR=${EPREFIX}/usr/portage */
729 for (i = 0; vars_to_read[i].name; ++i) {
730 char *svar;
731
732 var = &vars_to_read[i];
733 if (var->type == _Q_BOOL)
734 continue;
735
736 while ((svar = strchr(*var->value.s, '$'))) {
737 env_vars *evar;
738 bool brace;
739 const char *sval;
740 size_t slen, pre_len, var_len, post_len;
741 char byte;
742
743 pre_len = svar - *var->value.s;
744
745 /* First skip the leading "${" */
746 s = ++svar;
747 brace = (*svar == '{');
748 if (brace)
749 s = ++svar;
750
751 /* Now skip the variable name itself */
752 while (isalnum(*svar) || *svar == '_')
753 ++svar;
754
755 /* Finally skip the trailing "}" */
756 if (brace && *svar != '}') {
757 warn("invalid variable setting: %s\n", *var->value.s);
758 break;
759 }
760
761 var_len = svar - s + 1 + (brace ? 2 : 0);
762
763 byte = *svar;
764 *svar = '\0';
765
766 /* Don't try to expand ourselves */
767 if (strcmp(var->name, s)) {
768 evar = get_portage_env_var(vars_to_read, s);
769 if (evar) {
770 sval = *evar->value.s;
771 } else {
772 sval = getenv(s);
773 if (!sval)
774 sval = "";
775 }
776 } else {
777 sval = "";
778 }
779 *svar = byte;
780 slen = strlen(sval);
781 post_len = strlen(svar + 1);
782 *var->value.s = xrealloc(*var->value.s, pre_len + MAX(var_len, slen) + post_len + 1);
783
784 /*
785 * VAR=XxXxX (slen = 5)
786 * FOO${VAR}BAR
787 * pre_len = 3
788 * var_len = 6
789 * post_len = 3
790 */
791 memmove(*var->value.s + pre_len + slen,
792 *var->value.s + pre_len + var_len,
793 post_len + 1);
794 memcpy(*var->value.s + pre_len, sval, slen);
795 }
796 }
797
798 if (getenv("DEBUG") IF_DEBUG(|| 1)) {
799 for (i = 0; vars_to_read[i].name; ++i) {
800 var = &vars_to_read[i];
801 fprintf(stderr, "%s = ", var->name);
802 switch (var->type) {
803 case _Q_BOOL: fprintf(stderr, "%i\n", *var->value.b); break;
804 case _Q_STR:
805 case _Q_ISTR: fprintf(stderr, "%s\n", *var->value.s); break;
806 }
807 }
808 }
809
810 /* Make sure ROOT always ends in a slash */
811 var = &vars_to_read[0];
812 if ((*var->value.s)[var->value_len - 1] != '/') {
813 portroot = xrealloc(portroot, var->value_len + 2);
814 portroot[var->value_len] = '/';
815 portroot[var->value_len + 1] = '\0';
816 }
817
818 if (getenv("PORTAGE_QUIET") != NULL)
819 quiet = 1;
820
821 if (nocolor)
822 no_colors();
823 else
824 color_remap();
825 }
826
827 enum {
828 CACHE_EBUILD = 1,
829 CACHE_METADATA = 2,
830 CACHE_METADATA_PMS = 10,
831 CACHE_METADATA_MD5 = 11,
832 };
833
834 int filter_hidden(const struct dirent *dentry);
835 int filter_hidden(const struct dirent *dentry)
836 {
837 if (dentry->d_name[0] == '.')
838 return 0;
839 return 1;
840 }
841
842 #define CACHE_EBUILD_FILE (getenv("CACHE_EBUILD_FILE") ? getenv("CACHE_EBUILD_FILE") : ".ebuild.x")
843 #define CACHE_METADATA_FILE ".metadata.x"
844 const char *initialize_flat(int cache_type);
845 const char *initialize_flat(int cache_type)
846 {
847 struct dirent **category, **pn, **eb;
848 struct stat st;
849 struct timeval start, finish;
850 static const char *cache_file;
851 const char *portcachedir_actual;
852 char *p;
853 int a, b, c, d, e, i;
854 int frac, secs, count;
855 FILE *fp;
856
857 a = b = c = d = e = i = 0;
858 count = frac = secs = 0;
859
860 cache_file = (cache_type == CACHE_EBUILD ? CACHE_EBUILD_FILE : CACHE_METADATA_FILE);
861
862 if (chdir(portdir) != 0) {
863 warnp("chdir to PORTDIR '%s' failed", portdir);
864 goto ret;
865 }
866
867 if (cache_type == CACHE_METADATA) {
868 if (chdir(portcachedir_md5) == 0) {
869 portcachedir_type = CACHE_METADATA_MD5;
870 portcachedir_actual = portcachedir_md5;
871 } else if (chdir(portcachedir_pms) == 0) {
872 portcachedir_type = CACHE_METADATA_PMS;
873 portcachedir_actual = portcachedir_pms;
874 } else {
875 warnp("chdir to portage cache '%s/%s' or '%s/%s' failed", portdir, portcachedir_md5, portdir, portcachedir_pms);
876 goto ret;
877 }
878 }
879
880 if (stat(cache_file, &st) != -1)
881 if (st.st_size == 0)
882 unlink(cache_file);
883
884 /* assuming --sync is used with --delete this will get recreated after every merge */
885 if (access(cache_file, R_OK) == 0)
886 goto ret;
887 if (!quiet)
888 warn("Updating ebuild %scache ... ", cache_type == CACHE_EBUILD ? "" : "meta");
889
890 unlink(cache_file);
891 if (errno != ENOENT) {
892 warnfp("unlinking '%s/%s' failed", portdir, cache_file);
893 goto ret;
894 }
895
896 if ((fp = fopen(cache_file, "w")) == NULL) {
897 if (cache_type == CACHE_EBUILD)
898 warnfp("opening '%s/%s' failed", portdir, cache_file);
899 else
900 warnfp("opening '%s/%s/%s' failed", portdir, portcachedir_actual, cache_file);
901 if (errno == EACCES)
902 warnf("You should run this command as root: q -%c",
903 cache_type == CACHE_EBUILD ? 'r' : 'm');
904 goto ret;
905 }
906
907 gettimeofday(&start, NULL);
908
909 if ((a = scandir(".", &category, q_vdb_filter_cat, alphasort)) < 0)
910 goto ret;
911
912 for (i = 0; i < a; i++) {
913 stat(category[i]->d_name, &st);
914 if (!S_ISDIR(st.st_mode))
915 continue;
916 if (strchr(category[i]->d_name, '-') == NULL)
917 if (strncmp(category[i]->d_name, "virtual", 7) != 0)
918 continue;
919
920 if ((b = scandir(category[i]->d_name, &pn, q_vdb_filter_pkg, alphasort)) < 0)
921 continue;
922 for (c = 0; c < b; c++) {
923 char de[_Q_PATH_MAX];
924
925 snprintf(de, sizeof(de), "%s/%s", category[i]->d_name, pn[c]->d_name);
926
927 if (stat(de, &st) < 0)
928 continue;
929
930 switch (cache_type) {
931 case CACHE_EBUILD:
932 if (!S_ISDIR(st.st_mode))
933 continue;
934 break;
935 case CACHE_METADATA:
936 if (S_ISREG(st.st_mode))
937 fprintf(fp, "%s\n", de);
938 continue;
939 break;
940 }
941 if ((e = scandir(de, &eb, filter_hidden, alphasort)) < 0)
942 continue;
943 for (d = 0; d < e; d++) {
944 if ((p = strrchr(eb[d]->d_name, '.')) != NULL)
945 if (strcmp(p, ".ebuild") == 0) {
946 count++;
947 fprintf(fp, "%s/%s/%s\n", category[i]->d_name, pn[c]->d_name, eb[d]->d_name);
948 }
949 }
950 while (d--) free(eb[d]);
951 free(eb);
952 }
953 scandir_free(pn, b);
954 }
955 fclose(fp);
956 scandir_free(category, a);
957
958 if (quiet) goto ret;
959
960 gettimeofday(&finish, NULL);
961 if (start.tv_usec > finish.tv_usec) {
962 finish.tv_usec += 1000000;
963 finish.tv_sec--;
964 }
965 frac = (finish.tv_usec - start.tv_usec);
966 secs = (finish.tv_sec - start.tv_sec);
967 if (secs < 0) secs = 0;
968 if (frac < 0) frac = 0;
969
970 warn("Finished %u entries in %d.%06d seconds", count, secs, frac);
971 if (secs > 120)
972 warn("You should consider using the noatime mount option for PORTDIR='%s' if it's not already enabled", portdir);
973 ret:
974 return cache_file;
975 }
976 #define initialize_ebuild_flat() initialize_flat(CACHE_EBUILD)
977 #define initialize_metadata_flat() initialize_flat(CACHE_METADATA)
978
979 void reinitialize_ebuild_flat(void)
980 {
981 if (chdir(portdir) != 0) {
982 warnp("chdir to PORTDIR '%s' failed", portdir);
983 return;
984 }
985 unlink(CACHE_EBUILD_FILE);
986 initialize_ebuild_flat();
987 }
988
989 void reinitialize_as_needed(void)
990 {
991 if (reinitialize)
992 reinitialize_ebuild_flat();
993 if (reinitialize_metacache)
994 initialize_metadata_flat();
995 }
996
997 typedef struct {
998 char *_data;
999 char *DEPEND; /* line 1 */
1000 char *RDEPEND;
1001 char *SLOT;
1002 char *SRC_URI;
1003 char *RESTRICT; /* line 5 */
1004 char *HOMEPAGE;
1005 char *LICENSE;
1006 char *DESCRIPTION;
1007 char *KEYWORDS;
1008 char *INHERITED; /* line 10 */
1009 char *IUSE;
1010 char *CDEPEND;
1011 char *PDEPEND;
1012 char *PROVIDE; /* line 14 */
1013 char *EAPI;
1014 char *PROPERTIES;
1015 depend_atom *atom;
1016 /* These are MD5-Cache only */
1017 char *DEFINED_PHASES;
1018 char *REQUIRED_USE;
1019 char *_eclasses_;
1020 char *_md5_;
1021 } portage_cache;
1022
1023 void cache_free(portage_cache *cache);
1024 portage_cache *cache_read_file_pms(const char *file);
1025 portage_cache *cache_read_file_md5(const char *file);
1026 portage_cache *cache_read_file(const char *file);
1027
1028 portage_cache *cache_read_file(const char *file)
1029 {
1030 if (portcachedir_type == CACHE_METADATA_MD5)
1031 return(cache_read_file_md5(file));
1032 else if (portcachedir_type == CACHE_METADATA_PMS)
1033 return(cache_read_file_pms(file));
1034 warn("Unknown metadata cache type!");
1035 return NULL;
1036 }
1037
1038 portage_cache *cache_read_file_pms(const char *file)
1039 {
1040 struct stat s;
1041 char *ptr;
1042 FILE *f;
1043 portage_cache *ret = NULL;
1044 size_t len;
1045
1046 if ((f = fopen(file, "r")) == NULL)
1047 goto err;
1048
1049 if (fstat(fileno(f), &s) != 0)
1050 goto err;
1051 len = sizeof(*ret) + s.st_size + 1;
1052 ret = xzalloc(len);
1053 ptr = (char*)ret;
1054 ret->_data = ptr + sizeof(*ret);
1055 if ((off_t)fread(ret->_data, 1, s.st_size, f) != s.st_size)
1056 goto err;
1057
1058 ret->atom = atom_explode(file);
1059 ret->DEPEND = ret->_data;
1060 #define next_line(curr, next) \
1061 if ((ptr = strchr(ret->curr, '\n')) == NULL) { \
1062 warn("Invalid cache file '%s'", file); \
1063 goto err; \
1064 } \
1065 ret->next = ptr+1; \
1066 *ptr = '\0';
1067 next_line(DEPEND, RDEPEND)
1068 next_line(RDEPEND, SLOT)
1069 next_line(SLOT, SRC_URI)
1070 next_line(SRC_URI, RESTRICT)
1071 next_line(RESTRICT, HOMEPAGE)
1072 next_line(HOMEPAGE, LICENSE)
1073 next_line(LICENSE, DESCRIPTION)
1074 next_line(DESCRIPTION, KEYWORDS)
1075 next_line(KEYWORDS, INHERITED)
1076 next_line(INHERITED, IUSE)
1077 next_line(IUSE, CDEPEND)
1078 next_line(CDEPEND, PDEPEND)
1079 next_line(PDEPEND, PROVIDE)
1080 next_line(PROVIDE, EAPI)
1081 next_line(EAPI, PROPERTIES)
1082 #undef next_line
1083 ptr = strchr(ptr+1, '\n');
1084 *ptr = '\0';
1085
1086 fclose(f);
1087
1088 return ret;
1089
1090 err:
1091 if (ret) cache_free(ret);
1092 return NULL;
1093 }
1094
1095 portage_cache *cache_read_file_md5(const char *file)
1096 {
1097 struct stat s;
1098 char *ptr, *endptr;
1099 FILE *f;
1100 portage_cache *ret = NULL;
1101 size_t len;
1102
1103 if ((f = fopen(file, "r")) == NULL)
1104 goto err;
1105
1106 if (fstat(fileno(f), &s) != 0)
1107 goto err;
1108 len = sizeof(*ret) + s.st_size + 1;
1109 ret = xzalloc(len);
1110 ptr = (char*)ret;
1111 ret->_data = ptr + sizeof(*ret);
1112 if ((off_t)fread(ret->_data, 1, s.st_size, f) != s.st_size)
1113 goto err;
1114
1115 ret->atom = atom_explode(file);
1116
1117 /* We have a block of key=value\n data.
1118 * KEY=VALUE\n
1119 * Where KEY does NOT contain:
1120 * \0 \n =
1121 * And VALUE does NOT contain:
1122 * \0 \n
1123 * */
1124 #define assign_var_cmp(keyname, cmpkey) \
1125 if (strncmp(keyptr, cmpkey, strlen(cmpkey)) == 0) { \
1126 ret->keyname = valptr; \
1127 continue; \
1128 }
1129 #define assign_var(keyname) \
1130 assign_var_cmp(keyname, #keyname);
1131
1132 ptr = ret->_data;
1133 endptr = strchr(ptr, '\0');
1134 if (endptr == NULL) {
1135 warn("Invalid cache file '%s' - could not find end of cache data", file);
1136 goto err;
1137 }
1138
1139 while (ptr != NULL && ptr != endptr) {
1140 char *keyptr;
1141 char *valptr;
1142 keyptr = ptr;
1143 valptr = strchr(ptr, '=');
1144 if (valptr == NULL) {
1145 warn("Invalid cache file '%s' val", file);
1146 goto err;
1147 }
1148 *valptr = '\0';
1149 valptr++;
1150 ptr = strchr(valptr, '\n');
1151 if (ptr == NULL) {
1152 warn("Invalid cache file '%s' key", file);
1153 goto err;
1154 }
1155 *ptr = '\0';
1156 ptr++;
1157
1158 assign_var(CDEPEND);
1159 assign_var(DEPEND);
1160 assign_var(DESCRIPTION);
1161 assign_var(EAPI);
1162 assign_var(HOMEPAGE);
1163 assign_var(INHERITED);
1164 assign_var(IUSE);
1165 assign_var(KEYWORDS);
1166 assign_var(LICENSE);
1167 assign_var(PDEPEND);
1168 assign_var(PROPERTIES);
1169 assign_var(PROVIDE);
1170 assign_var(RDEPEND);
1171 assign_var(RESTRICT);
1172 assign_var(SLOT);
1173 assign_var(SRC_URI);
1174 assign_var(DEFINED_PHASES);
1175 assign_var(REQUIRED_USE);
1176 assign_var(_eclasses_);
1177 assign_var(_md5_);
1178 warn("Cache file '%s' with unknown key %s", file, keyptr);
1179 }
1180 #undef assign_var
1181 #undef assign_var_cmp
1182
1183 fclose(f);
1184
1185 return ret;
1186
1187 err:
1188 fclose(f);
1189 if (ret) cache_free(ret);
1190 return NULL;
1191 }
1192
1193 void cache_dump(portage_cache *cache);
1194 void cache_dump(portage_cache *cache)
1195 {
1196 if (!cache)
1197 errf("Cache is empty !");
1198
1199 printf("DEPEND : %s\n", cache->DEPEND);
1200 printf("RDEPEND : %s\n", cache->RDEPEND);
1201 printf("SLOT : %s\n", cache->SLOT);
1202 printf("SRC_URI : %s\n", cache->SRC_URI);
1203 printf("RESTRICT : %s\n", cache->RESTRICT);
1204 printf("HOMEPAGE : %s\n", cache->HOMEPAGE);
1205 printf("LICENSE : %s\n", cache->LICENSE);
1206 printf("DESCRIPTION: %s\n", cache->DESCRIPTION);
1207 printf("KEYWORDS : %s\n", cache->KEYWORDS);
1208 printf("INHERITED : %s\n", cache->INHERITED);
1209 printf("IUSE : %s\n", cache->IUSE);
1210 printf("CDEPEND : %s\n", cache->CDEPEND);
1211 printf("PDEPEND : %s\n", cache->PDEPEND);
1212 printf("PROVIDE : %s\n", cache->PROVIDE);
1213 printf("EAPI : %s\n", cache->EAPI);
1214 printf("PROPERTIES : %s\n", cache->PROPERTIES);
1215 if (!cache->atom) return;
1216 printf("CATEGORY : %s\n", cache->atom->CATEGORY);
1217 printf("PN : %s\n", cache->atom->PN);
1218 printf("PV : %s\n", cache->atom->PV);
1219 printf("PVR : %s\n", cache->atom->PVR);
1220 }
1221
1222 void cache_free(portage_cache *cache)
1223 {
1224 if (!cache)
1225 errf("Cache is empty !");
1226 atom_implode(cache->atom);
1227 free(cache);
1228 }
1229
1230 char *atom_to_pvr(depend_atom *atom);
1231 char *atom_to_pvr(depend_atom *atom) {
1232 return (atom->PR_int == 0 ? atom->P : atom->PVR );
1233 }
1234
1235 static char *grab_vdb_item(const char *item, const char *CATEGORY, const char *PF)
1236 {
1237 static char buf[_Q_PATH_MAX];
1238
1239 snprintf(buf, sizeof(buf), "%s%s/%s/%s/%s", portroot, portvdb, CATEGORY, PF, item);
1240 eat_file(buf, buf, sizeof(buf));
1241 rmspace(buf);
1242
1243 return buf;
1244 }
1245
1246 _q_static queue *get_vdb_atoms(int fullcpv)
1247 {
1248 q_vdb_ctx *ctx;
1249
1250 int cfd, j;
1251 int dfd, i;
1252
1253 char buf[_Q_PATH_MAX];
1254 char slot[_Q_PATH_MAX];
1255
1256 struct dirent **cat;
1257 struct dirent **pf;
1258
1259 depend_atom *atom = NULL;
1260 queue *cpf = NULL;
1261
1262 ctx = q_vdb_open();
1263 if (!ctx)
1264 return NULL;
1265
1266 /* scan the cat first */
1267 if ((cfd = scandirat(ctx->vdb_fd, ".", &cat, q_vdb_filter_cat, alphasort)) < 0)
1268 goto fuckit;
1269
1270 for (j = 0; j < cfd; j++) {
1271 if ((dfd = scandirat(ctx->vdb_fd, cat[j]->d_name, &pf, q_vdb_filter_pkg, alphasort)) < 0)
1272 continue;
1273 for (i = 0; i < dfd; i++) {
1274 snprintf(buf, sizeof(buf), "%s/%s", cat[j]->d_name, pf[i]->d_name);
1275 if ((atom = atom_explode(buf)) == NULL)
1276 continue;
1277
1278 slot[0] = '0';
1279 slot[1] = 0;
1280 strncat(buf, "/SLOT", sizeof(buf));
1281 eat_file_at(ctx->vdb_fd, buf, buf, sizeof(buf));
1282 rmspace(buf);
1283
1284 if (fullcpv) {
1285 if (atom->PR_int)
1286 snprintf(buf, sizeof(buf), "%s/%s-%s-r%i", atom->CATEGORY, atom->PN, atom->PV, atom->PR_int);
1287 else
1288 snprintf(buf, sizeof(buf), "%s/%s-%s", atom->CATEGORY, atom->PN, atom->PV);
1289 } else {
1290 snprintf(buf, sizeof(buf), "%s/%s", atom->CATEGORY, atom->PN);
1291 }
1292 atom_implode(atom);
1293 cpf = add_set(buf, slot, cpf);
1294 }
1295 scandir_free(pf, dfd);
1296 }
1297 scandir_free(cat, cfd);
1298
1299 fuckit:
1300 q_vdb_close(ctx);
1301 return cpf;
1302 }
1303
1304 void cleanup(void)
1305 {
1306 reinitialize_as_needed();
1307 free_sets(virtuals);
1308 fclose(stderr);
1309 }
1310
1311 int main(int argc, char **argv)
1312 {
1313 struct stat st;
1314 IF_DEBUG(init_coredumps());
1315 argv0 = argv[0];
1316
1317 #ifdef ENABLE_NLS /* never tested */
1318 setlocale(LC_ALL, "");
1319 bindtextdomain(argv0, CONFIG_EPREFIX "usr/share/locale");
1320 textdomain(argv0);
1321 #endif
1322 #if 1
1323 if (fstat(fileno(stdout), &st) != -1)
1324 if (!isatty(fileno(stdout)))
1325 if (S_ISFIFO(st.st_mode) == 0)
1326 no_colors();
1327 #endif
1328 if ((getenv("TERM") == NULL) || (strcmp(getenv("TERM"), "dumb") == 0))
1329 no_colors();
1330
1331 initialize_portage_env();
1332 atexit(cleanup);
1333 optind = 0;
1334 return q_main(argc, argv);
1335 }
1336
1337 #include "include_applets.h"

  ViewVC Help
Powered by ViewVC 1.1.20