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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2889 - (show annotations) (download) (as text)
Tue Sep 18 15:43:19 2007 UTC (6 years, 11 months ago) by uberlord
File MIME type: text/x-csrc
File size: 15339 byte(s)
Don't be an ass - don't free the 2nd list. Instead just empty 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_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 env = rc_get_list (USR_WHITELIST);
466 rc_strlist_join (&whitelist, env);
467 rc_strlist_free (env);
468 env = NULL;
469
470 if (! whitelist)
471 return (NULL);
472
473 if (rc_is_file (PROFILE_ENV))
474 profile = rc_get_config (PROFILE_ENV);
475
476 STRLIST_FOREACH (whitelist, env_name, count) {
477 char *space = strchr (env_name, ' ');
478 if (space)
479 *space = 0;
480
481 env_var = getenv (env_name);
482
483 if (! env_var && profile) {
484 env_len = strlen (env_name) + strlen ("export ") + 1;
485 p = rc_xmalloc (sizeof (char *) * env_len);
486 snprintf (p, env_len, "export %s", env_name);
487 env_var = rc_get_config_entry (profile, p);
488 free (p);
489 }
490
491 if (! env_var)
492 continue;
493
494 /* Ensure our PATH is prefixed with the system locations first
495 for a little extra security */
496 if (strcmp (env_name, "PATH") == 0 &&
497 strncmp (PATH_PREFIX, env_var, pplen) != 0)
498 {
499 got_path = true;
500 env_len = strlen (env_name) + strlen (env_var) + pplen + 2;
501 e = p = rc_xmalloc (sizeof (char *) * env_len);
502 p += snprintf (e, env_len, "%s=%s", env_name, PATH_PREFIX);
503
504 /* Now go through the env var and only add bits not in our PREFIX */
505 sep = env_var;
506 while ((token = strsep (&sep, ":"))) {
507 char *np = rc_xstrdup (PATH_PREFIX);
508 char *npp = np;
509 char *tok = NULL;
510 while ((tok = strsep (&npp, ":")))
511 if (strcmp (tok, token) == 0)
512 break;
513 if (! tok)
514 p += snprintf (p, env_len - (p - e), ":%s", token);
515 free (np);
516 }
517 *p++ = 0;
518 } else {
519 env_len = strlen (env_name) + strlen (env_var) + 2;
520 e = rc_xmalloc (sizeof (char *) * env_len);
521 snprintf (e, env_len, "%s=%s", env_name, env_var);
522 }
523
524 rc_strlist_add (&env, e);
525 free (e);
526 }
527
528 /* We filtered the env but didn't get a PATH? Very odd.
529 However, we do need a path, so use a default. */
530 if (! got_path) {
531 env_len = strlen ("PATH=") + strlen (PATH_PREFIX) + 2;
532 p = rc_xmalloc (sizeof (char *) * env_len);
533 snprintf (p, env_len, "PATH=%s", PATH_PREFIX);
534 rc_strlist_add (&env, p);
535 free (p);
536 }
537
538 rc_strlist_free (whitelist);
539 rc_strlist_free (profile);
540
541 return (env);
542 }
543 librc_hidden_def(rc_filter_env)
544
545 /* Other systems may need this at some point, but for now it's Linux only */
546 #ifdef __linux__
547 static bool file_regex (const char *file, const char *regex)
548 {
549 FILE *fp;
550 char buffer[RC_LINEBUFFER];
551 regex_t re;
552 bool retval = false;
553 int result;
554
555 if (! rc_exists (file))
556 return (false);
557
558 if (! (fp = fopen (file, "r"))) {
559 ewarn ("file_regex `%s': %s", file, strerror (errno));
560 return (false);
561 }
562
563 if ((result = regcomp (&re, regex, REG_EXTENDED | REG_NOSUB)) != 0) {
564 fclose (fp);
565 regerror (result, &re, buffer, sizeof (buffer));
566 eerror ("file_regex: %s", buffer);
567 return (false);
568 }
569
570 while (fgets (buffer, RC_LINEBUFFER, fp)) {
571 if (regexec (&re, buffer, 0, NULL, 0) == 0)
572 {
573 retval = true;
574 break;
575 }
576 }
577 fclose (fp);
578 regfree (&re);
579
580 return (retval);
581 }
582 #endif
583
584 char **rc_make_env (void)
585 {
586 char **env = NULL;
587 char *line;
588 int i;
589 char *p;
590 char **config;
591 char *e;
592 #ifdef __linux__
593 char sys[6];
594 #endif
595 struct utsname uts;
596 bool has_net_fs_list = false;
597 FILE *fp;
598 char buffer[PATH_MAX];
599
600 /* Don't trust environ for softlevel yet */
601 snprintf (buffer, PATH_MAX, "%s.%s", RC_CONFIG, rc_get_runlevel());
602 if (rc_exists (buffer))
603 config = rc_get_config (buffer);
604 else
605 config = rc_get_config (RC_CONFIG);
606
607 STRLIST_FOREACH (config, line, i) {
608 p = strchr (line, '=');
609 if (! p)
610 continue;
611
612 *p = 0;
613 e = getenv (line);
614 if (! e) {
615 *p = '=';
616 rc_strlist_add (&env, line);
617 } else {
618 int len = strlen (line) + strlen (e) + 2;
619 char *new = rc_xmalloc (sizeof (char *) * len);
620 snprintf (new, len, "%s=%s", line, e);
621 rc_strlist_add (&env, new);
622 free (new);
623 }
624 }
625 rc_strlist_free (config);
626
627 /* One char less to drop the trailing / */
628 i = strlen ("RC_LIBDIR=") + strlen (RC_LIBDIR) + 1;
629 line = rc_xmalloc (sizeof (char *) * i);
630 snprintf (line, i, "RC_LIBDIR=" RC_LIBDIR);
631 rc_strlist_add (&env, line);
632 free (line);
633
634 /* One char less to drop the trailing / */
635 i = strlen ("RC_SVCDIR=") + strlen (RC_SVCDIR) + 1;
636 line = rc_xmalloc (sizeof (char *) * i);
637 snprintf (line, i, "RC_SVCDIR=" RC_SVCDIR);
638 rc_strlist_add (&env, line);
639 free (line);
640
641 rc_strlist_add (&env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT);
642
643 p = rc_get_runlevel ();
644 i = strlen ("RC_SOFTLEVEL=") + strlen (p) + 1;
645 line = rc_xmalloc (sizeof (char *) * i);
646 snprintf (line, i, "RC_SOFTLEVEL=%s", p);
647 rc_strlist_add (&env, line);
648 free (line);
649
650 if (rc_exists (RC_KSOFTLEVEL)) {
651 if (! (fp = fopen (RC_KSOFTLEVEL, "r")))
652 eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
653 else {
654 memset (buffer, 0, sizeof (buffer));
655 if (fgets (buffer, sizeof (buffer), fp)) {
656 i = strlen (buffer) - 1;
657 if (buffer[i] == '\n')
658 buffer[i] = 0;
659 i += strlen ("RC_DEFAULTLEVEL=") + 2;
660 line = rc_xmalloc (sizeof (char *) * i);
661 snprintf (line, i, "RC_DEFAULTLEVEL=%s", buffer);
662 rc_strlist_add (&env, line);
663 free (line);
664 }
665 fclose (fp);
666 }
667 } else
668 rc_strlist_add (&env, "RC_DEFAULTLEVEL=" RC_LEVEL_DEFAULT);
669
670
671 #ifdef __linux__
672 /* Linux can run some funky stuff like Xen, VServer, UML, etc
673 We store this special system in RC_SYS so our scripts run fast */
674 memset (sys, 0, sizeof (sys));
675
676 if (rc_is_dir ("/proc/xen")) {
677 fp = fopen ("/proc/xen/capabilities", "r");
678 if (fp) {
679 fclose (fp);
680 if (file_regex ("/proc/xen/capabilities", "control_d"))
681 snprintf (sys, sizeof (sys), "XENU");
682 }
683 if (! sys[0])
684 snprintf (sys, sizeof (sys), "XEN0");
685 } else if (file_regex ("/proc/cpuinfo", "UML")) {
686 snprintf (sys, sizeof (sys), "UML");
687 } else if (file_regex ("/proc/self/status",
688 "(s_context|VxID|envID):[[:space:]]*[1-9]"))
689 {
690 snprintf (sys, sizeof (sys), "VPS");
691 }
692
693 if (sys[0]) {
694 i = strlen ("RC_SYS=") + strlen (sys) + 2;
695 line = rc_xmalloc (sizeof (char *) * i);
696 snprintf (line, i, "RC_SYS=%s", sys);
697 rc_strlist_add (&env, line);
698 free (line);
699 }
700
701 #endif
702
703 /* Only add a NET_FS list if not defined */
704 STRLIST_FOREACH (env, line, i)
705 if (strncmp (line, "RC_NET_FS_LIST=", strlen ("RC_NET_FS_LIST=")) == 0) {
706 has_net_fs_list = true;
707 break;
708 }
709
710 if (! has_net_fs_list) {
711 i = strlen ("RC_NET_FS_LIST=") + strlen (RC_NET_FS_LIST_DEFAULT) + 1;
712 line = rc_xmalloc (sizeof (char *) * i);
713 snprintf (line, i, "RC_NET_FS_LIST=%s", RC_NET_FS_LIST_DEFAULT);
714 rc_strlist_add (&env, line);
715 free (line);
716 }
717
718 /* Some scripts may need to take a different code path if Linux/FreeBSD, etc
719 To save on calling uname, we store it in an environment variable */
720 if (uname (&uts) == 0) {
721 i = strlen ("RC_UNAME=") + strlen (uts.sysname) + 2;
722 line = rc_xmalloc (sizeof (char *) * i);
723 snprintf (line, i, "RC_UNAME=%s", uts.sysname);
724 rc_strlist_add (&env, line);
725 free (line);
726 }
727
728 return (env);
729 }
730 librc_hidden_def(rc_make_env)

  ViewVC Help
Powered by ViewVC 1.1.20