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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20