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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2889 - (show annotations) (download) (as text)
Tue Sep 18 15:43:19 2007 UTC (7 years ago) by uberlord
File MIME type: text/x-csrc
File size: 22525 byte(s)
Don't be an ass - don't free the 2nd list. Instead just empty it.
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 char **tmp = NULL;
483
484 if (! runlevel)
485 return (NULL);
486
487 bootlevel = getenv ("RC_BOOTLEVEL");
488 if (! bootlevel)
489 bootlevel = RC_LEVEL_BOOT;
490
491 /* When shutting down, list all running services */
492 if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
493 strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
494 strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
495 {
496 list = rc_ls_dir (RC_SVCDIR_STARTING, RC_LS_INITD);
497
498 tmp = rc_ls_dir (RC_SVCDIR_INACTIVE, RC_LS_INITD);
499 rc_strlist_join (&list, tmp);
500 rc_strlist_free (tmp);
501
502 tmp = rc_ls_dir (RC_SVCDIR_INACTIVE, RC_LS_INITD);
503 rc_strlist_join (&list, tmp);
504 rc_strlist_free (tmp);
505 reverse = true;
506 } else {
507 list = rc_services_in_runlevel (runlevel);
508
509 /* Add coldplugged services */
510 tmp = rc_ls_dir (RC_SVCDIR_COLDPLUGGED, RC_LS_INITD);
511 rc_strlist_join (&list, tmp);
512 rc_strlist_free (tmp);
513
514 /* If we're not the boot runlevel then add that too */
515 if (strcmp (runlevel, bootlevel) != 0) {
516 char *path = rc_strcatpaths (RC_RUNLEVELDIR, bootlevel,
517 (char *) NULL);
518 tmp = rc_ls_dir (path, RC_LS_INITD);
519 rc_strlist_join (&list, tmp);
520 rc_strlist_free (tmp);
521 free (path);
522 }
523 }
524
525 /* Now we have our lists, we need to pull in any dependencies
526 and order them */
527 rc_strlist_add (&types, "ineed");
528 rc_strlist_add (&types, "iuse");
529 rc_strlist_add (&types, "iafter");
530 services = rc_get_depends (deptree, types, list, runlevel,
531 RC_DEP_STRICT | RC_DEP_TRACE | options);
532 rc_strlist_free (list);
533 rc_strlist_free (types);
534
535 if (reverse)
536 rc_strlist_reverse (services);
537
538 return (services);
539 }
540 librc_hidden_def(rc_order_services)
541
542 static bool is_newer_than (const char *file, const char *target)
543 {
544 struct stat buf;
545 time_t mtime;
546
547 if (stat (file, &buf) != 0 || buf.st_size == 0)
548 return (false);
549 mtime = buf.st_mtime;
550
551 /* Of course we are newever than targets that don't exist
552 Such as broken symlinks */
553 if (stat (target, &buf) != 0)
554 return (true);
555
556 if (mtime < buf.st_mtime)
557 return (false);
558
559 if (rc_is_dir (target))
560 {
561 char **targets = rc_ls_dir (target, 0);
562 char *t;
563 int i;
564 bool newer = true;
565 STRLIST_FOREACH (targets, t, i)
566 {
567 char *path = rc_strcatpaths (target, t, (char *) NULL);
568 newer = is_newer_than (file, path);
569 free (path);
570 if (! newer)
571 break;
572 }
573 rc_strlist_free (targets);
574 return (newer);
575 }
576
577 return (true);
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 /* This is a 5 phase operation
612 Phase 1 is a shell script which loads each init script and config in turn
613 and echos their dependency info to stdout
614 Phase 2 takes that and populates a depinfo object with that data
615 Phase 3 adds any provided services to the depinfo object
616 Phase 4 scans that depinfo object and puts in backlinks
617 Phase 5 saves the depinfo object to disk
618 */
619 int rc_update_deptree (bool force)
620 {
621 char *depends;
622 char *service;
623 char *type;
624 char *depend;
625 char **config = NULL;
626 int retval = 0;
627 FILE *fp;
628 rc_depinfo_t *deptree;
629 rc_depinfo_t *depinfo;
630 rc_depinfo_t *di;
631 rc_depinfo_t *last_depinfo = NULL;
632 rc_deptype_t *deptype = NULL;
633 rc_deptype_t *dt;
634 rc_deptype_t *last_deptype = NULL;
635 char buffer[RC_LINEBUFFER];
636 int len;
637 int i;
638 int j;
639 int k;
640 bool already_added;
641
642 /* Create base directories if needed */
643 for (i = 0; depdirs[i]; i++)
644 if (! rc_is_dir (depdirs[i]))
645 if (mkdir (depdirs[i], 0755) != 0)
646 eerrorx ("mkdir `%s': %s", depdirs[i], strerror (errno));
647
648 /* Quick test to see if anything we use has changed */
649 if (! force &&
650 is_newer_than (RC_DEPTREE, RC_INITDIR) &&
651 is_newer_than (RC_DEPTREE, RC_CONFDIR) &&
652 is_newer_than (RC_DEPTREE, "/etc/rc.conf"))
653 {
654 bool newer = false;
655
656 /* Some init scripts dependencies change depending on config files
657 * outside of baselayout, like syslog-ng, so we check those too. */
658 if (! rc_exists (RC_DEPCONFIG))
659 return 0;
660
661 config = rc_get_list (RC_DEPCONFIG);
662 STRLIST_FOREACH (config, service, i) {
663 if (! is_newer_than (RC_DEPTREE, service)) {
664 newer = true;
665 break;
666 }
667 }
668 rc_strlist_free (config);
669 config = NULL;
670
671 if (! newer)
672 return (0);
673 }
674
675 ebegin ("Caching service dependencies");
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 eerrorx ("popen: %s", strerror (errno));
685
686 deptree = rc_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 = rc_xmalloc (sizeof (rc_depinfo_t));
717 depinfo = last_depinfo->next;
718 }
719 memset (depinfo, 0, sizeof (rc_depinfo_t));
720 depinfo->service = rc_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 = rc_xmalloc (sizeof (rc_deptype_t));
742 deptype = depinfo->depends;
743 }
744 else
745 {
746 last_deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
747 deptype = last_deptype->next;
748 }
749 memset (deptype, 0, sizeof (rc_deptype_t));
750 deptype->type = rc_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 = rc_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 = rc_xmalloc (sizeof (rc_depinfo_t));
795 di = last_depinfo->next;
796 memset (di, 0, sizeof (rc_depinfo_t));
797 di->service = rc_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 = rc_get_deptype (depinfo, deppairs[i].depend);
808 if (! deptype)
809 continue;
810
811 STRLIST_FOREACH (deptype->services, service, j)
812 {
813 di = rc_get_depinfo (deptree, service);
814 if (! di)
815 {
816 if (strcmp (deptype->type, "ineed") == 0)
817 {
818 eerror ("Service `%s' needs non existant service `%s'",
819 depinfo->service, service);
820 retval = -1;
821 }
822 continue;
823 }
824
825 /* Add our deptype now */
826 last_deptype = NULL;
827 for (dt = di->depends; dt; dt = dt->next)
828 {
829 last_deptype = dt;
830 if (strcmp (dt->type, deppairs[i].addto) == 0)
831 break;
832 }
833 if (! dt)
834 {
835 if (! last_deptype)
836 {
837 di->depends = rc_xmalloc (sizeof (rc_deptype_t));
838 dt = di->depends;
839 }
840 else
841 {
842 last_deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
843 dt = last_deptype->next;
844 }
845 memset (dt, 0, sizeof (rc_deptype_t));
846 dt->type = rc_xstrdup (deppairs[i].addto);
847 }
848
849 already_added = false;
850 STRLIST_FOREACH (dt->services, service, k)
851 if (strcmp (service, depinfo->service) == 0)
852 {
853 already_added = true;
854 break;
855 }
856
857 if (! already_added)
858 rc_strlist_addsort (&dt->services, depinfo->service);
859 }
860 }
861 }
862
863 /* Phase 5 - save to disk
864 Now that we're purely in C, do we need to keep a shell parseable file?
865 I think yes as then it stays human readable
866 This works and should be entirely shell parseable provided that depend
867 names don't have any non shell variable characters in
868 */
869 if (! (fp = fopen (RC_DEPTREE, "w")))
870 eerror ("fopen `%s': %s", RC_DEPTREE, strerror (errno));
871 else
872 {
873 i = 0;
874 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
875 {
876 fprintf (fp, "depinfo_%d_service='%s'\n", i, depinfo->service);
877 for (deptype = depinfo->depends; deptype; deptype = deptype->next)
878 {
879 k = 0;
880 STRLIST_FOREACH (deptype->services, service, j)
881 {
882 fprintf (fp, "depinfo_%d_%s_%d='%s'\n", i, deptype->type,
883 k, service);
884 k++;
885 }
886 }
887 i++;
888 }
889 fclose (fp);
890 }
891
892 /* Save our external config files to disk */
893 if (config) {
894 if (! (fp = fopen (RC_DEPCONFIG, "w")))
895 eerror ("fopen `%s': %s", RC_DEPCONFIG, strerror (errno));
896 else
897 {
898 STRLIST_FOREACH (config, service, i)
899 fprintf (fp, "%s\n", service);
900 fclose (fp);
901 }
902 rc_strlist_free (config);
903 }
904
905 rc_free_deptree (deptree);
906
907 eend (retval, "Failed to update the service dependency tree");
908 return (retval);
909 }
910 librc_hidden_def(rc_update_deptree)

  ViewVC Help
Powered by ViewVC 1.1.20