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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20