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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3024 - (show annotations) (download) (as text)
Wed Oct 10 13:11:35 2007 UTC (6 years, 6 months ago) by uberlord
File MIME type: text/x-csrc
File size: 22219 byte(s)
rc_deptree_order_services -> rc_deptree_order
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, char **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, *item;
361 char *service;
362 rc_depinfo_t *di;
363 rc_deptype_t *dt;
364 char **provides;
365 char *svcname;
366
367 if (! deptree || !sorted || !visited || !depinfo)
368 return;
369
370 /* Check if we have already visited this service or not */
371 STRLIST_FOREACH (visited->list, item, i)
372 if (strcmp (item, depinfo->service) == 0)
373 return;
374
375 /* Add ourselves as a visited service */
376 rc_strlist_add (&visited->list, depinfo->service);
377
378 STRLIST_FOREACH (types, item, i)
379 {
380 if ((dt = get_deptype (depinfo, item)))
381 {
382 STRLIST_FOREACH (dt->services, service, j)
383 {
384 if (! options & RC_DEP_TRACE || strcmp (item, "iprovide") == 0)
385 {
386 rc_strlist_add (&sorted->list, service);
387 continue;
388 }
389
390 di = get_depinfo (deptree, service);
391 if ((provides = get_provided (deptree, di, runlevel, options)))
392 {
393 STRLIST_FOREACH (provides, lp, k)
394 {
395 di = get_depinfo (deptree, lp);
396 if (di && (strcmp (item, "ineed") == 0 ||
397 strcmp (item, "needsme") == 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 strcmp (item, "needsme") == 0 ||
407 valid_service (runlevel, service)))
408 visit_service (deptree, types, sorted, visited, di,
409 runlevel, options | RC_DEP_TRACE);
410 }
411 }
412 }
413
414 /* Now visit the stuff we provide for */
415 if (options & RC_DEP_TRACE &&
416 (dt = get_deptype (depinfo, "iprovide")))
417 {
418 STRLIST_FOREACH (dt->services, service, i)
419 {
420 if ((di = get_depinfo (deptree, service)))
421 if ((provides = get_provided (deptree, di, runlevel, options)))
422 {
423 STRLIST_FOREACH (provides, lp, j)
424 if (strcmp (lp, depinfo->service) == 0)
425 {
426 visit_service (deptree, types, sorted, visited, di,
427 runlevel, options | RC_DEP_TRACE);
428 break;
429 }
430 rc_strlist_free (provides);
431 }
432 }
433 }
434
435 /* We've visited everything we need, so add ourselves unless we
436 are also the service calling us or we are provided by something */
437 svcname = getenv("SVCNAME");
438 if (! svcname || strcmp (svcname, depinfo->service) != 0)
439 if (! get_deptype (depinfo, "providedby"))
440 rc_strlist_add (&sorted->list, depinfo->service);
441 }
442
443 char **rc_deptree_depends (rc_depinfo_t *deptree,
444 char **types, char **services,
445 const char *runlevel, int options)
446 {
447 struct lhead sorted;
448 struct lhead visited;
449 rc_depinfo_t *di;
450 char *service;
451 int i;
452
453 if (! deptree || ! services)
454 return (NULL);
455
456 memset (&sorted, 0, sizeof (struct lhead));
457 memset (&visited, 0, sizeof (struct lhead));
458
459 bootlevel = getenv ("RC_BOOTLEVEL");
460 if (! bootlevel)
461 bootlevel = RC_LEVEL_BOOT;
462
463 STRLIST_FOREACH (services, service, i)
464 {
465 if (! (di = get_depinfo (deptree, service))) {
466 errno = ENOENT;
467 continue;
468 }
469 if (types)
470 visit_service (deptree, types, &sorted, &visited,
471 di, runlevel, options);
472 }
473
474 rc_strlist_free (visited.list);
475 return (sorted.list);
476 }
477 librc_hidden_def(rc_deptree_depends)
478
479 char **rc_deptree_order (rc_depinfo_t *deptree, const char *runlevel,
480 int options)
481 {
482 char **list = NULL;
483 char **types = NULL;
484 char **services = NULL;
485 bool reverse = false;
486 char **tmp = NULL;
487
488 if (! runlevel)
489 return (NULL);
490
491 bootlevel = getenv ("RC_BOOTLEVEL");
492 if (! bootlevel)
493 bootlevel = RC_LEVEL_BOOT;
494
495 /* When shutting down, list all running services */
496 if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
497 strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
498 strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
499 {
500 list = rc_services_in_state (RC_SERVICE_STARTED);
501
502 tmp = rc_services_in_state (RC_SERVICE_INACTIVE);
503 rc_strlist_join (&list, tmp);
504 rc_strlist_free (tmp);
505
506 tmp = rc_services_in_state (RC_SERVICE_STARTING);
507 rc_strlist_join (&list, tmp);
508 rc_strlist_free (tmp);
509 reverse = true;
510 } else {
511 list = rc_services_in_runlevel (runlevel);
512
513 /* Add coldplugged services */
514 tmp = rc_services_in_state (RC_SERVICE_COLDPLUGGED);
515 rc_strlist_join (&list, tmp);
516 rc_strlist_free (tmp);
517
518 /* If we're not the boot runlevel then add that too */
519 if (strcmp (runlevel, bootlevel) != 0) {
520 tmp = rc_services_in_runlevel (bootlevel);
521 rc_strlist_join (&list, tmp);
522 rc_strlist_free (tmp);
523 }
524 }
525
526 /* Now we have our lists, we need to pull in any dependencies
527 and order them */
528 rc_strlist_add (&types, "ineed");
529 rc_strlist_add (&types, "iuse");
530 rc_strlist_add (&types, "iafter");
531 services = rc_deptree_depends (deptree, types, list, runlevel,
532 RC_DEP_STRICT | RC_DEP_TRACE | options);
533 rc_strlist_free (list);
534 rc_strlist_free (types);
535
536 if (reverse)
537 rc_strlist_reverse (services);
538
539 return (services);
540 }
541 librc_hidden_def(rc_deptree_order)
542
543 static bool is_newer_than (const char *file, const char *target)
544 {
545 struct stat buf;
546 time_t mtime;
547 bool newer = true;
548 DIR *dp;
549 struct dirent *d;
550 char *path;
551
552 if (stat (file, &buf) != 0 || buf.st_size == 0)
553 return (false);
554 mtime = buf.st_mtime;
555
556 /* Of course we are newever than targets that don't exist
557 Such as broken symlinks */
558 if (stat (target, &buf) != 0)
559 return (true);
560
561 if (mtime < buf.st_mtime)
562 return (false);
563
564 if (! (dp = opendir (target)))
565 return (true);
566
567 while ((d = readdir (dp))) {
568 if (d->d_name[0] == '.')
569 continue;
570
571 path = rc_strcatpaths (target, d->d_name, (char *) NULL);
572 newer = is_newer_than (file, path);
573 free (path);
574 if (! newer)
575 break;
576 }
577 closedir (dp);
578
579 return (newer);
580 }
581
582 typedef struct deppair
583 {
584 const char *depend;
585 const char *addto;
586 } deppair_t;
587
588 static const deppair_t deppairs[] = {
589 { "ineed", "needsme" },
590 { "iuse", "usesme" },
591 { "iafter", "ibefore" },
592 { "ibefore", "iafter" },
593 { "iprovide", "providedby" },
594 { NULL, NULL }
595 };
596
597 static const char *depdirs[] =
598 {
599 RC_SVCDIR "/starting",
600 RC_SVCDIR "/started",
601 RC_SVCDIR "/stopping",
602 RC_SVCDIR "/inactive",
603 RC_SVCDIR "/wasinactive",
604 RC_SVCDIR "/failed",
605 RC_SVCDIR "/coldplugged",
606 RC_SVCDIR "/daemons",
607 RC_SVCDIR "/options",
608 RC_SVCDIR "/exclusive",
609 RC_SVCDIR "/scheduled",
610 NULL
611 };
612
613 bool rc_deptree_update_needed (void)
614 {
615 bool newer = false;
616 char **config;
617 char *service;
618 int i;
619
620 /* Create base directories if needed */
621 for (i = 0; depdirs[i]; i++)
622 if (mkdir (depdirs[i], 0755) != 0 && errno != EEXIST)
623 fprintf (stderr, "mkdir `%s': %s", depdirs[i], strerror (errno));
624
625 /* Quick test to see if anything we use has changed */
626 if (! is_newer_than (RC_DEPTREE, RC_INITDIR) ||
627 ! is_newer_than (RC_DEPTREE, RC_CONFDIR) ||
628 ! is_newer_than (RC_DEPTREE, "/etc/rc.conf"))
629 return (true);
630
631 /* Some init scripts dependencies change depending on config files
632 * outside of baselayout, like syslog-ng, so we check those too. */
633 config = rc_config_list (RC_DEPCONFIG);
634 STRLIST_FOREACH (config, service, i) {
635 if (! is_newer_than (RC_DEPTREE, service)) {
636 newer = true;
637 break;
638 }
639 }
640 rc_strlist_free (config);
641
642 return (newer);
643 }
644 librc_hidden_def(rc_deptree_update_needed)
645
646 /* This is a 5 phase operation
647 Phase 1 is a shell script which loads each init script and config in turn
648 and echos their dependency info to stdout
649 Phase 2 takes that and populates a depinfo object with that data
650 Phase 3 adds any provided services to the depinfo object
651 Phase 4 scans that depinfo object and puts in backlinks
652 Phase 5 saves the depinfo object to disk
653 */
654 bool rc_deptree_update (void)
655 {
656 char *depends;
657 char *service;
658 char *type;
659 char *depend;
660 char **config = NULL;
661 int retval = true;
662 FILE *fp;
663 rc_depinfo_t *deptree;
664 rc_depinfo_t *depinfo;
665 rc_depinfo_t *di;
666 rc_depinfo_t *last_depinfo = NULL;
667 rc_deptype_t *deptype = NULL;
668 rc_deptype_t *dt;
669 rc_deptype_t *last_deptype = NULL;
670 char buffer[RC_LINEBUFFER];
671 int len;
672 int i;
673 int j;
674 int k;
675 bool already_added;
676
677 /* Some init scripts need RC_LIBDIR to source stuff
678 Ideally we should be setting our full env instead */
679 if (! getenv ("RC_LIBDIR"))
680 setenv ("RC_LIBDIR", RC_LIBDIR, 0);
681
682 /* Phase 1 */
683 if (! (fp = popen (GENDEP, "r")))
684 return (false);
685
686 deptree = xmalloc (sizeof (rc_depinfo_t));
687 memset (deptree, 0, sizeof (rc_depinfo_t));
688 memset (buffer, 0, RC_LINEBUFFER);
689
690 /* Phase 2 */
691 while (fgets (buffer, RC_LINEBUFFER, fp))
692 {
693 /* Trim the newline */
694 if (buffer[strlen (buffer) - 1] == '\n')
695 buffer[strlen(buffer) -1] = 0;
696
697 depends = buffer;
698 service = strsep (&depends, " ");
699 if (! service)
700 continue;
701 type = strsep (&depends, " ");
702
703 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
704 {
705 last_depinfo = depinfo;
706 if (depinfo->service && strcmp (depinfo->service, service) == 0)
707 break;
708 }
709
710 if (! depinfo)
711 {
712 if (! last_depinfo->service)
713 depinfo = last_depinfo;
714 else
715 {
716 last_depinfo->next = xmalloc (sizeof (rc_depinfo_t));
717 depinfo = last_depinfo->next;
718 }
719 memset (depinfo, 0, sizeof (rc_depinfo_t));
720 depinfo->service = xstrdup (service);
721 }
722
723 /* We may not have any depends */
724 if (! type || ! depends)
725 continue;
726
727 /* Get the type */
728 if (strcmp (type, "config") != 0) {
729 last_deptype = NULL;
730 for (deptype = depinfo->depends; deptype; deptype = deptype->next)
731 {
732 last_deptype = deptype;
733 if (strcmp (deptype->type, type) == 0)
734 break;
735 }
736
737 if (! deptype)
738 {
739 if (! last_deptype)
740 {
741 depinfo->depends = xmalloc (sizeof (rc_deptype_t));
742 deptype = depinfo->depends;
743 }
744 else
745 {
746 last_deptype->next = xmalloc (sizeof (rc_deptype_t));
747 deptype = last_deptype->next;
748 }
749 memset (deptype, 0, sizeof (rc_deptype_t));
750 deptype->type = xstrdup (type);
751 }
752 }
753
754 /* Now add each depend to our type.
755 We do this individually so we handle multiple spaces gracefully */
756 while ((depend = strsep (&depends, " ")))
757 {
758 if (depend[0] == 0)
759 continue;
760
761 if (strcmp (type, "config") == 0) {
762 rc_strlist_addsort (&config, depend);
763 continue;
764 }
765
766 /* .sh files are not init scripts */
767 len = strlen (depend);
768 if (len > 2 &&
769 depend[len - 3] == '.' &&
770 depend[len - 2] == 's' &&
771 depend[len - 1] == 'h')
772 continue;
773
774 rc_strlist_addsort (&deptype->services, depend);
775 }
776
777 }
778 pclose (fp);
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