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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20