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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2676 - (show annotations) (download) (as text)
Wed May 2 12:33:56 2007 UTC (7 years, 6 months ago) by uberlord
File MIME type: text/x-csrc
File size: 15494 byte(s)
    SSD_NICELEVEL can now affect the nicelevel for daemons started
    by start-stop-daemon, #175397.
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 = rc_get_config (NULL, RC_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 STRLIST_FOREACH (config, line, i) {
584 p = strchr (line, '=');
585 if (! p)
586 continue;
587
588 *p = 0;
589 e = getenv (line);
590 if (! e) {
591 *p = '=';
592 env = rc_strlist_add (env, line);
593 } else {
594 int len = strlen (line) + strlen (e) + 2;
595 char *new = rc_xmalloc (sizeof (char *) * len);
596 snprintf (new, len, "%s=%s", line, e);
597 env = rc_strlist_add (env, new);
598 free (new);
599 }
600 }
601 rc_strlist_free (config);
602
603 /* One char less to drop the trailing / */
604 i = strlen ("RC_LIBDIR=") + strlen (RC_LIBDIR);
605 line = rc_xmalloc (sizeof (char *) * i);
606 snprintf (line, i, "RC_LIBDIR=" RC_LIBDIR);
607 env = rc_strlist_add (env, line);
608 free (line);
609
610 /* One char less to drop the trailing / */
611 i = strlen ("RC_SVCDIR=") + strlen (RC_SVCDIR);
612 line = rc_xmalloc (sizeof (char *) * i);
613 snprintf (line, i, "RC_SVCDIR=" RC_SVCDIR);
614 env = rc_strlist_add (env, line);
615 free (line);
616
617 env = rc_strlist_add (env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT);
618
619 p = rc_get_runlevel ();
620 i = strlen ("RC_SOFTLEVEL=") + strlen (p) + 1;
621 line = rc_xmalloc (sizeof (char *) * i);
622 snprintf (line, i, "RC_SOFTLEVEL=%s", p);
623 env = rc_strlist_add (env, line);
624 free (line);
625
626 if (rc_exists (RC_SVCDIR "ksoftlevel")) {
627 if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r")))
628 eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel",
629 strerror (errno));
630 else {
631 memset (buffer, 0, sizeof (buffer));
632 if (fgets (buffer, sizeof (buffer), fp)) {
633 i = strlen (buffer) - 1;
634 if (buffer[i] == '\n')
635 buffer[i] = 0;
636 i += strlen ("RC_DEFAULTLEVEL=") + 2;
637 line = rc_xmalloc (sizeof (char *) * i);
638 snprintf (line, i, "RC_DEFAULTLEVEL=%s", buffer);
639 env = rc_strlist_add (env, line);
640 free (line);
641 }
642 fclose (fp);
643 }
644 } else
645 env = rc_strlist_add (env, "RC_DEFAULTLEVEL=" RC_LEVEL_DEFAULT);
646
647 /* Store the name of the tty that stdout is connected to
648 * We do this so our init scripts can call eflush without any knowledge
649 * of our fd's */
650 if (isatty (fileno (stdout))) {
651 if ((p = rc_xstrdup (ttyname (fileno (stdout))))) {
652 i = strlen ("RC_TTY=") + strlen (p) + 1;
653 line = rc_xmalloc (sizeof (char *) * i);
654 snprintf (line, i, "RC_TTY=%s", p);
655 env = rc_strlist_add (env, line);
656 free (p);
657 free (line);
658 }
659 }
660
661 memset (sys, 0, sizeof (sys));
662
663 /* Linux can run some funky stuff like Xen, VServer, UML, etc
664 We store this special system in RC_SYS so our scripts run fast */
665 #ifdef __linux__
666 if (rc_is_dir ("/proc/xen")) {
667 fp = fopen ("/proc/xen/capabilities", "r");
668 if (fp) {
669 fclose (fp);
670 if (file_regex ("/proc/xen/capabilities", "control_d"))
671 snprintf (sys, sizeof (sys), "XENU");
672 }
673 if (! sys)
674 snprintf (sys, sizeof (sys), "XEN0");
675 } else if (file_regex ("/proc/cpuinfo", "UML"))
676 snprintf (sys, sizeof (sys), "UML");
677 else if (file_regex ("/proc/self/status",
678 "(s_context|VxID|envID):[[:space:]]*[1-9]"))
679 snprintf (sys, sizeof (sys), "VPS");
680 #endif
681
682 /* Only add a NET_FS list if not defined */
683 STRLIST_FOREACH (env, line, i)
684 if (strncmp (line, "RC_NET_FS_LIST=", strlen ("RC_NET_FS_LIST=")) == 0) {
685 has_net_fs_list = true;
686 break;
687 }
688
689 if (! has_net_fs_list) {
690 i = strlen ("RC_NET_FS_LIST=") + strlen (RC_NET_FS_LIST_DEFAULT) + 1;
691 line = rc_xmalloc (sizeof (char *) * i);
692 snprintf (line, i, "RC_NET_FS_LIST=%s", RC_NET_FS_LIST_DEFAULT);
693 env = rc_strlist_add (env, line);
694 free (line);
695 }
696
697 if (sys[0]) {
698 i = strlen ("RC_SYS=") + strlen (sys) + 2;
699 line = rc_xmalloc (sizeof (char *) * i);
700 snprintf (line, i, "RC_SYS=%s", sys);
701 env = rc_strlist_add (env, line);
702 free (line);
703 }
704
705 /* Some scripts may need to take a different code path if Linux/FreeBSD, etc
706 To save on calling uname, we store it in an environment variable */
707 if (uname (&uts) == 0) {
708 i = strlen ("RC_UNAME=") + strlen (uts.sysname) + 2;
709 line = rc_xmalloc (sizeof (char *) * i);
710 snprintf (line, i, "RC_UNAME=%s", uts.sysname);
711 env = rc_strlist_add (env, line);
712 free (line);
713 }
714
715 return (env);
716 }
717 librc_hidden_def(rc_config_env)

  ViewVC Help
Powered by ViewVC 1.1.20