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

Contents of /trunk/src/librc-depend.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: 22428 byte(s)
Rename config funcs
1 /*
2 librc-depend
3 rc service dependency and ordering
4 Copyright 2006-2007 Gentoo Foundation
5 */
6
7 #include "librc.h"
8
9 #define GENDEP RC_LIBDIR "/sh/gendepends.sh"
10
11 #define RC_DEPCONFIG RC_SVCDIR "/depconfig"
12
13 static const char *bootlevel = NULL;
14
15 /* We use this so we can pass our char array through many functions */
16 struct lhead
17 {
18 char **list;
19 };
20
21 static char *get_shell_value (char *string)
22 {
23 char *p = string;
24 char *e;
25
26 if (! string)
27 return (NULL);
28
29 if (*p == '\'')
30 p++;
31
32 e = p + strlen (p) - 1;
33 if (*e == '\n')
34 *e-- = 0;
35 if (*e == '\'')
36 *e-- = 0;
37
38 if (*p != 0)
39 return p;
40
41 return (NULL);
42 }
43
44 void rc_deptree_free (rc_depinfo_t *deptree)
45 {
46 rc_depinfo_t *di = deptree;
47 while (di)
48 {
49 rc_depinfo_t *dip = di->next;
50 rc_deptype_t *dt = di->depends;
51 free (di->service);
52 while (dt)
53 {
54 rc_deptype_t *dtp = dt->next;
55 free (dt->type);
56 rc_strlist_free (dt->services);
57 free (dt);
58 dt = dtp;
59 }
60 free (di);
61 di = dip;
62 }
63 }
64 librc_hidden_def(rc_deptree_free)
65
66 rc_depinfo_t *rc_deptree_load (void)
67 {
68 FILE *fp;
69 rc_depinfo_t *deptree = NULL;
70 rc_depinfo_t *depinfo = NULL;
71 rc_deptype_t *deptype = NULL;
72 char buffer [RC_LINEBUFFER];
73 char *type;
74 char *p;
75 char *e;
76 int i;
77
78 if (! (fp = fopen (RC_DEPTREE, "r")))
79 return (NULL);
80
81 while (fgets (buffer, RC_LINEBUFFER, fp))
82 {
83 p = buffer;
84 e = strsep (&p, "_");
85 if (! e || strcmp (e, "depinfo") != 0)
86 continue;
87
88 e = strsep (&p, "_");
89 if (! e || sscanf (e, "%d", &i) != 1)
90 continue;
91
92 if (! (type = strsep (&p, "_=")))
93 continue;
94
95 if (strcmp (type, "service") == 0)
96 {
97 /* Sanity */
98 e = get_shell_value (p);
99 if (! e || strlen (e) == 0)
100 continue;
101
102 if (! deptree)
103 {
104 deptree = rc_xmalloc (sizeof (rc_depinfo_t));
105 depinfo = deptree;
106 }
107 else
108 {
109 depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
110 depinfo = depinfo->next;
111 }
112 memset (depinfo, 0, sizeof (rc_depinfo_t));
113 depinfo->service = rc_xstrdup (e);
114 deptype = NULL;
115 continue;
116 }
117
118 e = strsep (&p, "=");
119 if (! e || sscanf (e, "%d", &i) != 1)
120 continue;
121
122 /* Sanity */
123 e = get_shell_value (p);
124 if (! e || strlen (e) == 0)
125 continue;
126
127 if (! deptype)
128 {
129 depinfo->depends = rc_xmalloc (sizeof (rc_deptype_t));
130 deptype = depinfo->depends;
131 memset (deptype, 0, sizeof (rc_deptype_t));
132 }
133 else
134 if (strcmp (deptype->type, type) != 0)
135 {
136 deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
137 deptype = deptype->next;
138 memset (deptype, 0, sizeof (rc_deptype_t));
139 }
140
141 if (! deptype->type)
142 deptype->type = rc_xstrdup (type);
143
144 rc_strlist_addsort (&deptype->services, e);
145 }
146 fclose (fp);
147
148 return (deptree);
149 }
150 librc_hidden_def(rc_deptree_load)
151
152 rc_depinfo_t *rc_deptree_depinfo (rc_depinfo_t *deptree, const char *service)
153 {
154 rc_depinfo_t *di;
155
156 if (! deptree || ! service)
157 return (NULL);
158
159 for (di = deptree; di; di = di->next)
160 if (strcmp (di->service, service) == 0)
161 return (di);
162
163 return (NULL);
164 }
165 librc_hidden_def(rc_deptree_depinfo)
166
167 rc_deptype_t *rc_deptree_deptype (rc_depinfo_t *depinfo, const char *type)
168 {
169 rc_deptype_t *dt;
170
171 if (! depinfo || !type)
172 return (NULL);
173
174 for (dt = depinfo->depends; dt; dt = dt->next)
175 if (strcmp (dt->type, type) == 0)
176 return (dt);
177
178 return (NULL);
179 }
180 librc_hidden_def(rc_deptree_deptype)
181
182 static bool valid_service (const char *runlevel, const char *service)
183 {
184 rc_service_state_t state = rc_service_state (service);
185
186 return ((strcmp (runlevel, bootlevel) != 0 &&
187 rc_service_in_runlevel (service, bootlevel)) ||
188 rc_service_in_runlevel (service, runlevel) ||
189 state & RC_SERVICE_COLDPLUGGED ||
190 state & RC_SERVICE_STARTED);
191 }
192
193 static bool get_provided1 (const char *runlevel, struct lhead *providers,
194 rc_deptype_t *deptype,
195 const char *level, bool coldplugged,
196 rc_service_state_t state)
197 {
198 char *service;
199 int i;
200 bool retval = false;
201
202 STRLIST_FOREACH (deptype->services, service, i)
203 {
204 bool ok = true;
205 rc_service_state_t s = rc_service_state (service);
206 if (level)
207 ok = rc_service_in_runlevel (service, level);
208 else if (coldplugged)
209 ok = (s & RC_SERVICE_COLDPLUGGED &&
210 ! rc_service_in_runlevel (service, runlevel) &&
211 ! rc_service_in_runlevel (service, bootlevel));
212
213 if (! ok)
214 continue;
215
216 switch (state) {
217 case RC_SERVICE_STARTED:
218 ok = (s & RC_SERVICE_STARTED);
219 break;
220 case RC_SERVICE_INACTIVE:
221 case RC_SERVICE_STARTING:
222 case RC_SERVICE_STOPPING:
223 ok = (s & RC_SERVICE_STARTING ||
224 s & RC_SERVICE_STOPPING ||
225 s & RC_SERVICE_INACTIVE);
226 break;
227 default:
228 break;
229 }
230
231 if (! ok)
232 continue;
233
234 retval = true;
235 rc_strlist_add (&providers->list, service);
236 }
237
238 return (retval);
239 }
240
241 /* Work out if a service is provided by another service.
242 For example metalog provides logger.
243 We need to be able to handle syslogd providing logger too.
244 We do this by checking whats running, then what's starting/stopping,
245 then what's run in the runlevels and finally alphabetical order.
246
247 If there are any bugs in rc-depend, they will probably be here as
248 provided dependancy can change depending on runlevel state.
249 */
250 static char **get_provided (rc_depinfo_t *deptree, rc_depinfo_t *depinfo,
251 const char *runlevel, int options)
252 {
253 rc_deptype_t *dt;
254 struct lhead providers;
255 char *service;
256 int i;
257
258 if (! deptree || ! depinfo)
259 return (NULL);
260 if (rc_service_exists (depinfo->service))
261 return (NULL);
262
263 dt = rc_deptree_deptype (depinfo, "providedby");
264 if (! dt)
265 return (NULL);
266
267 memset (&providers, 0, sizeof (struct lhead));
268 /* If we are stopping then all depends are true, regardless of state.
269 This is especially true for net services as they could force a restart
270 of the local dns resolver which may depend on net. */
271 if (options & RC_DEP_STOP)
272 {
273 STRLIST_FOREACH (dt->services, service, i)
274 rc_strlist_add (&providers.list, service);
275
276 return (providers.list);
277 }
278
279 /* If we're strict, then only use what we have in our runlevel
280 * and bootlevel */
281 if (options & RC_DEP_STRICT)
282 {
283 STRLIST_FOREACH (dt->services, service, i)
284 if (rc_service_in_runlevel (service, runlevel) ||
285 rc_service_in_runlevel (service, bootlevel))
286 rc_strlist_add (&providers.list, service);
287
288 if (providers.list)
289 return (providers.list);
290 }
291
292 /* OK, we're not strict or there were no services in our runlevel.
293 This is now where the logic gets a little fuzzy :)
294 If there is >1 running service then we return NULL.
295 We do this so we don't hang around waiting for inactive services and
296 our need has already been satisfied as it's not strict.
297 We apply this to our runlevel, coldplugged services, then bootlevel
298 and finally any running.*/
299 #define DO \
300 if (providers.list && providers.list[0] && providers.list[1]) \
301 { \
302 rc_strlist_free (providers.list); \
303 return (NULL); \
304 } \
305 else if (providers.list) \
306 return providers.list; \
307
308 /* Anything in the runlevel has to come first */
309 if (get_provided1 (runlevel, &providers, dt, runlevel, false, RC_SERVICE_STARTED))
310 { DO }
311 if (get_provided1 (runlevel, &providers, dt, runlevel, false, RC_SERVICE_STARTING))
312 return (providers.list);
313 if (get_provided1 (runlevel, &providers, dt, runlevel, false, RC_SERVICE_STOPPED))
314 return (providers.list);
315
316 /* Check coldplugged services */
317 if (get_provided1 (runlevel, &providers, dt, NULL, true, RC_SERVICE_STARTED))
318 { DO }
319 if (get_provided1 (runlevel, &providers, dt, NULL, true, RC_SERVICE_STARTING))
320 return (providers.list);
321
322 /* Check bootlevel if we're not in it */
323 if (bootlevel && strcmp (runlevel, bootlevel) != 0)
324 {
325 if (get_provided1 (runlevel, &providers, dt, bootlevel, false, RC_SERVICE_STARTED))
326 { DO }
327 if (get_provided1 (runlevel, &providers, dt, bootlevel, false, RC_SERVICE_STARTING))
328 return (providers.list);
329 }
330
331 /* Check coldplugged services */
332 if (get_provided1 (runlevel, &providers, dt, NULL, true, RC_SERVICE_STOPPED))
333 { DO }
334
335 /* Check manually started */
336 if (get_provided1 (runlevel, &providers, dt, NULL, false, RC_SERVICE_STARTED))
337 { DO }
338 if (get_provided1 (runlevel, &providers, dt, NULL, false, RC_SERVICE_STARTING))
339 return (providers.list);
340
341 /* Nothing started then. OK, lets get the stopped services */
342 if (get_provided1 (runlevel, &providers, dt, runlevel, false, RC_SERVICE_STOPPED))
343 return (providers.list);
344
345 if (bootlevel && (strcmp (runlevel, bootlevel) != 0)
346 && (get_provided1 (runlevel, &providers, dt, bootlevel, false, RC_SERVICE_STOPPED)))
347 return (providers.list);
348
349 /* Still nothing? OK, list all services */
350 STRLIST_FOREACH (dt->services, service, i)
351 rc_strlist_add (&providers.list, service);
352
353 return (providers.list);
354 }
355
356 static void visit_service (rc_depinfo_t *deptree, char **types,
357 struct lhead *sorted, struct lhead *visited,
358 rc_depinfo_t *depinfo,
359 const char *runlevel, int options)
360 {
361 int i, j, k;
362 char *lp, *item;
363 char *service;
364 rc_depinfo_t *di;
365 rc_deptype_t *dt;
366 char **provides;
367 char *svcname;
368
369 if (! deptree || !sorted || !visited || !depinfo)
370 return;
371
372 /* Check if we have already visited this service or not */
373 STRLIST_FOREACH (visited->list, item, i)
374 if (strcmp (item, depinfo->service) == 0)
375 return;
376
377 /* Add ourselves as a visited service */
378 rc_strlist_add (&visited->list, depinfo->service);
379
380 STRLIST_FOREACH (types, item, i)
381 {
382 if ((dt = rc_deptree_deptype (depinfo, item)))
383 {
384 STRLIST_FOREACH (dt->services, service, j)
385 {
386 if (! options & RC_DEP_TRACE || strcmp (item, "iprovide") == 0)
387 {
388 rc_strlist_add (&sorted->list, service);
389 continue;
390 }
391
392 di = rc_deptree_depinfo (deptree, service);
393 if ((provides = get_provided (deptree, di, runlevel, options)))
394 {
395 STRLIST_FOREACH (provides, lp, k)
396 {
397 di = rc_deptree_depinfo (deptree, lp);
398 if (di && (strcmp (item, "ineed") == 0 ||
399 strcmp (item, "needsme") == 0 ||
400 valid_service (runlevel, di->service)))
401 visit_service (deptree, types, sorted, visited, di,
402 runlevel, options | RC_DEP_TRACE);
403 }
404 rc_strlist_free (provides);
405 }
406 else
407 if (di && (strcmp (item, "ineed") == 0 ||
408 strcmp (item, "needsme") == 0 ||
409 valid_service (runlevel, service)))
410 visit_service (deptree, types, sorted, visited, di,
411 runlevel, options | RC_DEP_TRACE);
412 }
413 }
414 }
415
416 /* Now visit the stuff we provide for */
417 if (options & RC_DEP_TRACE &&
418 (dt = rc_deptree_deptype (depinfo, "iprovide")))
419 {
420 STRLIST_FOREACH (dt->services, service, i)
421 {
422 if ((di = rc_deptree_depinfo (deptree, service)))
423 if ((provides = get_provided (deptree, di, runlevel, options)))
424 {
425 STRLIST_FOREACH (provides, lp, j)
426 if (strcmp (lp, depinfo->service) == 0)
427 {
428 visit_service (deptree, types, sorted, visited, di,
429 runlevel, options | RC_DEP_TRACE);
430 break;
431 }
432 rc_strlist_free (provides);
433 }
434 }
435 }
436
437 /* We've visited everything we need, so add ourselves unless we
438 are also the service calling us or we are provided by something */
439 svcname = getenv("SVCNAME");
440 if (! svcname || strcmp (svcname, depinfo->service) != 0)
441 if (! rc_deptree_deptype (depinfo, "providedby"))
442 rc_strlist_add (&sorted->list, depinfo->service);
443 }
444
445 char **rc_deptree_depends (rc_depinfo_t *deptree,
446 char **types, char **services,
447 const char *runlevel, int options)
448 {
449 struct lhead sorted;
450 struct lhead visited;
451 rc_depinfo_t *di;
452 char *service;
453 int i;
454
455 if (! deptree || ! types || ! services)
456 return (NULL);
457
458 memset (&sorted, 0, sizeof (struct lhead));
459 memset (&visited, 0, sizeof (struct lhead));
460
461 bootlevel = getenv ("RC_BOOTLEVEL");
462 if (! bootlevel)
463 bootlevel = RC_LEVEL_BOOT;
464
465 STRLIST_FOREACH (services, service, i)
466 {
467 di = rc_deptree_depinfo (deptree, service);
468 visit_service (deptree, types, &sorted, &visited, di, runlevel, options);
469 }
470
471 rc_strlist_free (visited.list);
472 return (sorted.list);
473 }
474 librc_hidden_def(rc_deptree_depends)
475
476 char **rc_deptree_order_services (rc_depinfo_t *deptree, const char *runlevel,
477 int options)
478 {
479 char **list = NULL;
480 char **types = NULL;
481 char **services = NULL;
482 bool reverse = false;
483 char **tmp = NULL;
484
485 if (! runlevel)
486 return (NULL);
487
488 bootlevel = getenv ("RC_BOOTLEVEL");
489 if (! bootlevel)
490 bootlevel = RC_LEVEL_BOOT;
491
492 /* When shutting down, list all running services */
493 if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
494 strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
495 strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
496 {
497 list = rc_ls_dir (RC_SVCDIR_STARTING, RC_LS_INITD);
498
499 tmp = rc_ls_dir (RC_SVCDIR_INACTIVE, RC_LS_INITD);
500 rc_strlist_join (&list, tmp);
501 rc_strlist_free (tmp);
502
503 tmp = rc_ls_dir (RC_SVCDIR_INACTIVE, RC_LS_INITD);
504 rc_strlist_join (&list, tmp);
505 rc_strlist_free (tmp);
506 reverse = true;
507 } else {
508 list = rc_services_in_runlevel (runlevel);
509
510 /* Add coldplugged services */
511 tmp = rc_ls_dir (RC_SVCDIR_COLDPLUGGED, RC_LS_INITD);
512 rc_strlist_join (&list, tmp);
513 rc_strlist_free (tmp);
514
515 /* If we're not the boot runlevel then add that too */
516 if (strcmp (runlevel, bootlevel) != 0) {
517 char *path = rc_strcatpaths (RC_RUNLEVELDIR, bootlevel,
518 (char *) NULL);
519 tmp = rc_ls_dir (path, RC_LS_INITD);
520 rc_strlist_join (&list, tmp);
521 rc_strlist_free (tmp);
522 free (path);
523 }
524 }
525
526 /* Now we have our lists, we need to pull in any dependencies
527 and order them */
528 rc_strlist_add (&types, "ineed");
529 rc_strlist_add (&types, "iuse");
530 rc_strlist_add (&types, "iafter");
531 services = rc_deptree_depends (deptree, types, list, runlevel,
532 RC_DEP_STRICT | RC_DEP_TRACE | options);
533 rc_strlist_free (list);
534 rc_strlist_free (types);
535
536 if (reverse)
537 rc_strlist_reverse (services);
538
539 return (services);
540 }
541 librc_hidden_def(rc_deptree_order_services)
542
543 static bool is_newer_than (const char *file, const char *target)
544 {
545 struct stat buf;
546 time_t mtime;
547
548 if (stat (file, &buf) != 0 || buf.st_size == 0)
549 return (false);
550 mtime = buf.st_mtime;
551
552 /* Of course we are newever than targets that don't exist
553 Such as broken symlinks */
554 if (stat (target, &buf) != 0)
555 return (true);
556
557 if (mtime < buf.st_mtime)
558 return (false);
559
560 if (rc_is_dir (target))
561 {
562 char **targets = rc_ls_dir (target, 0);
563 char *t;
564 int i;
565 bool newer = true;
566 STRLIST_FOREACH (targets, t, i)
567 {
568 char *path = rc_strcatpaths (target, t, (char *) NULL);
569 newer = is_newer_than (file, path);
570 free (path);
571 if (! newer)
572 break;
573 }
574 rc_strlist_free (targets);
575 return (newer);
576 }
577
578 return (true);
579 }
580
581 typedef struct deppair
582 {
583 const char *depend;
584 const char *addto;
585 } deppair_t;
586
587 static const deppair_t deppairs[] = {
588 { "ineed", "needsme" },
589 { "iuse", "usesme" },
590 { "iafter", "ibefore" },
591 { "ibefore", "iafter" },
592 { "iprovide", "providedby" },
593 { NULL, NULL }
594 };
595
596 static const char *depdirs[] =
597 {
598 RC_SVCDIR "/starting",
599 RC_SVCDIR "/started",
600 RC_SVCDIR "/stopping",
601 RC_SVCDIR "/inactive",
602 RC_SVCDIR "/wasinactive",
603 RC_SVCDIR "/failed",
604 RC_SVCDIR "/coldplugged",
605 RC_SVCDIR "/daemons",
606 RC_SVCDIR "/options",
607 RC_SVCDIR "/exclusive",
608 RC_SVCDIR "/scheduled",
609 NULL
610 };
611
612 bool rc_deptree_update_needed (void)
613 {
614 bool newer = false;
615 char **config;
616 char *service;
617 int i;
618
619 /* Create base directories if needed */
620 for (i = 0; depdirs[i]; i++)
621 if (mkdir (depdirs[i], 0755) != 0 && errno != EEXIST)
622 fprintf (stderr, "mkdir `%s': %s", depdirs[i], strerror (errno));
623
624 /* Quick test to see if anything we use has changed */
625 if (! is_newer_than (RC_DEPTREE, RC_INITDIR) ||
626 ! is_newer_than (RC_DEPTREE, RC_CONFDIR) ||
627 ! is_newer_than (RC_DEPTREE, "/etc/rc.conf"))
628 return (true);
629
630 /* Some init scripts dependencies change depending on config files
631 * outside of baselayout, like syslog-ng, so we check those too. */
632 config = rc_config_list (RC_DEPCONFIG);
633 STRLIST_FOREACH (config, service, i) {
634 if (! is_newer_than (RC_DEPTREE, service)) {
635 newer = true;
636 break;
637 }
638 }
639 rc_strlist_free (config);
640
641 return (newer);
642 }
643 librc_hidden_def(rc_deptree_update_needed)
644
645 /* This is a 5 phase operation
646 Phase 1 is a shell script which loads each init script and config in turn
647 and echos their dependency info to stdout
648 Phase 2 takes that and populates a depinfo object with that data
649 Phase 3 adds any provided services to the depinfo object
650 Phase 4 scans that depinfo object and puts in backlinks
651 Phase 5 saves the depinfo object to disk
652 */
653 int rc_deptree_update (void)
654 {
655 char *depends;
656 char *service;
657 char *type;
658 char *depend;
659 char **config = NULL;
660 int retval = 0;
661 FILE *fp;
662 rc_depinfo_t *deptree;
663 rc_depinfo_t *depinfo;
664 rc_depinfo_t *di;
665 rc_depinfo_t *last_depinfo = NULL;
666 rc_deptype_t *deptype = NULL;
667 rc_deptype_t *dt;
668 rc_deptype_t *last_deptype = NULL;
669 char buffer[RC_LINEBUFFER];
670 int len;
671 int i;
672 int j;
673 int k;
674 bool already_added;
675
676 /* Some init scripts need RC_LIBDIR to source stuff
677 Ideally we should be setting our full env instead */
678 if (! getenv ("RC_LIBDIR"))
679 setenv ("RC_LIBDIR", RC_LIBDIR, 0);
680
681 /* Phase 1 */
682 if (! (fp = popen (GENDEP, "r")))
683 return (-1);
684
685 deptree = rc_xmalloc (sizeof (rc_depinfo_t));
686 memset (deptree, 0, sizeof (rc_depinfo_t));
687 memset (buffer, 0, RC_LINEBUFFER);
688
689 /* Phase 2 */
690 while (fgets (buffer, RC_LINEBUFFER, fp))
691 {
692 /* Trim the newline */
693 if (buffer[strlen (buffer) - 1] == '\n')
694 buffer[strlen(buffer) -1] = 0;
695
696 depends = buffer;
697 service = strsep (&depends, " ");
698 if (! service)
699 continue;
700 type = strsep (&depends, " ");
701
702 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
703 {
704 last_depinfo = depinfo;
705 if (depinfo->service && strcmp (depinfo->service, service) == 0)
706 break;
707 }
708
709 if (! depinfo)
710 {
711 if (! last_depinfo->service)
712 depinfo = last_depinfo;
713 else
714 {
715 last_depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
716 depinfo = last_depinfo->next;
717 }
718 memset (depinfo, 0, sizeof (rc_depinfo_t));
719 depinfo->service = rc_xstrdup (service);
720 }
721
722 /* We may not have any depends */
723 if (! type || ! depends)
724 continue;
725
726 /* Get the type */
727 if (strcmp (type, "config") != 0) {
728 last_deptype = NULL;
729 for (deptype = depinfo->depends; deptype; deptype = deptype->next)
730 {
731 last_deptype = deptype;
732 if (strcmp (deptype->type, type) == 0)
733 break;
734 }
735
736 if (! deptype)
737 {
738 if (! last_deptype)
739 {
740 depinfo->depends = rc_xmalloc (sizeof (rc_deptype_t));
741 deptype = depinfo->depends;
742 }
743 else
744 {
745 last_deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
746 deptype = last_deptype->next;
747 }
748 memset (deptype, 0, sizeof (rc_deptype_t));
749 deptype->type = rc_xstrdup (type);
750 }
751 }
752
753 /* Now add each depend to our type.
754 We do this individually so we handle multiple spaces gracefully */
755 while ((depend = strsep (&depends, " ")))
756 {
757 if (depend[0] == 0)
758 continue;
759
760 if (strcmp (type, "config") == 0) {
761 rc_strlist_addsort (&config, depend);
762 continue;
763 }
764
765 /* .sh files are not init scripts */
766 len = strlen (depend);
767 if (len > 2 &&
768 depend[len - 3] == '.' &&
769 depend[len - 2] == 's' &&
770 depend[len - 1] == 'h')
771 continue;
772
773 rc_strlist_addsort (&deptype->services, depend);
774 }
775
776 }
777 pclose (fp);
778
779 /* Phase 3 - add our providors to the tree */
780 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
781 {
782 if ((deptype = rc_deptree_deptype (depinfo, "iprovide")))
783 STRLIST_FOREACH (deptype->services, service, i)
784 {
785 for (di = deptree; di; di = di->next)
786 {
787 last_depinfo = di;
788 if (strcmp (di->service, service) == 0)
789 break;
790 }
791 if (! di)
792 {
793 last_depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
794 di = last_depinfo->next;
795 memset (di, 0, sizeof (rc_depinfo_t));
796 di->service = rc_xstrdup (service);
797 }
798 }
799 }
800
801 /* Phase 4 - backreference our depends */
802 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
803 {
804 for (i = 0; deppairs[i].depend; i++)
805 {
806 deptype = rc_deptree_deptype (depinfo, deppairs[i].depend);
807 if (! deptype)
808 continue;
809
810 STRLIST_FOREACH (deptype->services, service, j)
811 {
812 di = rc_deptree_depinfo (deptree, service);
813 if (! di)
814 {
815 if (strcmp (deptype->type, "ineed") == 0)
816 {
817 fprintf (stderr,
818 "Service `%s' needs non existant service `%s'",
819 depinfo->service, service);
820 retval = -1;
821 }
822 continue;
823 }
824
825 /* Add our deptype now */
826 last_deptype = NULL;
827 for (dt = di->depends; dt; dt = dt->next)
828 {
829 last_deptype = dt;
830 if (strcmp (dt->type, deppairs[i].addto) == 0)
831 break;
832 }
833 if (! dt)
834 {
835 if (! last_deptype)
836 {
837 di->depends = rc_xmalloc (sizeof (rc_deptype_t));
838 dt = di->depends;
839 }
840 else
841 {
842 last_deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
843 dt = last_deptype->next;
844 }
845 memset (dt, 0, sizeof (rc_deptype_t));
846 dt->type = rc_xstrdup (deppairs[i].addto);
847 }
848
849 already_added = false;
850 STRLIST_FOREACH (dt->services, service, k)
851 if (strcmp (service, depinfo->service) == 0)
852 {
853 already_added = true;
854 break;
855 }
856
857 if (! already_added)
858 rc_strlist_addsort (&dt->services, depinfo->service);
859 }
860 }
861 }
862
863 /* Phase 5 - save to disk
864 Now that we're purely in C, do we need to keep a shell parseable file?
865 I think yes as then it stays human readable
866 This works and should be entirely shell parseable provided that depend
867 names don't have any non shell variable characters in
868 */
869 if ((fp = fopen (RC_DEPTREE, "w"))) {
870 i = 0;
871 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
872 {
873 fprintf (fp, "depinfo_%d_service='%s'\n", i, depinfo->service);
874 for (deptype = depinfo->depends; deptype; deptype = deptype->next)
875 {
876 k = 0;
877 STRLIST_FOREACH (deptype->services, service, j)
878 {
879 fprintf (fp, "depinfo_%d_%s_%d='%s'\n", i, deptype->type,
880 k, service);
881 k++;
882 }
883 }
884 i++;
885 }
886 fclose (fp);
887 } else
888 fprintf (stderr, "fopen `%s': %s", RC_DEPTREE, strerror (errno));
889
890 /* Save our external config files to disk */
891 if (config) {
892 if ((fp = fopen (RC_DEPCONFIG, "w"))) {
893 STRLIST_FOREACH (config, service, i)
894 fprintf (fp, "%s\n", service);
895 fclose (fp);
896 } else
897 fprintf (stderr, "fopen `%s': %s\n", RC_DEPCONFIG, strerror (errno));
898 rc_strlist_free (config);
899 }
900
901 rc_deptree_free (deptree);
902
903 return (retval);
904 }
905 librc_hidden_def(rc_deptree_update)

  ViewVC Help
Powered by ViewVC 1.1.20