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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2883 - (show annotations) (download) (as text)
Tue Sep 18 12:04:51 2007 UTC (10 years, 5 months ago) by uberlord
File MIME type: text/x-csrc
File size: 22407 byte(s)
    API change! rc_ls_dir, rc_get_config and rc_get_list no longer take
    a starting list as a first argument. Instead, use rc_strlist_join
    to append or prepend the new list to an existing list.
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 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 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 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_get_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_get_depinfo (deptree, service);
393 if ((provides = get_provided (deptree, di, runlevel, options)))
394 {
395 STRLIST_FOREACH (provides, lp, k)
396 {
397 di = rc_get_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 && (dt = rc_get_deptype (depinfo, "iprovide")))
418 {
419 STRLIST_FOREACH (dt->services, service, i)
420 {
421 if ((di = rc_get_depinfo (deptree, service)))
422 if ((provides = get_provided (deptree, di, runlevel, options)))
423 {
424 STRLIST_FOREACH (provides, lp, j)
425 if (strcmp (lp, depinfo->service) == 0)
426 {
427 visit_service (deptree, types, sorted, visited, di,
428 runlevel, options | RC_DEP_TRACE);
429 break;
430 }
431 rc_strlist_free (provides);
432 }
433 }
434 }
435
436 /* We've visited everything we need, so add ourselves unless we
437 are also the service calling us or we are provided by something */
438 svcname = getenv("SVCNAME");
439 if (! svcname || strcmp (svcname, depinfo->service) != 0)
440 if (! rc_get_deptype (depinfo, "providedby"))
441 rc_strlist_add (&sorted->list, depinfo->service);
442 }
443
444 char **rc_get_depends (rc_depinfo_t *deptree,
445 char **types, char **services,
446 const char *runlevel, int options)
447 {
448 struct lhead sorted;
449 struct lhead visited;
450 rc_depinfo_t *di;
451 char *service;
452 int i;
453
454 if (! deptree || ! types || ! services)
455 return (NULL);
456
457 memset (&sorted, 0, sizeof (struct lhead));
458 memset (&visited, 0, sizeof (struct lhead));
459
460 bootlevel = getenv ("RC_BOOTLEVEL");
461 if (! bootlevel)
462 bootlevel = RC_LEVEL_BOOT;
463
464 STRLIST_FOREACH (services, service, i)
465 {
466 di = rc_get_depinfo (deptree, service);
467 visit_service (deptree, types, &sorted, &visited, di, runlevel, options);
468 }
469
470 rc_strlist_free (visited.list);
471 return (sorted.list);
472 }
473 librc_hidden_def(rc_get_depends)
474
475 char **rc_order_services (rc_depinfo_t *deptree, const char *runlevel,
476 int options)
477 {
478 char **list = NULL;
479 char **types = NULL;
480 char **services = NULL;
481 bool reverse = false;
482
483 if (! runlevel)
484 return (NULL);
485
486 bootlevel = getenv ("RC_BOOTLEVEL");
487 if (! bootlevel)
488 bootlevel = RC_LEVEL_BOOT;
489
490 /* When shutting down, list all running services */
491 if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
492 strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
493 strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
494 {
495 list = rc_ls_dir (RC_SVCDIR_STARTING, RC_LS_INITD);
496 list = rc_strlist_join (list,
497 rc_ls_dir (RC_SVCDIR_INACTIVE, RC_LS_INITD));
498 list = rc_strlist_join (list,
499 rc_ls_dir (RC_SVCDIR_STARTED, RC_LS_INITD));
500 reverse = true;
501 } else {
502 list = rc_services_in_runlevel (runlevel);
503
504 /* Add coldplugged services */
505 list = rc_strlist_join (list,
506 rc_ls_dir (RC_SVCDIR_COLDPLUGGED, RC_LS_INITD));
507
508
509 /* If we're not the boot runlevel then add that too */
510 if (strcmp (runlevel, bootlevel) != 0) {
511 char *path = rc_strcatpaths (RC_RUNLEVELDIR, bootlevel,
512 (char *) NULL);
513 list = rc_strlist_join (list,
514 rc_ls_dir (path, RC_LS_INITD));
515 free (path);
516 }
517 }
518
519 /* Now we have our lists, we need to pull in any dependencies
520 and order them */
521 rc_strlist_add (&types, "ineed");
522 rc_strlist_add (&types, "iuse");
523 rc_strlist_add (&types, "iafter");
524 services = rc_get_depends (deptree, types, list, runlevel,
525 RC_DEP_STRICT | RC_DEP_TRACE | options);
526 rc_strlist_free (list);
527 rc_strlist_free (types);
528
529 if (reverse)
530 rc_strlist_reverse (services);
531
532 return (services);
533 }
534 librc_hidden_def(rc_order_services)
535
536 static bool is_newer_than (const char *file, const char *target)
537 {
538 struct stat buf;
539 time_t mtime;
540
541 if (stat (file, &buf) != 0 || buf.st_size == 0)
542 return (false);
543 mtime = buf.st_mtime;
544
545 /* Of course we are newever than targets that don't exist
546 Such as broken symlinks */
547 if (stat (target, &buf) != 0)
548 return (true);
549
550 if (mtime < buf.st_mtime)
551 return (false);
552
553 if (rc_is_dir (target))
554 {
555 char **targets = rc_ls_dir (target, 0);
556 char *t;
557 int i;
558 bool newer = true;
559 STRLIST_FOREACH (targets, t, i)
560 {
561 char *path = rc_strcatpaths (target, t, (char *) NULL);
562 newer = is_newer_than (file, path);
563 free (path);
564 if (! newer)
565 break;
566 }
567 rc_strlist_free (targets);
568 return (newer);
569 }
570
571 return (true);
572 }
573
574 typedef struct deppair
575 {
576 const char *depend;
577 const char *addto;
578 } deppair_t;
579
580 static const deppair_t deppairs[] = {
581 { "ineed", "needsme" },
582 { "iuse", "usesme" },
583 { "iafter", "ibefore" },
584 { "ibefore", "iafter" },
585 { "iprovide", "providedby" },
586 { NULL, NULL }
587 };
588
589 static const char *depdirs[] =
590 {
591 RC_SVCDIR "/starting",
592 RC_SVCDIR "/started",
593 RC_SVCDIR "/stopping",
594 RC_SVCDIR "/inactive",
595 RC_SVCDIR "/wasinactive",
596 RC_SVCDIR "/failed",
597 RC_SVCDIR "/coldplugged",
598 RC_SVCDIR "/daemons",
599 RC_SVCDIR "/options",
600 RC_SVCDIR "/exclusive",
601 RC_SVCDIR "/scheduled",
602 NULL
603 };
604
605 /* This is a 5 phase operation
606 Phase 1 is a shell script which loads each init script and config in turn
607 and echos their dependency info to stdout
608 Phase 2 takes that and populates a depinfo object with that data
609 Phase 3 adds any provided services to the depinfo object
610 Phase 4 scans that depinfo object and puts in backlinks
611 Phase 5 saves the depinfo object to disk
612 */
613 int rc_update_deptree (bool force)
614 {
615 char *depends;
616 char *service;
617 char *type;
618 char *depend;
619 char **config = NULL;
620 int retval = 0;
621 FILE *fp;
622 rc_depinfo_t *deptree;
623 rc_depinfo_t *depinfo;
624 rc_depinfo_t *di;
625 rc_depinfo_t *last_depinfo = NULL;
626 rc_deptype_t *deptype = NULL;
627 rc_deptype_t *dt;
628 rc_deptype_t *last_deptype = NULL;
629 char buffer[RC_LINEBUFFER];
630 int len;
631 int i;
632 int j;
633 int k;
634 bool already_added;
635
636 /* Create base directories if needed */
637 for (i = 0; depdirs[i]; i++)
638 if (! rc_is_dir (depdirs[i]))
639 if (mkdir (depdirs[i], 0755) != 0)
640 eerrorx ("mkdir `%s': %s", depdirs[i], strerror (errno));
641
642 /* Quick test to see if anything we use has changed */
643 if (! force &&
644 is_newer_than (RC_DEPTREE, RC_INITDIR) &&
645 is_newer_than (RC_DEPTREE, RC_CONFDIR) &&
646 is_newer_than (RC_DEPTREE, "/etc/rc.conf"))
647 {
648 bool newer = false;
649
650 /* Some init scripts dependencies change depending on config files
651 * outside of baselayout, like syslog-ng, so we check those too. */
652 if (! rc_exists (RC_DEPCONFIG))
653 return 0;
654
655 config = rc_get_list (RC_DEPCONFIG);
656 STRLIST_FOREACH (config, service, i) {
657 if (! is_newer_than (RC_DEPTREE, service)) {
658 newer = true;
659 break;
660 }
661 }
662 rc_strlist_free (config);
663 config = NULL;
664
665 if (! newer)
666 return (0);
667 }
668
669 ebegin ("Caching service dependencies");
670
671 /* Some init scripts need RC_LIBDIR to source stuff
672 Ideally we should be setting our full env instead */
673 if (! getenv ("RC_LIBDIR"))
674 setenv ("RC_LIBDIR", RC_LIBDIR, 0);
675
676 /* Phase 1 */
677 if (! (fp = popen (GENDEP, "r")))
678 eerrorx ("popen: %s", strerror (errno));
679
680 deptree = rc_xmalloc (sizeof (rc_depinfo_t));
681 memset (deptree, 0, sizeof (rc_depinfo_t));
682 memset (buffer, 0, RC_LINEBUFFER);
683
684 /* Phase 2 */
685 while (fgets (buffer, RC_LINEBUFFER, fp))
686 {
687 /* Trim the newline */
688 if (buffer[strlen (buffer) - 1] == '\n')
689 buffer[strlen(buffer) -1] = 0;
690
691 depends = buffer;
692 service = strsep (&depends, " ");
693 if (! service)
694 continue;
695 type = strsep (&depends, " ");
696
697 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
698 {
699 last_depinfo = depinfo;
700 if (depinfo->service && strcmp (depinfo->service, service) == 0)
701 break;
702 }
703
704 if (! depinfo)
705 {
706 if (! last_depinfo->service)
707 depinfo = last_depinfo;
708 else
709 {
710 last_depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
711 depinfo = last_depinfo->next;
712 }
713 memset (depinfo, 0, sizeof (rc_depinfo_t));
714 depinfo->service = rc_xstrdup (service);
715 }
716
717 /* We may not have any depends */
718 if (! type || ! depends)
719 continue;
720
721 /* Get the type */
722 if (strcmp (type, "config") != 0) {
723 last_deptype = NULL;
724 for (deptype = depinfo->depends; deptype; deptype = deptype->next)
725 {
726 last_deptype = deptype;
727 if (strcmp (deptype->type, type) == 0)
728 break;
729 }
730
731 if (! deptype)
732 {
733 if (! last_deptype)
734 {
735 depinfo->depends = rc_xmalloc (sizeof (rc_deptype_t));
736 deptype = depinfo->depends;
737 }
738 else
739 {
740 last_deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
741 deptype = last_deptype->next;
742 }
743 memset (deptype, 0, sizeof (rc_deptype_t));
744 deptype->type = rc_xstrdup (type);
745 }
746 }
747
748 /* Now add each depend to our type.
749 We do this individually so we handle multiple spaces gracefully */
750 while ((depend = strsep (&depends, " ")))
751 {
752 if (depend[0] == 0)
753 continue;
754
755 if (strcmp (type, "config") == 0) {
756 rc_strlist_addsort (&config, depend);
757 continue;
758 }
759
760 /* .sh files are not init scripts */
761 len = strlen (depend);
762 if (len > 2 &&
763 depend[len - 3] == '.' &&
764 depend[len - 2] == 's' &&
765 depend[len - 1] == 'h')
766 continue;
767
768 rc_strlist_addsort (&deptype->services, depend);
769 }
770
771 }
772 pclose (fp);
773
774 /* Phase 3 - add our providors to the tree */
775 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
776 {
777 if ((deptype = rc_get_deptype (depinfo, "iprovide")))
778 STRLIST_FOREACH (deptype->services, service, i)
779 {
780 for (di = deptree; di; di = di->next)
781 {
782 last_depinfo = di;
783 if (strcmp (di->service, service) == 0)
784 break;
785 }
786 if (! di)
787 {
788 last_depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
789 di = last_depinfo->next;
790 memset (di, 0, sizeof (rc_depinfo_t));
791 di->service = rc_xstrdup (service);
792 }
793 }
794 }
795
796 /* Phase 4 - backreference our depends */
797 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
798 {
799 for (i = 0; deppairs[i].depend; i++)
800 {
801 deptype = rc_get_deptype (depinfo, deppairs[i].depend);
802 if (! deptype)
803 continue;
804
805 STRLIST_FOREACH (deptype->services, service, j)
806 {
807 di = rc_get_depinfo (deptree, service);
808 if (! di)
809 {
810 if (strcmp (deptype->type, "ineed") == 0)
811 {
812 eerror ("Service `%s' needs non existant service `%s'",
813 depinfo->service, service);
814 retval = -1;
815 }
816 continue;
817 }
818
819 /* Add our deptype now */
820 last_deptype = NULL;
821 for (dt = di->depends; dt; dt = dt->next)
822 {
823 last_deptype = dt;
824 if (strcmp (dt->type, deppairs[i].addto) == 0)
825 break;
826 }
827 if (! dt)
828 {
829 if (! last_deptype)
830 {
831 di->depends = rc_xmalloc (sizeof (rc_deptype_t));
832 dt = di->depends;
833 }
834 else
835 {
836 last_deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
837 dt = last_deptype->next;
838 }
839 memset (dt, 0, sizeof (rc_deptype_t));
840 dt->type = rc_xstrdup (deppairs[i].addto);
841 }
842
843 already_added = false;
844 STRLIST_FOREACH (dt->services, service, k)
845 if (strcmp (service, depinfo->service) == 0)
846 {
847 already_added = true;
848 break;
849 }
850
851 if (! already_added)
852 rc_strlist_addsort (&dt->services, depinfo->service);
853 }
854 }
855 }
856
857 /* Phase 5 - save to disk
858 Now that we're purely in C, do we need to keep a shell parseable file?
859 I think yes as then it stays human readable
860 This works and should be entirely shell parseable provided that depend
861 names don't have any non shell variable characters in
862 */
863 if (! (fp = fopen (RC_DEPTREE, "w")))
864 eerror ("fopen `%s': %s", RC_DEPTREE, strerror (errno));
865 else
866 {
867 i = 0;
868 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
869 {
870 fprintf (fp, "depinfo_%d_service='%s'\n", i, depinfo->service);
871 for (deptype = depinfo->depends; deptype; deptype = deptype->next)
872 {
873 k = 0;
874 STRLIST_FOREACH (deptype->services, service, j)
875 {
876 fprintf (fp, "depinfo_%d_%s_%d='%s'\n", i, deptype->type,
877 k, service);
878 k++;
879 }
880 }
881 i++;
882 }
883 fclose (fp);
884 }
885
886 /* Save our external config files to disk */
887 if (config) {
888 if (! (fp = fopen (RC_DEPCONFIG, "w")))
889 eerror ("fopen `%s': %s", RC_DEPCONFIG, strerror (errno));
890 else
891 {
892 STRLIST_FOREACH (config, service, i)
893 fprintf (fp, "%s\n", service);
894 fclose (fp);
895 }
896 rc_strlist_free (config);
897 }
898
899 rc_free_deptree (deptree);
900
901 eend (retval, "Failed to update the service dependency tree");
902 return (retval);
903 }
904 librc_hidden_def(rc_update_deptree)

  ViewVC Help
Powered by ViewVC 1.1.20