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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3040 - (show annotations) (download) (as text)
Mon Oct 15 14:40:53 2007 UTC (6 years, 6 months ago) by uberlord
File MIME type: text/x-csrc
File size: 22294 byte(s)
const correctness
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 = xmalloc (sizeof (rc_depinfo_t));
105 depinfo = deptree;
106 }
107 else
108 {
109 depinfo->next = xmalloc (sizeof (rc_depinfo_t));
110 depinfo = depinfo->next;
111 }
112 memset (depinfo, 0, sizeof (rc_depinfo_t));
113 depinfo->service = 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 = 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 = 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 = 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 static rc_depinfo_t *get_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
166 static rc_deptype_t *get_deptype (rc_depinfo_t *depinfo, const char *type)
167 {
168 rc_deptype_t *dt;
169
170 if (! depinfo || !type)
171 return (NULL);
172
173 for (dt = depinfo->depends; dt; dt = dt->next)
174 if (strcmp (dt->type, type) == 0)
175 return (dt);
176
177 return (NULL);
178 }
179
180 static bool valid_service (const char *runlevel, const char *service)
181 {
182 rc_service_state_t state = rc_service_state (service);
183
184 return ((strcmp (runlevel, bootlevel) != 0 &&
185 rc_service_in_runlevel (service, bootlevel)) ||
186 rc_service_in_runlevel (service, runlevel) ||
187 state & RC_SERVICE_COLDPLUGGED ||
188 state & RC_SERVICE_STARTED);
189 }
190
191 static bool get_provided1 (const char *runlevel, struct lhead *providers,
192 rc_deptype_t *deptype,
193 const char *level, bool coldplugged,
194 rc_service_state_t state)
195 {
196 char *service;
197 int i;
198 bool retval = false;
199
200 STRLIST_FOREACH (deptype->services, service, i)
201 {
202 bool ok = true;
203 rc_service_state_t s = rc_service_state (service);
204 if (level)
205 ok = rc_service_in_runlevel (service, level);
206 else if (coldplugged)
207 ok = (s & 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 = (s & RC_SERVICE_STARTED);
217 break;
218 case RC_SERVICE_INACTIVE:
219 case RC_SERVICE_STARTING:
220 case RC_SERVICE_STOPPING:
221 ok = (s & RC_SERVICE_STARTING ||
222 s & RC_SERVICE_STOPPING ||
223 s & RC_SERVICE_INACTIVE);
224 break;
225 default:
226 break;
227 }
228
229 if (! ok)
230 continue;
231
232 retval = true;
233 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 = 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 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 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 { DO }
332
333 /* Check manually started */
334 if (get_provided1 (runlevel, &providers, dt, NULL, false, RC_SERVICE_STARTED))
335 { DO }
336 if (get_provided1 (runlevel, &providers, dt, NULL, false, RC_SERVICE_STARTING))
337 return (providers.list);
338
339 /* Nothing started then. OK, lets get the stopped services */
340 if (get_provided1 (runlevel, &providers, dt, runlevel, false, RC_SERVICE_STOPPED))
341 return (providers.list);
342
343 if (bootlevel && (strcmp (runlevel, bootlevel) != 0)
344 && (get_provided1 (runlevel, &providers, dt, bootlevel, false, RC_SERVICE_STOPPED)))
345 return (providers.list);
346
347 /* Still nothing? OK, list all services */
348 STRLIST_FOREACH (dt->services, service, i)
349 rc_strlist_add (&providers.list, service);
350
351 return (providers.list);
352 }
353
354 static void visit_service (rc_depinfo_t *deptree, const char * const *types,
355 struct lhead *sorted, struct lhead *visited,
356 rc_depinfo_t *depinfo,
357 const char *runlevel, int options)
358 {
359 int i, j, k;
360 char *lp;
361 const char *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 rc_strlist_add (&visited->list, depinfo->service);
378
379 STRLIST_FOREACH (types, item, i)
380 {
381 if ((dt = 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 rc_strlist_add (&sorted->list, service);
388 continue;
389 }
390
391 di = get_depinfo (deptree, service);
392 if ((provides = get_provided (deptree, di, runlevel, options)))
393 {
394 STRLIST_FOREACH (provides, lp, k)
395 {
396 di = get_depinfo (deptree, lp);
397 if (di && (strcmp (item, "ineed") == 0 ||
398 strcmp (item, "needsme") == 0 ||
399 valid_service (runlevel, di->service)))
400 visit_service (deptree, types, sorted, visited, di,
401 runlevel, options | RC_DEP_TRACE);
402 }
403 rc_strlist_free (provides);
404 }
405 else
406 if (di && (strcmp (item, "ineed") == 0 ||
407 strcmp (item, "needsme") == 0 ||
408 valid_service (runlevel, service)))
409 visit_service (deptree, types, sorted, visited, di,
410 runlevel, options | RC_DEP_TRACE);
411 }
412 }
413 }
414
415 /* Now visit the stuff we provide for */
416 if (options & RC_DEP_TRACE &&
417 (dt = get_deptype (depinfo, "iprovide")))
418 {
419 STRLIST_FOREACH (dt->services, service, i)
420 {
421 if ((di = 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 (! get_deptype (depinfo, "providedby"))
441 rc_strlist_add (&sorted->list, depinfo->service);
442 }
443
444 char **rc_deptree_depends (rc_depinfo_t *deptree,
445 const char * const *types, const char * const *services,
446 const char *runlevel, int options)
447 {
448 struct lhead sorted;
449 struct lhead visited;
450 rc_depinfo_t *di;
451 const char *service;
452 int i;
453
454 if (! deptree || ! 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 if (! (di = get_depinfo (deptree, service))) {
467 errno = ENOENT;
468 continue;
469 }
470 if (types)
471 visit_service (deptree, types, &sorted, &visited,
472 di, runlevel, options);
473 }
474
475 rc_strlist_free (visited.list);
476 return (sorted.list);
477 }
478 librc_hidden_def(rc_deptree_depends)
479
480 static const const char *order_types[] = { "ineed", "iuse", "iafter", NULL };
481 char **rc_deptree_order (rc_depinfo_t *deptree, const char *runlevel,
482 int options)
483 {
484 char **list = NULL;
485 char **services = NULL;
486 bool reverse = false;
487 char **tmp = NULL;
488
489 if (! runlevel)
490 return (NULL);
491
492 bootlevel = getenv ("RC_BOOTLEVEL");
493 if (! bootlevel)
494 bootlevel = RC_LEVEL_BOOT;
495
496 /* When shutting down, list all running services */
497 if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
498 strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
499 strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
500 {
501 list = rc_services_in_state (RC_SERVICE_STARTED);
502
503 tmp = rc_services_in_state (RC_SERVICE_INACTIVE);
504 rc_strlist_join (&list, tmp);
505 rc_strlist_free (tmp);
506
507 tmp = rc_services_in_state (RC_SERVICE_STARTING);
508 rc_strlist_join (&list, tmp);
509 rc_strlist_free (tmp);
510 reverse = true;
511 } else {
512 list = rc_services_in_runlevel (runlevel);
513
514 /* Add coldplugged services */
515 tmp = rc_services_in_state (RC_SERVICE_COLDPLUGGED);
516 rc_strlist_join (&list, tmp);
517 rc_strlist_free (tmp);
518
519 /* If we're not the boot runlevel then add that too */
520 if (strcmp (runlevel, bootlevel) != 0) {
521 tmp = rc_services_in_runlevel (bootlevel);
522 rc_strlist_join (&list, tmp);
523 rc_strlist_free (tmp);
524 }
525 }
526
527 /* Now we have our lists, we need to pull in any dependencies
528 and order them */
529 services = rc_deptree_depends (deptree, order_types, (const char **) list,
530 runlevel,
531 RC_DEP_STRICT | RC_DEP_TRACE | options);
532 rc_strlist_free (list);
533
534 if (reverse)
535 rc_strlist_reverse (services);
536
537 return (services);
538 }
539 librc_hidden_def(rc_deptree_order)
540
541 static bool is_newer_than (const char *file, const char *target)
542 {
543 struct stat buf;
544 time_t mtime;
545 bool newer = true;
546 DIR *dp;
547 struct dirent *d;
548 char *path;
549
550 if (stat (file, &buf) != 0 || buf.st_size == 0)
551 return (false);
552 mtime = buf.st_mtime;
553
554 /* Of course we are newever than targets that don't exist
555 Such as broken symlinks */
556 if (stat (target, &buf) != 0)
557 return (true);
558
559 if (mtime < buf.st_mtime)
560 return (false);
561
562 if (! (dp = opendir (target)))
563 return (true);
564
565 while ((d = readdir (dp))) {
566 if (d->d_name[0] == '.')
567 continue;
568
569 path = rc_strcatpaths (target, d->d_name, (char *) NULL);
570 newer = is_newer_than (file, path);
571 free (path);
572 if (! newer)
573 break;
574 }
575 closedir (dp);
576
577 return (newer);
578 }
579
580 typedef struct deppair
581 {
582 const char *depend;
583 const char *addto;
584 } deppair_t;
585
586 static const deppair_t deppairs[] = {
587 { "ineed", "needsme" },
588 { "iuse", "usesme" },
589 { "iafter", "ibefore" },
590 { "ibefore", "iafter" },
591 { "iprovide", "providedby" },
592 { NULL, NULL }
593 };
594
595 static const char *depdirs[] =
596 {
597 RC_SVCDIR "/starting",
598 RC_SVCDIR "/started",
599 RC_SVCDIR "/stopping",
600 RC_SVCDIR "/inactive",
601 RC_SVCDIR "/wasinactive",
602 RC_SVCDIR "/failed",
603 RC_SVCDIR "/coldplugged",
604 RC_SVCDIR "/daemons",
605 RC_SVCDIR "/options",
606 RC_SVCDIR "/exclusive",
607 RC_SVCDIR "/scheduled",
608 NULL
609 };
610
611 bool rc_deptree_update_needed (void)
612 {
613 bool newer = false;
614 char **config;
615 char *service;
616 int i;
617
618 /* Create base directories if needed */
619 for (i = 0; depdirs[i]; i++)
620 if (mkdir (depdirs[i], 0755) != 0 && errno != EEXIST)
621 fprintf (stderr, "mkdir `%s': %s", depdirs[i], strerror (errno));
622
623 /* Quick test to see if anything we use has changed */
624 if (! is_newer_than (RC_DEPTREE, RC_INITDIR) ||
625 ! is_newer_than (RC_DEPTREE, RC_CONFDIR) ||
626 ! is_newer_than (RC_DEPTREE, "/etc/rc.conf"))
627 return (true);
628
629 /* Some init scripts dependencies change depending on config files
630 * outside of baselayout, like syslog-ng, so we check those too. */
631 config = rc_config_list (RC_DEPCONFIG);
632 STRLIST_FOREACH (config, service, i) {
633 if (! is_newer_than (RC_DEPTREE, service)) {
634 newer = true;
635 break;
636 }
637 }
638 rc_strlist_free (config);
639
640 return (newer);
641 }
642 librc_hidden_def(rc_deptree_update_needed)
643
644 /* This is a 5 phase operation
645 Phase 1 is a shell script which loads each init script and config in turn
646 and echos their dependency info to stdout
647 Phase 2 takes that and populates a depinfo object with that data
648 Phase 3 adds any provided services to the depinfo object
649 Phase 4 scans that depinfo object and puts in backlinks
650 Phase 5 saves the depinfo object to disk
651 */
652 bool rc_deptree_update (void)
653 {
654 char *depends;
655 char *service;
656 char *type;
657 char *depend;
658 char **config = NULL;
659 int retval = true;
660 FILE *fp;
661 rc_depinfo_t *deptree;
662 rc_depinfo_t *depinfo;
663 rc_depinfo_t *di;
664 rc_depinfo_t *last_depinfo = NULL;
665 rc_deptype_t *deptype = NULL;
666 rc_deptype_t *dt;
667 rc_deptype_t *last_deptype = NULL;
668 char *buffer = NULL;
669 int len;
670 int i;
671 int j;
672 int k;
673 bool already_added;
674
675 /* Some init scripts need RC_LIBDIR to source stuff
676 Ideally we should be setting our full env instead */
677 if (! getenv ("RC_LIBDIR"))
678 setenv ("RC_LIBDIR", RC_LIBDIR, 0);
679
680 /* Phase 1 */
681 if (! (fp = popen (GENDEP, "r")))
682 return (false);
683
684 deptree = xmalloc (sizeof (rc_depinfo_t));
685 memset (deptree, 0, sizeof (rc_depinfo_t));
686 buffer = xmalloc (sizeof (char) * RC_LINEBUFFER);
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 = xmalloc (sizeof (rc_depinfo_t));
716 depinfo = last_depinfo->next;
717 }
718 memset (depinfo, 0, sizeof (rc_depinfo_t));
719 depinfo->service = 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 = xmalloc (sizeof (rc_deptype_t));
741 deptype = depinfo->depends;
742 }
743 else
744 {
745 last_deptype->next = xmalloc (sizeof (rc_deptype_t));
746 deptype = last_deptype->next;
747 }
748 memset (deptype, 0, sizeof (rc_deptype_t));
749 deptype->type = 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 free (buffer);
779
780 /* Phase 3 - add our providors to the tree */
781 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
782 {
783 if ((deptype = get_deptype (depinfo, "iprovide")))
784 STRLIST_FOREACH (deptype->services, service, i)
785 {
786 for (di = deptree; di; di = di->next)
787 {
788 last_depinfo = di;
789 if (strcmp (di->service, service) == 0)
790 break;
791 }
792 if (! di)
793 {
794 last_depinfo->next = xmalloc (sizeof (rc_depinfo_t));
795 di = last_depinfo->next;
796 memset (di, 0, sizeof (rc_depinfo_t));
797 di->service = xstrdup (service);
798 }
799 }
800 }
801
802 /* Phase 4 - backreference our depends */
803 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
804 {
805 for (i = 0; deppairs[i].depend; i++)
806 {
807 deptype = get_deptype (depinfo, deppairs[i].depend);
808 if (! deptype)
809 continue;
810
811 STRLIST_FOREACH (deptype->services, service, j)
812 {
813 di = get_depinfo (deptree, service);
814 if (! di)
815 {
816 if (strcmp (deptype->type, "ineed") == 0)
817 {
818 fprintf (stderr,
819 "Service `%s' needs non existant service `%s'",
820 depinfo->service, service);
821 retval = false;
822 }
823 continue;
824 }
825
826 /* Add our deptype now */
827 last_deptype = NULL;
828 for (dt = di->depends; dt; dt = dt->next)
829 {
830 last_deptype = dt;
831 if (strcmp (dt->type, deppairs[i].addto) == 0)
832 break;
833 }
834 if (! dt)
835 {
836 if (! last_deptype)
837 {
838 di->depends = xmalloc (sizeof (rc_deptype_t));
839 dt = di->depends;
840 }
841 else
842 {
843 last_deptype->next = xmalloc (sizeof (rc_deptype_t));
844 dt = last_deptype->next;
845 }
846 memset (dt, 0, sizeof (rc_deptype_t));
847 dt->type = xstrdup (deppairs[i].addto);
848 }
849
850 already_added = false;
851 STRLIST_FOREACH (dt->services, service, k)
852 if (strcmp (service, depinfo->service) == 0)
853 {
854 already_added = true;
855 break;
856 }
857
858 if (! already_added)
859 rc_strlist_addsort (&dt->services, depinfo->service);
860 }
861 }
862 }
863
864 /* Phase 5 - save to disk
865 Now that we're purely in C, do we need to keep a shell parseable file?
866 I think yes as then it stays human readable
867 This works and should be entirely shell parseable provided that depend
868 names don't have any non shell variable characters in
869 */
870 if ((fp = fopen (RC_DEPTREE, "w"))) {
871 i = 0;
872 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
873 {
874 fprintf (fp, "depinfo_%d_service='%s'\n", i, depinfo->service);
875 for (deptype = depinfo->depends; deptype; deptype = deptype->next)
876 {
877 k = 0;
878 STRLIST_FOREACH (deptype->services, service, j)
879 {
880 fprintf (fp, "depinfo_%d_%s_%d='%s'\n", i, deptype->type,
881 k, service);
882 k++;
883 }
884 }
885 i++;
886 }
887 fclose (fp);
888 } else {
889 fprintf (stderr, "fopen `%s': %s\n", RC_DEPTREE, strerror (errno));
890 retval = false;
891 }
892
893 /* Save our external config files to disk */
894 if (config) {
895 if ((fp = fopen (RC_DEPCONFIG, "w"))) {
896 STRLIST_FOREACH (config, service, i)
897 fprintf (fp, "%s\n", service);
898 fclose (fp);
899 } else {
900 fprintf (stderr, "fopen `%s': %s\n", RC_DEPCONFIG, strerror (errno));
901 retval = false;
902 }
903 rc_strlist_free (config);
904 }
905
906 rc_deptree_free (deptree);
907
908 return (retval);
909 }
910 librc_hidden_def(rc_deptree_update)

  ViewVC Help
Powered by ViewVC 1.1.20