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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2831 - (show annotations) (download) (as text)
Wed Aug 15 14:49:41 2007 UTC (11 years, 3 months ago) by uberlord
File MIME type: text/x-csrc
File size: 22436 byte(s)
    `config /etc/fstab' can now be used in depend() functions to show that
    the deptree should be regenerated if /etc/fstab has changed.
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_free_deptree (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_free_deptree)
65
66 rc_depinfo_t *rc_load_deptree (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 /* Update our deptree, but only if we need too */
79 rc_update_deptree (false);
80
81 if (! (fp = fopen (RC_DEPTREE, "r")))
82 return (NULL);
83
84 while (fgets (buffer, RC_LINEBUFFER, fp))
85 {
86 p = buffer;
87 e = strsep (&p, "_");
88 if (! e || strcmp (e, "depinfo") != 0)
89 continue;
90
91 e = strsep (&p, "_");
92 if (! e || sscanf (e, "%d", &i) != 1)
93 continue;
94
95 if (! (type = strsep (&p, "_=")))
96 continue;
97
98 if (strcmp (type, "service") == 0)
99 {
100 /* Sanity */
101 e = get_shell_value (p);
102 if (! e || strlen (e) == 0)
103 continue;
104
105 if (! deptree)
106 {
107 deptree = rc_xmalloc (sizeof (rc_depinfo_t));
108 depinfo = deptree;
109 }
110 else
111 {
112 depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
113 depinfo = depinfo->next;
114 }
115 memset (depinfo, 0, sizeof (rc_depinfo_t));
116 depinfo->service = rc_xstrdup (e);
117 deptype = NULL;
118 continue;
119 }
120
121 e = strsep (&p, "=");
122 if (! e || sscanf (e, "%d", &i) != 1)
123 continue;
124
125 /* Sanity */
126 e = get_shell_value (p);
127 if (! e || strlen (e) == 0)
128 continue;
129
130 if (! deptype)
131 {
132 depinfo->depends = rc_xmalloc (sizeof (rc_deptype_t));
133 deptype = depinfo->depends;
134 memset (deptype, 0, sizeof (rc_deptype_t));
135 }
136 else
137 if (strcmp (deptype->type, type) != 0)
138 {
139 deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
140 deptype = deptype->next;
141 memset (deptype, 0, sizeof (rc_deptype_t));
142 }
143
144 if (! deptype->type)
145 deptype->type = rc_xstrdup (type);
146
147 deptype->services = rc_strlist_addsort (deptype->services, e);
148 }
149 fclose (fp);
150
151 return (deptree);
152 }
153 librc_hidden_def(rc_load_deptree)
154
155 rc_depinfo_t *rc_get_depinfo (rc_depinfo_t *deptree, const char *service)
156 {
157 rc_depinfo_t *di;
158
159 if (! deptree || ! service)
160 return (NULL);
161
162 for (di = deptree; di; di = di->next)
163 if (strcmp (di->service, service) == 0)
164 return (di);
165
166 return (NULL);
167 }
168 librc_hidden_def(rc_get_depinfo)
169
170 rc_deptype_t *rc_get_deptype (rc_depinfo_t *depinfo, const char *type)
171 {
172 rc_deptype_t *dt;
173
174 if (! depinfo || !type)
175 return (NULL);
176
177 for (dt = depinfo->depends; dt; dt = dt->next)
178 if (strcmp (dt->type, type) == 0)
179 return (dt);
180
181 return (NULL);
182 }
183 librc_hidden_def(rc_get_deptype)
184
185 static bool valid_service (const char *runlevel, const char *service)
186 {
187 return ((strcmp (runlevel, bootlevel) != 0 &&
188 rc_service_in_runlevel (service, bootlevel)) ||
189 rc_service_in_runlevel (service, runlevel) ||
190 rc_service_state (service, rc_service_coldplugged) ||
191 rc_service_state (service, rc_service_started));
192 }
193
194 static bool get_provided1 (const char *runlevel, struct lhead *providers,
195 rc_deptype_t *deptype,
196 const char *level, bool coldplugged,
197 rc_service_state_t state)
198 {
199 char *service;
200 int i;
201 bool retval = false;
202
203 STRLIST_FOREACH (deptype->services, service, i)
204 {
205 bool ok = true;
206 if (level)
207 ok = rc_service_in_runlevel (service, level);
208 else if (coldplugged)
209 ok = (rc_service_state (service, 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 = rc_service_state (service, state);
219 break;
220 case rc_service_inactive:
221 case rc_service_starting:
222 case rc_service_stopping:
223 ok = (rc_service_state (service, rc_service_starting) ||
224 rc_service_state (service, rc_service_stopping) ||
225 rc_service_state (service, rc_service_inactive));
226 break;
227 default:
228 break;
229 }
230
231 if (! ok)
232 continue;
233
234 retval = true;
235 providers->list = 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_get_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 providers.list = 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 providers.list = 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
334 /* Check manually started */
335 if (get_provided1 (runlevel, &providers, dt, NULL, false, rc_service_started))
336 { DO }
337 if (get_provided1 (runlevel, &providers, dt, NULL, false, rc_service_starting))
338 return (providers.list);
339
340 /* Nothing started then. OK, lets get the stopped services */
341 if (get_provided1 (runlevel, &providers, dt, runlevel, false, rc_service_stopped))
342 return (providers.list);
343
344 if (bootlevel && (strcmp (runlevel, bootlevel) != 0)
345 && (get_provided1 (runlevel, &providers, dt, bootlevel, false, rc_service_stopped)))
346 return (providers.list);
347
348 /* Still nothing? OK, list all services */
349 STRLIST_FOREACH (dt->services, service, i)
350 providers.list = rc_strlist_add (providers.list, service);
351
352 return (providers.list);
353 }
354
355 static void visit_service (rc_depinfo_t *deptree, char **types,
356 struct lhead *sorted, struct lhead *visited,
357 rc_depinfo_t *depinfo,
358 const char *runlevel, int options)
359 {
360 int i, j, k;
361 char *lp, *item;
362 char *service;
363 rc_depinfo_t *di;
364 rc_deptype_t *dt;
365 char **provides;
366 char *svcname;
367
368 if (! deptree || !sorted || !visited || !depinfo)
369 return;
370
371 /* Check if we have already visited this service or not */
372 STRLIST_FOREACH (visited->list, item, i)
373 if (strcmp (item, depinfo->service) == 0)
374 return;
375
376 /* Add ourselves as a visited service */
377 visited->list = rc_strlist_add (visited->list, depinfo->service);
378
379 STRLIST_FOREACH (types, item, i)
380 {
381 if ((dt = rc_get_deptype (depinfo, item)))
382 {
383 STRLIST_FOREACH (dt->services, service, j)
384 {
385 if (! options & RC_DEP_TRACE || strcmp (item, "iprovide") == 0)
386 {
387 sorted->list = rc_strlist_add (sorted->list, service);
388 continue;
389 }
390
391 di = rc_get_depinfo (deptree, service);
392 if ((provides = get_provided (deptree, di, runlevel, options)))
393 {
394 STRLIST_FOREACH (provides, lp, k)
395 {
396 di = rc_get_depinfo (deptree, lp);
397 if (di && (strcmp (item, "ineed") == 0 ||
398 valid_service (runlevel, di->service)))
399 visit_service (deptree, types, sorted, visited, di,
400 runlevel, options | RC_DEP_TRACE);
401 }
402 rc_strlist_free (provides);
403 }
404 else
405 if (di && (strcmp (item, "ineed") == 0 ||
406 valid_service (runlevel, service)))
407 visit_service (deptree, types, sorted, visited, di,
408 runlevel, options | RC_DEP_TRACE);
409 }
410 }
411 }
412
413 /* Now visit the stuff we provide for */
414 if (options & RC_DEP_TRACE && (dt = rc_get_deptype (depinfo, "iprovide")))
415 {
416 STRLIST_FOREACH (dt->services, service, i)
417 {
418 if ((di = rc_get_depinfo (deptree, service)))
419 if ((provides = get_provided (deptree, di, runlevel, options)))
420 {
421 STRLIST_FOREACH (provides, lp, j)
422 if (strcmp (lp, depinfo->service) == 0)
423 {
424 visit_service (deptree, types, sorted, visited, di,
425 runlevel, options | RC_DEP_TRACE);
426 break;
427 }
428 rc_strlist_free (provides);
429 }
430 }
431 }
432
433 /* We've visited everything we need, so add ourselves unless we
434 are also the service calling us or we are provided by something */
435 svcname = getenv("SVCNAME");
436 if (! svcname || strcmp (svcname, depinfo->service) != 0)
437 if (! rc_get_deptype (depinfo, "providedby"))
438 sorted->list = rc_strlist_add (sorted->list, depinfo->service);
439 }
440
441 char **rc_get_depends (rc_depinfo_t *deptree,
442 char **types, char **services,
443 const char *runlevel, int options)
444 {
445 struct lhead sorted;
446 struct lhead visited;
447 rc_depinfo_t *di;
448 char *service;
449 int i;
450
451 if (! deptree || ! types || ! services)
452 return (NULL);
453
454 memset (&sorted, 0, sizeof (struct lhead));
455 memset (&visited, 0, sizeof (struct lhead));
456
457 bootlevel = getenv ("RC_BOOTLEVEL");
458 if (! bootlevel)
459 bootlevel = RC_LEVEL_BOOT;
460
461 STRLIST_FOREACH (services, service, i)
462 {
463 di = rc_get_depinfo (deptree, service);
464 visit_service (deptree, types, &sorted, &visited, di, runlevel, options);
465 }
466
467 rc_strlist_free (visited.list);
468 return (sorted.list);
469 }
470 librc_hidden_def(rc_get_depends)
471
472 char **rc_order_services (rc_depinfo_t *deptree, const char *runlevel,
473 int options)
474 {
475 char **list = NULL;
476 char **types = NULL;
477 char **services = NULL;
478 bool reverse = false;
479
480 if (! runlevel)
481 return (NULL);
482
483 bootlevel = getenv ("RC_BOOTLEVEL");
484 if (! bootlevel)
485 bootlevel = RC_LEVEL_BOOT;
486
487 /* When shutting down, list all running services */
488 if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
489 strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
490 strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
491 {
492 list = rc_ls_dir (list, RC_SVCDIR_STARTING, RC_LS_INITD);
493 list = rc_ls_dir (list, RC_SVCDIR_INACTIVE, RC_LS_INITD);
494 list = rc_ls_dir (list, RC_SVCDIR_STARTED, RC_LS_INITD);
495 reverse = true;
496 }
497 else
498 {
499 list = rc_services_in_runlevel (runlevel);
500
501 /* Add coldplugged services */
502 list = rc_ls_dir (list, RC_SVCDIR_COLDPLUGGED, RC_LS_INITD);
503
504
505 /* If we're not the boot runlevel then add that too */
506 if (strcmp (runlevel, bootlevel) != 0)
507 {
508 char *path = rc_strcatpaths (RC_RUNLEVELDIR, bootlevel,
509 (char *) NULL);
510 list = rc_ls_dir (list, path, RC_LS_INITD);
511 free (path);
512 }
513 }
514
515 /* Now we have our lists, we need to pull in any dependencies
516 and order them */
517 types = rc_strlist_add (NULL, "ineed");
518 types = rc_strlist_add (types, "iuse");
519 types = rc_strlist_add (types, "iafter");
520 services = rc_get_depends (deptree, types, list, runlevel,
521 RC_DEP_STRICT | RC_DEP_TRACE | options);
522 rc_strlist_free (list);
523 rc_strlist_free (types);
524
525 if (reverse)
526 rc_strlist_reverse (services);
527
528 return (services);
529 }
530 librc_hidden_def(rc_order_services)
531
532 static bool is_newer_than (const char *file, const char *target)
533 {
534 struct stat buf;
535 time_t mtime;
536
537 if (stat (file, &buf) != 0 || buf.st_size == 0)
538 return (false);
539 mtime = buf.st_mtime;
540
541 /* Of course we are newever than targets that don't exist
542 Such as broken symlinks */
543 if (stat (target, &buf) != 0)
544 return (true);
545
546 if (mtime < buf.st_mtime)
547 return (false);
548
549 if (rc_is_dir (target))
550 {
551 char **targets = rc_ls_dir (NULL, target, 0);
552 char *t;
553 int i;
554 bool newer = true;
555 STRLIST_FOREACH (targets, t, i)
556 {
557 char *path = rc_strcatpaths (target, t, (char *) NULL);
558 newer = is_newer_than (file, path);
559 free (path);
560 if (! newer)
561 break;
562 }
563 rc_strlist_free (targets);
564 return (newer);
565 }
566
567 return (true);
568 }
569
570 typedef struct deppair
571 {
572 const char *depend;
573 const char *addto;
574 } deppair_t;
575
576 static const deppair_t deppairs[] = {
577 { "ineed", "needsme" },
578 { "iuse", "usesme" },
579 { "iafter", "ibefore" },
580 { "ibefore", "iafter" },
581 { "iprovide", "providedby" },
582 { NULL, NULL }
583 };
584
585 static const char *depdirs[] =
586 {
587 RC_SVCDIR "/starting",
588 RC_SVCDIR "/started",
589 RC_SVCDIR "/stopping",
590 RC_SVCDIR "/inactive",
591 RC_SVCDIR "/wasinactive",
592 RC_SVCDIR "/failed",
593 RC_SVCDIR "/coldplugged",
594 RC_SVCDIR "/daemons",
595 RC_SVCDIR "/options",
596 RC_SVCDIR "/exclusive",
597 RC_SVCDIR "/scheduled",
598 NULL
599 };
600
601 /* This is a 5 phase operation
602 Phase 1 is a shell script which loads each init script and config in turn
603 and echos their dependency info to stdout
604 Phase 2 takes that and populates a depinfo object with that data
605 Phase 3 adds any provided services to the depinfo object
606 Phase 4 scans that depinfo object and puts in backlinks
607 Phase 5 saves the depinfo object to disk
608 */
609 int rc_update_deptree (bool force)
610 {
611 char *depends;
612 char *service;
613 char *type;
614 char *depend;
615 char **config = NULL;
616 int retval = 0;
617 FILE *fp;
618 rc_depinfo_t *deptree;
619 rc_depinfo_t *depinfo;
620 rc_depinfo_t *di;
621 rc_depinfo_t *last_depinfo = NULL;
622 rc_deptype_t *deptype = NULL;
623 rc_deptype_t *dt;
624 rc_deptype_t *last_deptype = NULL;
625 char buffer[RC_LINEBUFFER];
626 int len;
627 int i;
628 int j;
629 int k;
630 bool already_added;
631
632 /* Create base directories if needed */
633 for (i = 0; depdirs[i]; i++)
634 if (! rc_is_dir (depdirs[i]))
635 if (mkdir (depdirs[i], 0755) != 0)
636 eerrorx ("mkdir `%s': %s", depdirs[i], strerror (errno));
637
638 /* Quick test to see if anything we use has changed */
639 if (! force &&
640 is_newer_than (RC_DEPTREE, RC_INITDIR) &&
641 is_newer_than (RC_DEPTREE, RC_CONFDIR) &&
642 is_newer_than (RC_DEPTREE, "/etc/rc.conf"))
643 {
644 bool newer = false;
645
646 /* Some init scripts dependencies change depending on config files
647 * outside of baselayout, like syslog-ng, so we check those too. */
648 if (! rc_exists (RC_DEPCONFIG))
649 return 0;
650
651 config = rc_get_list (NULL, RC_DEPCONFIG);
652 STRLIST_FOREACH (config, service, i) {
653 if (! is_newer_than (RC_DEPTREE, service)) {
654 newer = true;
655 break;
656 }
657 }
658 rc_strlist_free (config);
659 config = NULL;
660
661 if (! newer)
662 return (0);
663 }
664
665 ebegin ("Caching service dependencies");
666
667 /* Some init scripts need RC_LIBDIR to source stuff
668 Ideally we should be setting our full env instead */
669 if (! getenv ("RC_LIBDIR"))
670 setenv ("RC_LIBDIR", RC_LIBDIR, 0);
671
672 /* Phase 1 */
673 if (! (fp = popen (GENDEP, "r")))
674 eerrorx ("popen: %s", strerror (errno));
675
676 deptree = rc_xmalloc (sizeof (rc_depinfo_t));
677 memset (deptree, 0, sizeof (rc_depinfo_t));
678 memset (buffer, 0, RC_LINEBUFFER);
679
680 /* Phase 2 */
681 while (fgets (buffer, RC_LINEBUFFER, fp))
682 {
683 /* Trim the newline */
684 if (buffer[strlen (buffer) - 1] == '\n')
685 buffer[strlen(buffer) -1] = 0;
686
687 depends = buffer;
688 service = strsep (&depends, " ");
689 if (! service)
690 continue;
691 type = strsep (&depends, " ");
692
693 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
694 {
695 last_depinfo = depinfo;
696 if (depinfo->service && strcmp (depinfo->service, service) == 0)
697 break;
698 }
699
700 if (! depinfo)
701 {
702 if (! last_depinfo->service)
703 depinfo = last_depinfo;
704 else
705 {
706 last_depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
707 depinfo = last_depinfo->next;
708 }
709 memset (depinfo, 0, sizeof (rc_depinfo_t));
710 depinfo->service = rc_xstrdup (service);
711 }
712
713 /* We may not have any depends */
714 if (! type || ! depends)
715 continue;
716
717 /* Get the type */
718 if (strcmp (type, "config") != 0) {
719 last_deptype = NULL;
720 for (deptype = depinfo->depends; deptype; deptype = deptype->next)
721 {
722 last_deptype = deptype;
723 if (strcmp (deptype->type, type) == 0)
724 break;
725 }
726
727 if (! deptype)
728 {
729 if (! last_deptype)
730 {
731 depinfo->depends = rc_xmalloc (sizeof (rc_deptype_t));
732 deptype = depinfo->depends;
733 }
734 else
735 {
736 last_deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
737 deptype = last_deptype->next;
738 }
739 memset (deptype, 0, sizeof (rc_deptype_t));
740 deptype->type = rc_xstrdup (type);
741 }
742 }
743
744 /* Now add each depend to our type.
745 We do this individually so we handle multiple spaces gracefully */
746 while ((depend = strsep (&depends, " ")))
747 {
748 if (depend[0] == 0)
749 continue;
750
751 if (strcmp (type, "config") == 0) {
752 config = rc_strlist_addsort (config, depend);
753 continue;
754 }
755
756 /* .sh files are not init scripts */
757 len = strlen (depend);
758 if (len > 2 &&
759 depend[len - 3] == '.' &&
760 depend[len - 2] == 's' &&
761 depend[len - 1] == 'h')
762 continue;
763
764 deptype->services = rc_strlist_addsort (deptype->services, depend);
765 }
766
767 }
768 pclose (fp);
769
770 /* Phase 3 - add our providors to the tree */
771 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
772 {
773 if ((deptype = rc_get_deptype (depinfo, "iprovide")))
774 STRLIST_FOREACH (deptype->services, service, i)
775 {
776 for (di = deptree; di; di = di->next)
777 {
778 last_depinfo = di;
779 if (strcmp (di->service, service) == 0)
780 break;
781 }
782 if (! di)
783 {
784 last_depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
785 di = last_depinfo->next;
786 memset (di, 0, sizeof (rc_depinfo_t));
787 di->service = rc_xstrdup (service);
788 }
789 }
790 }
791
792 /* Phase 4 - backreference our depends */
793 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
794 {
795 for (i = 0; deppairs[i].depend; i++)
796 {
797 deptype = rc_get_deptype (depinfo, deppairs[i].depend);
798 if (! deptype)
799 continue;
800
801 STRLIST_FOREACH (deptype->services, service, j)
802 {
803 di = rc_get_depinfo (deptree, service);
804 if (! di)
805 {
806 if (strcmp (deptype->type, "ineed") == 0)
807 {
808 eerror ("Service `%s' needs non existant service `%s'",
809 depinfo->service, service);
810 retval = -1;
811 }
812 continue;
813 }
814
815 /* Add our deptype now */
816 last_deptype = NULL;
817 for (dt = di->depends; dt; dt = dt->next)
818 {
819 last_deptype = dt;
820 if (strcmp (dt->type, deppairs[i].addto) == 0)
821 break;
822 }
823 if (! dt)
824 {
825 if (! last_deptype)
826 {
827 di->depends = rc_xmalloc (sizeof (rc_deptype_t));
828 dt = di->depends;
829 }
830 else
831 {
832 last_deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
833 dt = last_deptype->next;
834 }
835 memset (dt, 0, sizeof (rc_deptype_t));
836 dt->type = rc_xstrdup (deppairs[i].addto);
837 }
838
839 already_added = false;
840 STRLIST_FOREACH (dt->services, service, k)
841 if (strcmp (service, depinfo->service) == 0)
842 {
843 already_added = true;
844 break;
845 }
846
847 if (! already_added)
848 dt->services = rc_strlist_addsort (dt->services,
849 depinfo->service);
850 }
851 }
852 }
853
854 /* Phase 5 - save to disk
855 Now that we're purely in C, do we need to keep a shell parseable file?
856 I think yes as then it stays human readable
857 This works and should be entirely shell parseable provided that depend
858 names don't have any non shell variable characters in
859 */
860 if (! (fp = fopen (RC_DEPTREE, "w")))
861 eerror ("fopen `%s': %s", RC_DEPTREE, strerror (errno));
862 else
863 {
864 i = 0;
865 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
866 {
867 fprintf (fp, "depinfo_%d_service='%s'\n", i, depinfo->service);
868 for (deptype = depinfo->depends; deptype; deptype = deptype->next)
869 {
870 k = 0;
871 STRLIST_FOREACH (deptype->services, service, j)
872 {
873 fprintf (fp, "depinfo_%d_%s_%d='%s'\n", i, deptype->type,
874 k, service);
875 k++;
876 }
877 }
878 i++;
879 }
880 fclose (fp);
881 }
882
883 /* Save our external config files to disk */
884 if (config) {
885 if (! (fp = fopen (RC_DEPCONFIG, "w")))
886 eerror ("fopen `%s': %s", RC_DEPCONFIG, strerror (errno));
887 else
888 {
889 STRLIST_FOREACH (config, service, i)
890 fprintf (fp, "%s\n", service);
891 fclose (fp);
892 }
893 rc_strlist_free (config);
894 }
895
896 rc_free_deptree (deptree);
897
898 eend (retval, "Failed to update the service dependency tree");
899 return (retval);
900 }
901 librc_hidden_def(rc_update_deptree)

  ViewVC Help
Powered by ViewVC 1.1.20