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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2891 - (show annotations) (download) (as text)
Tue Sep 18 16:57:39 2007 UTC (6 years, 9 months ago) by uberlord
File MIME type: text/x-csrc
File size: 15367 byte(s)
Hide errors caused by old splash plugin for the time being
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 (! file)
323 return (NULL);
324
325 if (! (fp = fopen (file, "r"))) {
326 ewarn ("rc_get_config `%s': %s", file, strerror (errno));
327 return (NULL);
328 }
329
330 while (fgets (buffer, RC_LINEBUFFER, fp)) {
331 p = buffer;
332
333 /* Strip leading spaces/tabs */
334 while ((*p == ' ') || (*p == '\t'))
335 p++;
336
337 if (! p || strlen (p) < 3 || p[0] == '#')
338 continue;
339
340 /* Get entry */
341 token = strsep (&p, "=");
342
343 if (! token)
344 continue;
345
346 entry = rc_xstrdup (token);
347
348 /* Preserve shell coloring */
349 if (*p == '$')
350 token = p;
351 else
352 do {
353 /* Bash variables are usually quoted */
354 token = strsep (&p, "\"\'");
355 } while ((token) && (strlen (token) == 0));
356
357 /* Drop a newline if that's all we have */
358 i = strlen (token) - 1;
359 if (token[i] == 10)
360 token[i] = 0;
361
362 i = strlen (entry) + strlen (token) + 2;
363 newline = rc_xmalloc (i);
364 snprintf (newline, i, "%s=%s", entry, token);
365
366 replaced = false;
367 /* In shells the last item takes precedence, so we need to remove
368 any prior values we may already have */
369 STRLIST_FOREACH (list, line, i) {
370 char *tmp = rc_xstrdup (line);
371 linep = tmp;
372 linetok = strsep (&linep, "=");
373 if (strcmp (linetok, entry) == 0) {
374 /* We have a match now - to save time we directly replace it */
375 free (list[i - 1]);
376 list[i - 1] = newline;
377 replaced = true;
378 free (tmp);
379 break;
380 }
381 free (tmp);
382 }
383
384 if (! replaced) {
385 rc_strlist_addsort (&list, newline);
386 free (newline);
387 }
388 free (entry);
389 }
390 fclose (fp);
391
392 return (list);
393 }
394 librc_hidden_def(rc_get_config)
395
396 char *rc_get_config_entry (char **list, const char *entry)
397 {
398 char *line;
399 int i;
400 char *p;
401
402 STRLIST_FOREACH (list, line, i) {
403 p = strchr (line, '=');
404 if (p && strncmp (entry, line, p - line) == 0)
405 return (p += 1);
406 }
407
408 return (NULL);
409 }
410 librc_hidden_def(rc_get_config_entry)
411
412 char **rc_get_list (const char *file)
413 {
414 FILE *fp;
415 char buffer[RC_LINEBUFFER];
416 char *p;
417 char *token;
418 char **list = NULL;
419
420 if (! (fp = fopen (file, "r"))) {
421 ewarn ("rc_get_list `%s': %s", file, strerror (errno));
422 return (NULL);
423 }
424
425 while (fgets (buffer, RC_LINEBUFFER, fp)) {
426 p = buffer;
427
428 /* Strip leading spaces/tabs */
429 while ((*p == ' ') || (*p == '\t'))
430 p++;
431
432 /* Get entry - we do not want comments */
433 token = strsep (&p, "#");
434 if (token && (strlen (token) > 1)) {
435 /* Stip the newline if present */
436 if (token[strlen (token) - 1] == '\n')
437 token[strlen (token) - 1] = 0;
438
439 rc_strlist_add (&list, token);
440 }
441 }
442 fclose (fp);
443
444 return (list);
445 }
446 librc_hidden_def(rc_get_list)
447
448 char **rc_filter_env (void)
449 {
450 char **env = NULL;
451 char **whitelist = NULL;
452 char *env_name = NULL;
453 char **profile = NULL;
454 int count = 0;
455 bool got_path = false;
456 char *env_var;
457 int env_len;
458 char *p;
459 char *token;
460 char *sep;
461 char *e;
462 int pplen = strlen (PATH_PREFIX);
463
464 whitelist = rc_get_list (SYS_WHITELIST);
465 if (! whitelist)
466 ewarn ("system environment whitelist (" SYS_WHITELIST ") missing");
467
468 env = rc_get_list (USR_WHITELIST);
469 rc_strlist_join (&whitelist, env);
470 rc_strlist_free (env);
471 env = NULL;
472
473 if (! whitelist)
474 return (NULL);
475
476 if (rc_is_file (PROFILE_ENV))
477 profile = rc_get_config (PROFILE_ENV);
478
479 STRLIST_FOREACH (whitelist, env_name, count) {
480 char *space = strchr (env_name, ' ');
481 if (space)
482 *space = 0;
483
484 env_var = getenv (env_name);
485
486 if (! env_var && profile) {
487 env_len = strlen (env_name) + strlen ("export ") + 1;
488 p = rc_xmalloc (sizeof (char *) * env_len);
489 snprintf (p, env_len, "export %s", env_name);
490 env_var = rc_get_config_entry (profile, p);
491 free (p);
492 }
493
494 if (! env_var)
495 continue;
496
497 /* Ensure our PATH is prefixed with the system locations first
498 for a little extra security */
499 if (strcmp (env_name, "PATH") == 0 &&
500 strncmp (PATH_PREFIX, env_var, pplen) != 0)
501 {
502 got_path = true;
503 env_len = strlen (env_name) + strlen (env_var) + pplen + 2;
504 e = p = rc_xmalloc (sizeof (char *) * env_len);
505 p += snprintf (e, env_len, "%s=%s", env_name, PATH_PREFIX);
506
507 /* Now go through the env var and only add bits not in our PREFIX */
508 sep = env_var;
509 while ((token = strsep (&sep, ":"))) {
510 char *np = rc_xstrdup (PATH_PREFIX);
511 char *npp = np;
512 char *tok = NULL;
513 while ((tok = strsep (&npp, ":")))
514 if (strcmp (tok, token) == 0)
515 break;
516 if (! tok)
517 p += snprintf (p, env_len - (p - e), ":%s", token);
518 free (np);
519 }
520 *p++ = 0;
521 } else {
522 env_len = strlen (env_name) + strlen (env_var) + 2;
523 e = rc_xmalloc (sizeof (char *) * env_len);
524 snprintf (e, env_len, "%s=%s", env_name, env_var);
525 }
526
527 rc_strlist_add (&env, e);
528 free (e);
529 }
530
531 /* We filtered the env but didn't get a PATH? Very odd.
532 However, we do need a path, so use a default. */
533 if (! got_path) {
534 env_len = strlen ("PATH=") + strlen (PATH_PREFIX) + 2;
535 p = rc_xmalloc (sizeof (char *) * env_len);
536 snprintf (p, env_len, "PATH=%s", PATH_PREFIX);
537 rc_strlist_add (&env, p);
538 free (p);
539 }
540
541 rc_strlist_free (whitelist);
542 rc_strlist_free (profile);
543
544 return (env);
545 }
546 librc_hidden_def(rc_filter_env)
547
548 /* Other systems may need this at some point, but for now it's Linux only */
549 #ifdef __linux__
550 static bool file_regex (const char *file, const char *regex)
551 {
552 FILE *fp;
553 char buffer[RC_LINEBUFFER];
554 regex_t re;
555 bool retval = false;
556 int result;
557
558 if (! rc_exists (file))
559 return (false);
560
561 if (! (fp = fopen (file, "r"))) {
562 ewarn ("file_regex `%s': %s", file, strerror (errno));
563 return (false);
564 }
565
566 if ((result = regcomp (&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) {
567 fclose (fp);
568 regerror (result, &re, buffer, sizeof (buffer));
569 eerror ("file_regex: %s", buffer);
570 return (false);
571 }
572
573 while (fgets (buffer, RC_LINEBUFFER, fp)) {
574 if (regexec (&re, buffer, 0, NULL, 0) == 0)
575 {
576 retval = true;
577 break;
578 }
579 }
580 fclose (fp);
581 regfree (&re);
582
583 return (retval);
584 }
585 #endif
586
587 char **rc_make_env (void)
588 {
589 char **env = NULL;
590 char *line;
591 int i;
592 char *p;
593 char **config;
594 char *e;
595 #ifdef __linux__
596 char sys[6];
597 #endif
598 struct utsname uts;
599 bool has_net_fs_list = false;
600 FILE *fp;
601 char buffer[PATH_MAX];
602
603 /* Don't trust environ for softlevel yet */
604 snprintf (buffer, PATH_MAX, "%s.%s", RC_CONFIG, rc_get_runlevel());
605 if (rc_exists (buffer))
606 config = rc_get_config (buffer);
607 else
608 config = rc_get_config (RC_CONFIG);
609
610 STRLIST_FOREACH (config, line, i) {
611 p = strchr (line, '=');
612 if (! p)
613 continue;
614
615 *p = 0;
616 e = getenv (line);
617 if (! e) {
618 *p = '=';
619 rc_strlist_add (&env, line);
620 } else {
621 int len = strlen (line) + strlen (e) + 2;
622 char *new = rc_xmalloc (sizeof (char *) * len);
623 snprintf (new, len, "%s=%s", line, e);
624 rc_strlist_add (&env, new);
625 free (new);
626 }
627 }
628 rc_strlist_free (config);
629
630 /* One char less to drop the trailing / */
631 i = strlen ("RC_LIBDIR=") + strlen (RC_LIBDIR) + 1;
632 line = rc_xmalloc (sizeof (char *) * i);
633 snprintf (line, i, "RC_LIBDIR=" RC_LIBDIR);
634 rc_strlist_add (&env, line);
635 free (line);
636
637 /* One char less to drop the trailing / */
638 i = strlen ("RC_SVCDIR=") + strlen (RC_SVCDIR) + 1;
639 line = rc_xmalloc (sizeof (char *) * i);
640 snprintf (line, i, "RC_SVCDIR=" RC_SVCDIR);
641 rc_strlist_add (&env, line);
642 free (line);
643
644 rc_strlist_add (&env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT);
645
646 p = rc_get_runlevel ();
647 i = strlen ("RC_SOFTLEVEL=") + strlen (p) + 1;
648 line = rc_xmalloc (sizeof (char *) * i);
649 snprintf (line, i, "RC_SOFTLEVEL=%s", p);
650 rc_strlist_add (&env, line);
651 free (line);
652
653 if (rc_exists (RC_KSOFTLEVEL)) {
654 if (! (fp = fopen (RC_KSOFTLEVEL, "r")))
655 eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
656 else {
657 memset (buffer, 0, sizeof (buffer));
658 if (fgets (buffer, sizeof (buffer), fp)) {
659 i = strlen (buffer) - 1;
660 if (buffer[i] == '\n')
661 buffer[i] = 0;
662 i += strlen ("RC_DEFAULTLEVEL=") + 2;
663 line = rc_xmalloc (sizeof (char *) * i);
664 snprintf (line, i, "RC_DEFAULTLEVEL=%s", buffer);
665 rc_strlist_add (&env, line);
666 free (line);
667 }
668 fclose (fp);
669 }
670 } else
671 rc_strlist_add (&env, "RC_DEFAULTLEVEL=" RC_LEVEL_DEFAULT);
672
673
674 #ifdef __linux__
675 /* Linux can run some funky stuff like Xen, VServer, UML, etc
676 We store this special system in RC_SYS so our scripts run fast */
677 memset (sys, 0, sizeof (sys));
678
679 if (rc_is_dir ("/proc/xen")) {
680 fp = fopen ("/proc/xen/capabilities", "r");
681 if (fp) {
682 fclose (fp);
683 if (file_regex ("/proc/xen/capabilities", "control_d"))
684 snprintf (sys, sizeof (sys), "XENU");
685 }
686 if (! sys[0])
687 snprintf (sys, sizeof (sys), "XEN0");
688 } else if (file_regex ("/proc/cpuinfo", "UML")) {
689 snprintf (sys, sizeof (sys), "UML");
690 } else if (file_regex ("/proc/self/status",
691 "(s_context|VxID|envID):[[:space:]]*[1-9]"))
692 {
693 snprintf (sys, sizeof (sys), "VPS");
694 }
695
696 if (sys[0]) {
697 i = strlen ("RC_SYS=") + strlen (sys) + 2;
698 line = rc_xmalloc (sizeof (char *) * i);
699 snprintf (line, i, "RC_SYS=%s", sys);
700 rc_strlist_add (&env, line);
701 free (line);
702 }
703
704 #endif
705
706 /* Only add a NET_FS list if not defined */
707 STRLIST_FOREACH (env, line, i)
708 if (strncmp (line, "RC_NET_FS_LIST=", strlen ("RC_NET_FS_LIST=")) == 0) {
709 has_net_fs_list = true;
710 break;
711 }
712
713 if (! has_net_fs_list) {
714 i = strlen ("RC_NET_FS_LIST=") + strlen (RC_NET_FS_LIST_DEFAULT) + 1;
715 line = rc_xmalloc (sizeof (char *) * i);
716 snprintf (line, i, "RC_NET_FS_LIST=%s", RC_NET_FS_LIST_DEFAULT);
717 rc_strlist_add (&env, line);
718 free (line);
719 }
720
721 /* Some scripts may need to take a different code path if Linux/FreeBSD, etc
722 To save on calling uname, we store it in an environment variable */
723 if (uname (&uts) == 0) {
724 i = strlen ("RC_UNAME=") + strlen (uts.sysname) + 2;
725 line = rc_xmalloc (sizeof (char *) * i);
726 snprintf (line, i, "RC_UNAME=%s", uts.sysname);
727 rc_strlist_add (&env, line);
728 free (line);
729 }
730
731 return (env);
732 }
733 librc_hidden_def(rc_make_env)

  ViewVC Help
Powered by ViewVC 1.1.20