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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20