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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20