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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20