/[baselayout]/trunk/src/librc-misc.c
Gentoo

Contents of /trunk/src/librc-misc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2755 - (show annotations) (download) (as text)
Mon Jul 9 10:26:02 2007 UTC (7 years, 2 months ago) by uberlord
File MIME type: text/x-csrc
File size: 15768 byte(s)
Add an option to fork ldconfig in env-update, #182794. Also, preserve the entire line in /etc/env.d/foo if it begins with $
1 /*
2 rc-misc.c
3 rc misc functions
4 Copyright 2007 Gentoo Foundation
5 */
6
7 #include "librc.h"
8
9 #define ERRX eerrorx("out of memory");
10
11 #define PROFILE_ENV "/etc/profile.env"
12 #define SYS_WHITELIST RC_LIBDIR "conf.d/env_whitelist"
13 #define USR_WHITELIST "/etc/conf.d/env_whitelist"
14 #define RC_CONFIG "/etc/conf.d/rc"
15
16 #define PATH_PREFIX RC_LIBDIR "bin:/bin:/sbin:/usr/bin:/usr/sbin"
17
18 #ifndef S_IXUGO
19 # define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
20 #endif
21
22 void *rc_xcalloc (size_t n, size_t size)
23 {
24 void *value = calloc (n, size);
25
26 if (value)
27 return value;
28
29 ERRX
30 }
31 librc_hidden_def(rc_xcalloc)
32
33 void *rc_xmalloc (size_t size)
34 {
35 void *value = malloc (size);
36
37 if (value)
38 return (value);
39
40 ERRX
41 }
42 librc_hidden_def(rc_xmalloc)
43
44 void *rc_xrealloc (void *ptr, size_t size)
45 {
46 void *value = realloc (ptr, size);
47
48 if (value)
49 return (value);
50
51 ERRX
52 }
53 librc_hidden_def(rc_xrealloc)
54
55 char *rc_xstrdup (const char *str)
56 {
57 char *value;
58
59 if (! str)
60 return (NULL);
61
62 value = strdup (str);
63
64 if (value)
65 return (value);
66
67 ERRX
68 }
69 librc_hidden_def(rc_xstrdup)
70
71 bool rc_is_env (const char *var, const char *val)
72 {
73 char *v;
74
75 if (! var)
76 return (false);
77
78 v = getenv (var);
79 if (! v)
80 return (val == NULL ? true : false);
81
82 return (strcasecmp (v, val) == 0 ? true : false);
83 }
84 librc_hidden_def(rc_is_env)
85
86 char *rc_strcatpaths (const char *path1, const char *paths, ...)
87 {
88 va_list ap;
89 int length;
90 int i;
91 char *p;
92 char *path;
93 char *pathp;
94
95 if (! path1 || ! paths)
96 return (NULL);
97
98 length = strlen (path1) + strlen (paths) + 3;
99 i = 0;
100 va_start (ap, paths);
101 while ((p = va_arg (ap, char *)) != NULL)
102 length += strlen (p) + 1;
103 va_end (ap);
104
105 path = rc_xmalloc (length);
106 memset (path, 0, length);
107 memcpy (path, path1, strlen (path1));
108 pathp = path + strlen (path1) - 1;
109 if (*pathp != '/') {
110 pathp++;
111 *pathp++ = '/';
112 }
113 else
114 pathp++;
115 memcpy (pathp, paths, strlen (paths));
116 pathp += strlen (paths);
117
118 va_start (ap, paths);
119 while ((p = va_arg (ap, char *)) != NULL) {
120 if (*pathp != '/')
121 *pathp++ = '/';
122 i = strlen (p);
123 memcpy (pathp, p, i);
124 pathp += i;
125 }
126 va_end (ap);
127
128 *pathp++ = 0;
129
130 return (path);
131 }
132 librc_hidden_def(rc_strcatpaths)
133
134 bool rc_exists (const char *pathname)
135 {
136 struct stat buf;
137
138 if (! pathname)
139 return (false);
140
141 if (stat (pathname, &buf) == 0)
142 return (true);
143
144 errno = 0;
145 return (false);
146 }
147 librc_hidden_def(rc_exists)
148
149 bool rc_is_file (const char *pathname)
150 {
151 struct stat buf;
152
153 if (! pathname)
154 return (false);
155
156 if (stat (pathname, &buf) == 0)
157 return (S_ISREG (buf.st_mode));
158
159 errno = 0;
160 return (false);
161 }
162 librc_hidden_def(rc_is_file)
163
164 bool rc_is_dir (const char *pathname)
165 {
166 struct stat buf;
167
168 if (! pathname)
169 return (false);
170
171 if (stat (pathname, &buf) == 0)
172 return (S_ISDIR (buf.st_mode));
173
174 errno = 0;
175 return (false);
176 }
177 librc_hidden_def(rc_is_dir)
178
179 bool rc_is_link (const char *pathname)
180 {
181 struct stat buf;
182
183 if (! pathname)
184 return (false);
185
186 if (lstat (pathname, &buf) == 0)
187 return (S_ISLNK (buf.st_mode));
188
189 errno = 0;
190 return (false);
191 }
192 librc_hidden_def(rc_is_link)
193
194 bool rc_is_exec (const char *pathname)
195 {
196 struct stat buf;
197
198 if (! pathname)
199 return (false);
200
201 if (lstat (pathname, &buf) == 0)
202 return (buf.st_mode & S_IXUGO);
203
204 errno = 0;
205 return (false);
206 }
207 librc_hidden_def(rc_is_exec)
208
209 char **rc_ls_dir (char **list, const char *dir, int options)
210 {
211 DIR *dp;
212 struct dirent *d;
213
214 if (! dir)
215 return (list);
216
217 if ((dp = opendir (dir)) == NULL) {
218 eerror ("failed to opendir `%s': %s", dir, strerror (errno));
219 return (list);
220 }
221
222 errno = 0;
223 while (((d = readdir (dp)) != NULL) && errno == 0) {
224 if (d->d_name[0] != '.') {
225 if (options & RC_LS_INITD) {
226 int l = strlen (d->d_name);
227 char *init = rc_strcatpaths (RC_INITDIR, d->d_name,
228 (char *) NULL);
229 bool ok = rc_exists (init);
230 free (init);
231 if (! ok)
232 continue;
233
234 /* .sh files are not init scripts */
235 if (l > 2 && d->d_name[l - 3] == '.' &&
236 d->d_name[l - 2] == 's' &&
237 d->d_name[l - 1] == 'h')
238 continue;
239 }
240 list = rc_strlist_addsort (list, d->d_name);
241 }
242 }
243 closedir (dp);
244
245 if (errno != 0) {
246 eerror ("failed to readdir `%s': %s", dir, strerror (errno));
247 rc_strlist_free (list);
248 return (NULL);
249 }
250
251 return (list);
252 }
253 librc_hidden_def(rc_ls_dir)
254
255 bool rc_rm_dir (const char *pathname, bool top)
256 {
257 DIR *dp;
258 struct dirent *d;
259
260 if (! pathname)
261 return (false);
262
263 if ((dp = opendir (pathname)) == NULL) {
264 eerror ("failed to opendir `%s': %s", pathname, strerror (errno));
265 return (false);
266 }
267
268 errno = 0;
269 while (((d = readdir (dp)) != NULL) && errno == 0) {
270 if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) {
271 char *tmp = rc_strcatpaths (pathname, d->d_name, (char *) NULL);
272 if (d->d_type == DT_DIR) {
273 if (! rc_rm_dir (tmp, true))
274 {
275 free (tmp);
276 closedir (dp);
277 return (false);
278 }
279 } else {
280 if (unlink (tmp)) {
281 eerror ("failed to unlink `%s': %s", tmp, strerror (errno));
282 free (tmp);
283 closedir (dp);
284 return (false);
285 }
286 }
287 free (tmp);
288 }
289 }
290 if (errno != 0)
291 eerror ("failed to readdir `%s': %s", pathname, strerror (errno));
292 closedir (dp);
293
294 if (top && rmdir (pathname) != 0) {
295 eerror ("failed to rmdir `%s': %s", pathname, strerror (errno));
296 return false;
297 }
298
299 return (true);
300 }
301 librc_hidden_def(rc_rm_dir)
302
303 char **rc_get_config (char **list, const char *file)
304 {
305 FILE *fp;
306 char buffer[RC_LINEBUFFER];
307 char *p;
308 char *token;
309 char *line;
310 char *linep;
311 char *linetok;
312 int i = 0;
313 bool replaced;
314 char *entry;
315 char *newline;
316
317 if (! (fp = fopen (file, "r"))) {
318 ewarn ("load_config_file `%s': %s", file, strerror (errno));
319 return (list);
320 }
321
322 while (fgets (buffer, RC_LINEBUFFER, fp)) {
323 p = buffer;
324
325 /* Strip leading spaces/tabs */
326 while ((*p == ' ') || (*p == '\t'))
327 p++;
328
329 if (! p || strlen (p) < 3 || p[0] == '#')
330 continue;
331
332 /* Get entry */
333 token = strsep (&p, "=");
334 if (! token)
335 continue;
336
337 entry = rc_xstrdup (token);
338
339 /* Preserve shell coloring */
340 if (*p == '$')
341 token = p;
342 else
343 do {
344 /* Bash variables are usually quoted */
345 token = strsep (&p, "\"\'");
346 } while ((token) && (strlen (token) == 0));
347
348 /* Drop a newline if that's all we have */
349 i = strlen (token) - 1;
350 if (token[i] == 10)
351 token[i] = 0;
352
353 i = strlen (entry) + strlen (token) + 2;
354 newline = rc_xmalloc (i);
355 snprintf (newline, i, "%s=%s", entry, token);
356
357 replaced = false;
358 /* In shells the last item takes precedence, so we need to remove
359 any prior values we may already have */
360 STRLIST_FOREACH (list, line, i) {
361 char *tmp = rc_xstrdup (line);
362 linep = tmp;
363 linetok = strsep (&linep, "=");
364 if (strcmp (linetok, entry) == 0) {
365 /* We have a match now - to save time we directly replace it */
366 free (list[i - 1]);
367 list[i - 1] = newline;
368 replaced = true;
369 free (tmp);
370 break;
371 }
372 free (tmp);
373 }
374
375 if (! replaced) {
376 list = rc_strlist_addsort (list, newline);
377 free (newline);
378 }
379 free (entry);
380 }
381 fclose (fp);
382
383 return (list);
384 }
385 librc_hidden_def(rc_get_config)
386
387 char *rc_get_config_entry (char **list, const char *entry)
388 {
389 char *line;
390 int i;
391 char *p;
392
393 STRLIST_FOREACH (list, line, i) {
394 p = strchr (line, '=');
395 if (p && strncmp (entry, line, p - line) == 0)
396 return (p += 1);
397 }
398
399 return (NULL);
400 }
401 librc_hidden_def(rc_get_config_entry)
402
403 char **rc_get_list (char **list, const char *file)
404 {
405 FILE *fp;
406 char buffer[RC_LINEBUFFER];
407 char *p;
408 char *token;
409
410 if (! (fp = fopen (file, "r"))) {
411 ewarn ("rc_get_list `%s': %s", file, strerror (errno));
412 return (list);
413 }
414
415 while (fgets (buffer, RC_LINEBUFFER, fp)) {
416 p = buffer;
417
418 /* Strip leading spaces/tabs */
419 while ((*p == ' ') || (*p == '\t'))
420 p++;
421
422 /* Get entry - we do not want comments */
423 token = strsep (&p, "#");
424 if (token && (strlen (token) > 1)) {
425 /* Stip the newline if present */
426 if (token[strlen (token) - 1] == '\n')
427 token[strlen (token) - 1] = 0;
428
429 list = rc_strlist_add (list, token);
430 }
431 }
432 fclose (fp);
433
434 return (list);
435 }
436 librc_hidden_def(rc_get_list)
437
438 char **rc_filter_env (void)
439 {
440 char **env = NULL;
441 char **whitelist = NULL;
442 char *env_name = NULL;
443 char **profile = NULL;
444 int count = 0;
445 bool got_path = false;
446 char *env_var;
447 int env_len;
448 char *p;
449 char *token;
450 char *sep;
451 char *e;
452 int pplen = strlen (PATH_PREFIX);
453
454 whitelist = rc_get_list (whitelist, SYS_WHITELIST);
455 if (! whitelist)
456 ewarn ("system environment whitelist (" SYS_WHITELIST ") missing");
457
458 whitelist = rc_get_list (whitelist, USR_WHITELIST);
459
460 if (! whitelist)
461 return (NULL);
462
463 if (rc_is_file (PROFILE_ENV))
464 profile = rc_get_config (profile, PROFILE_ENV);
465
466 STRLIST_FOREACH (whitelist, env_name, count) {
467 char *space = strchr (env_name, ' ');
468 if (space)
469 *space = 0;
470
471 env_var = getenv (env_name);
472
473 if (! env_var && profile) {
474 env_len = strlen (env_name) + strlen ("export ") + 1;
475 p = rc_xmalloc (sizeof (char *) * env_len);
476 snprintf (p, env_len, "export %s", env_name);
477 env_var = rc_get_config_entry (profile, p);
478 free (p);
479 }
480
481 if (! env_var)
482 continue;
483
484 /* Ensure our PATH is prefixed with the system locations first
485 for a little extra security */
486 if (strcmp (env_name, "PATH") == 0 &&
487 strncmp (PATH_PREFIX, env_var, pplen) != 0)
488 {
489 got_path = true;
490 env_len = strlen (env_name) + strlen (env_var) + pplen + 2;
491 e = p = rc_xmalloc (sizeof (char *) * env_len);
492 p += snprintf (e, env_len, "%s=%s", env_name, PATH_PREFIX);
493
494 /* Now go through the env var and only add bits not in our PREFIX */
495 sep = env_var;
496 while ((token = strsep (&sep, ":"))) {
497 char *np = rc_xstrdup (PATH_PREFIX);
498 char *npp = np;
499 char *tok = NULL;
500 while ((tok = strsep (&npp, ":")))
501 if (strcmp (tok, token) == 0)
502 break;
503 if (! tok)
504 p += snprintf (p, env_len - (p - e), ":%s", token);
505 free (np);
506 }
507 *p++ = 0;
508 } else {
509 env_len = strlen (env_name) + strlen (env_var) + 2;
510 e = rc_xmalloc (sizeof (char *) * env_len);
511 snprintf (e, env_len, "%s=%s", env_name, env_var);
512 }
513
514 env = rc_strlist_add (env, e);
515 free (e);
516 }
517
518 /* We filtered the env but didn't get a PATH? Very odd.
519 However, we do need a path, so use a default. */
520 if (! got_path) {
521 env_len = strlen ("PATH=") + strlen (PATH_PREFIX) + 2;
522 p = rc_xmalloc (sizeof (char *) * env_len);
523 snprintf (p, env_len, "PATH=%s", PATH_PREFIX);
524 env = rc_strlist_add (env, p);
525 free (p);
526 }
527
528 rc_strlist_free (whitelist);
529 rc_strlist_free (profile);
530
531 return (env);
532 }
533 librc_hidden_def(rc_filter_env)
534
535 /* Other systems may need this at some point, but for now it's Linux only */
536 #ifdef __linux__
537 static bool file_regex (const char *file, const char *regex)
538 {
539 FILE *fp;
540 char buffer[RC_LINEBUFFER];
541 regex_t re;
542 bool retval = false;
543 int result;
544
545 if (! rc_exists (file))
546 return (false);
547
548 if (! (fp = fopen (file, "r"))) {
549 ewarn ("file_regex `%s': %s", file, strerror (errno));
550 return (false);
551 }
552
553 if ((result = regcomp (&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) {
554 fclose (fp);
555 regerror (result, &re, buffer, sizeof (buffer));
556 eerror ("file_regex: %s", buffer);
557 return (false);
558 }
559
560 while (fgets (buffer, RC_LINEBUFFER, fp)) {
561 if (regexec (&re, buffer, 0, NULL, 0) == 0)
562 {
563 retval = true;
564 break;
565 }
566 }
567 fclose (fp);
568 regfree (&re);
569
570 return (retval);
571 }
572 #endif
573
574 char **rc_config_env (char **env)
575 {
576 char *line;
577 int i;
578 char *p;
579 char **config;
580 char *e;
581 char sys[6];
582 struct utsname uts;
583 bool has_net_fs_list = false;
584 FILE *fp;
585 char buffer[PATH_MAX];
586
587 /* Don't trust environ for softlevel yet */
588 snprintf (buffer, PATH_MAX, "%s.%s", RC_CONFIG, rc_get_runlevel());
589 if (rc_exists (buffer))
590 config = rc_get_config (NULL, buffer);
591 else
592 config = rc_get_config (NULL, RC_CONFIG);
593
594 STRLIST_FOREACH (config, line, i) {
595 p = strchr (line, '=');
596 if (! p)
597 continue;
598
599 *p = 0;
600 e = getenv (line);
601 if (! e) {
602 *p = '=';
603 env = rc_strlist_add (env, line);
604 } else {
605 int len = strlen (line) + strlen (e) + 2;
606 char *new = rc_xmalloc (sizeof (char *) * len);
607 snprintf (new, len, "%s=%s", line, e);
608 env = rc_strlist_add (env, new);
609 free (new);
610 }
611 }
612 rc_strlist_free (config);
613
614 /* One char less to drop the trailing / */
615 i = strlen ("RC_LIBDIR=") + strlen (RC_LIBDIR);
616 line = rc_xmalloc (sizeof (char *) * i);
617 snprintf (line, i, "RC_LIBDIR=" RC_LIBDIR);
618 env = rc_strlist_add (env, line);
619 free (line);
620
621 /* One char less to drop the trailing / */
622 i = strlen ("RC_SVCDIR=") + strlen (RC_SVCDIR);
623 line = rc_xmalloc (sizeof (char *) * i);
624 snprintf (line, i, "RC_SVCDIR=" RC_SVCDIR);
625 env = rc_strlist_add (env, line);
626 free (line);
627
628 env = rc_strlist_add (env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT);
629
630 p = rc_get_runlevel ();
631 i = strlen ("RC_SOFTLEVEL=") + strlen (p) + 1;
632 line = rc_xmalloc (sizeof (char *) * i);
633 snprintf (line, i, "RC_SOFTLEVEL=%s", p);
634 env = rc_strlist_add (env, line);
635 free (line);
636
637 if (rc_exists (RC_SVCDIR "ksoftlevel")) {
638 if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r")))
639 eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel",
640 strerror (errno));
641 else {
642 memset (buffer, 0, sizeof (buffer));
643 if (fgets (buffer, sizeof (buffer), fp)) {
644 i = strlen (buffer) - 1;
645 if (buffer[i] == '\n')
646 buffer[i] = 0;
647 i += strlen ("RC_DEFAULTLEVEL=") + 2;
648 line = rc_xmalloc (sizeof (char *) * i);
649 snprintf (line, i, "RC_DEFAULTLEVEL=%s", buffer);
650 env = rc_strlist_add (env, line);
651 free (line);
652 }
653 fclose (fp);
654 }
655 } else
656 env = rc_strlist_add (env, "RC_DEFAULTLEVEL=" RC_LEVEL_DEFAULT);
657
658 /* Store the name of the tty that stdout is connected to
659 * We do this so our init scripts can call eflush without any knowledge
660 * of our fd's */
661 if (isatty (fileno (stdout))) {
662 if ((p = rc_xstrdup (ttyname (fileno (stdout))))) {
663 i = strlen ("RC_TTY=") + strlen (p) + 1;
664 line = rc_xmalloc (sizeof (char *) * i);
665 snprintf (line, i, "RC_TTY=%s", p);
666 env = rc_strlist_add (env, line);
667 free (p);
668 free (line);
669 }
670 }
671
672 memset (sys, 0, sizeof (sys));
673
674 /* Linux can run some funky stuff like Xen, VServer, UML, etc
675 We store this special system in RC_SYS so our scripts run fast */
676 #ifdef __linux__
677 if (rc_is_dir ("/proc/xen")) {
678 fp = fopen ("/proc/xen/capabilities", "r");
679 if (fp) {
680 fclose (fp);
681 if (file_regex ("/proc/xen/capabilities", "control_d"))
682 snprintf (sys, sizeof (sys), "XENU");
683 }
684 if (! sys[0])
685 snprintf (sys, sizeof (sys), "XEN0");
686 } else if (file_regex ("/proc/cpuinfo", "UML")) {
687 snprintf (sys, sizeof (sys), "UML");
688 } else if (file_regex ("/proc/self/status",
689 "(s_context|VxID|envID):[[:space:]]*[1-9]"))
690 {
691 snprintf (sys, sizeof (sys), "VPS");
692 }
693 #endif
694
695 /* Only add a NET_FS list if not defined */
696 STRLIST_FOREACH (env, line, i)
697 if (strncmp (line, "RC_NET_FS_LIST=", strlen ("RC_NET_FS_LIST=")) == 0) {
698 has_net_fs_list = true;
699 break;
700 }
701
702 if (! has_net_fs_list) {
703 i = strlen ("RC_NET_FS_LIST=") + strlen (RC_NET_FS_LIST_DEFAULT) + 1;
704 line = rc_xmalloc (sizeof (char *) * i);
705 snprintf (line, i, "RC_NET_FS_LIST=%s", RC_NET_FS_LIST_DEFAULT);
706 env = rc_strlist_add (env, line);
707 free (line);
708 }
709
710 if (sys[0]) {
711 i = strlen ("RC_SYS=") + strlen (sys) + 2;
712 line = rc_xmalloc (sizeof (char *) * i);
713 snprintf (line, i, "RC_SYS=%s", sys);
714 env = rc_strlist_add (env, line);
715 free (line);
716 }
717
718 /* Some scripts may need to take a different code path if Linux/FreeBSD, etc
719 To save on calling uname, we store it in an environment variable */
720 if (uname (&uts) == 0) {
721 i = strlen ("RC_UNAME=") + strlen (uts.sysname) + 2;
722 line = rc_xmalloc (sizeof (char *) * i);
723 snprintf (line, i, "RC_UNAME=%s", uts.sysname);
724 env = rc_strlist_add (env, line);
725 free (line);
726 }
727
728 return (env);
729 }
730 librc_hidden_def(rc_config_env)

  ViewVC Help
Powered by ViewVC 1.1.20