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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20