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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2571 - (show annotations) (download) (as text)
Tue Apr 10 14:03:37 2007 UTC (7 years, 5 months ago) by uberlord
File MIME type: text/x-csrc
File size: 23954 byte(s)
int -> time_t
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 if (stat (target, &buf) != 0)
524 return (false);
525
526 if (mtime < buf.st_mtime)
527 return (false);
528
529 if (rc_is_dir (target))
530 {
531 char **targets = rc_ls_dir (NULL, target, 0);
532 char *t;
533 int i;
534 bool newer = true;
535 STRLIST_FOREACH (targets, t, i)
536 {
537 char *path = rc_strcatpaths (target, t, (char *) NULL);
538 newer = is_newer_than (file, path);
539 free (path);
540 if (! newer)
541 break;
542 }
543 rc_strlist_free (targets);
544 return (newer);
545 }
546
547 return (true);
548 }
549
550 typedef struct deppair
551 {
552 const char *depend;
553 const char *addto;
554 } deppair_t;
555
556 static const deppair_t deppairs[] = {
557 { "ineed", "needsme" },
558 { "iuse", "usesme" },
559 { "iafter", "ibefore" },
560 { "ibefore", "iafter" },
561 { "iprovide", "providedby" },
562 { NULL, NULL }
563 };
564
565 static const char *depdirs[] =
566 {
567 RC_SVCDIR "starting",
568 RC_SVCDIR "started",
569 RC_SVCDIR "stopping",
570 RC_SVCDIR "inactive",
571 RC_SVCDIR "wasinactive",
572 RC_SVCDIR "failed",
573 RC_SVCDIR "coldplugged",
574 RC_SVCDIR "daemons",
575 RC_SVCDIR "options",
576 RC_SVCDIR "exclusive",
577 RC_SVCDIR "scheduled",
578 RC_SVCDIR "ebuffer",
579 NULL
580 };
581
582 /* This is a 5 phase operation
583 Phase 1 is a shell script which loads each init script and config in turn
584 and echos their dependency info to stdout
585 Phase 2 takes that and populates a depinfo object with that data
586 Phase 3 adds any provided services to the depinfo object
587 Phase 4 scans that depinfo object and puts in backlinks
588 Phase 5 saves the depinfo object to disk
589 */
590 int rc_update_deptree (bool force)
591 {
592 char *depends;
593 char *service;
594 char *type;
595 char *depend;
596 int retval = 0;
597 FILE *fp;
598 rc_depinfo_t *deptree;
599 rc_depinfo_t *depinfo;
600 rc_depinfo_t *di;
601 rc_depinfo_t *last_depinfo = NULL;
602 rc_deptype_t *deptype;
603 rc_deptype_t *dt;
604 rc_deptype_t *last_deptype = NULL;
605 char buffer[RC_LINEBUFFER];
606 int len;
607 int i;
608 int j;
609 int k;
610 bool already_added;
611
612 /* Create base directories if needed */
613 for (i = 0; depdirs[i]; i++)
614 if (! rc_is_dir (depdirs[i]))
615 if (mkdir (depdirs[i], 0755) != 0)
616 eerrorx ("mkdir `%s': %s", depdirs[i], strerror (errno));
617
618 if (! force)
619 if (is_newer_than (RC_DEPTREE, RC_INITDIR) &&
620 is_newer_than (RC_DEPTREE, RC_CONFDIR) &&
621 is_newer_than (RC_DEPTREE, "/etc/rc.conf"))
622 return 0;
623
624 ebegin ("Caching service dependencies");
625
626 /* Some init scripts need RC_LIBDIR to source stuff
627 Ideally we should be setting our full env instead */
628 if (! getenv ("RC_LIBDIR"))
629 setenv ("RC_LIBDIR", RC_LIBDIR, 0);
630
631 /* Phase 1 */
632 if (! (fp = popen (GENDEP, "r")))
633 eerrorx ("popen: %s", strerror (errno));
634
635 deptree = rc_xmalloc (sizeof (rc_depinfo_t));
636 memset (deptree, 0, sizeof (rc_depinfo_t));
637 memset (buffer, 0, RC_LINEBUFFER);
638
639 /* Phase 2 */
640 while (fgets (buffer, RC_LINEBUFFER, fp))
641 {
642 /* Trim the newline */
643 if (buffer[strlen (buffer) - 1] == '\n')
644 buffer[strlen(buffer) -1] = 0;
645
646 depends = buffer;
647 service = strsep (&depends, " ");
648 if (! service)
649 continue;
650 type = strsep (&depends, " ");
651
652 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
653 {
654 last_depinfo = depinfo;
655 if (depinfo->service && strcmp (depinfo->service, service) == 0)
656 break;
657 }
658
659 if (! depinfo)
660 {
661 if (! last_depinfo->service)
662 depinfo = last_depinfo;
663 else
664 {
665 last_depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
666 depinfo = last_depinfo->next;
667 }
668 memset (depinfo, 0, sizeof (rc_depinfo_t));
669 depinfo->service = strdup (service);
670 }
671
672 /* We may not have any depends */
673 if (! type || ! depends)
674 continue;
675
676 last_deptype = NULL;
677 for (deptype = depinfo->depends; deptype; deptype = deptype->next)
678 {
679 last_deptype = deptype;
680 if (strcmp (deptype->type, type) == 0)
681 break;
682 }
683
684 if (! deptype)
685 {
686 if (! last_deptype)
687 {
688 depinfo->depends = rc_xmalloc (sizeof (rc_deptype_t));
689 deptype = depinfo->depends;
690 }
691 else
692 {
693 last_deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
694 deptype = last_deptype->next;
695 }
696 memset (deptype, 0, sizeof (rc_deptype_t));
697 deptype->type = strdup (type);
698 }
699
700 /* Now add each depend to our type.
701 We do this individually so we handle multiple spaces gracefully */
702 while ((depend = strsep (&depends, " ")))
703 {
704 if (depend[0] == 0)
705 continue;
706
707 /* .sh files are not init scripts */
708 len = strlen (depend);
709 if (len > 2 &&
710 depend[len - 3] == '.' &&
711 depend[len - 2] == 's' &&
712 depend[len - 1] == 'h')
713 continue;
714
715 deptype->services = rc_strlist_addsort (deptype->services, depend);
716 }
717
718 }
719 pclose (fp);
720
721 /* Phase 3 - add our providors to the tree */
722 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
723 {
724 if ((deptype = rc_get_deptype (depinfo, "iprovide")))
725 STRLIST_FOREACH (deptype->services, service, i)
726 {
727 for (di = deptree; di; di = di->next)
728 {
729 last_depinfo = di;
730 if (strcmp (di->service, service) == 0)
731 break;
732 }
733 if (! di)
734 {
735 last_depinfo->next = rc_xmalloc (sizeof (rc_depinfo_t));
736 di = last_depinfo->next;
737 memset (di, 0, sizeof (rc_depinfo_t));
738 di->service = strdup (service);
739 }
740 }
741 }
742
743 /* Phase 4 - backreference our depends */
744 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
745 {
746 for (i = 0; deppairs[i].depend; i++)
747 {
748 deptype = rc_get_deptype (depinfo, deppairs[i].depend);
749 if (! deptype)
750 continue;
751
752 STRLIST_FOREACH (deptype->services, service, j)
753 {
754 di = rc_get_depinfo (deptree, service);
755 if (! di)
756 {
757 if (strcmp (deptype->type, "ineed") == 0)
758 {
759 eerror ("Service `%s' needs non existant service `%s'",
760 depinfo->service, service);
761 retval = -1;
762 }
763 continue;
764 }
765
766 /* Add our deptype now */
767 last_deptype = NULL;
768 for (dt = di->depends; dt; dt = dt->next)
769 {
770 last_deptype = dt;
771 if (strcmp (dt->type, deppairs[i].addto) == 0)
772 break;
773 }
774 if (! dt)
775 {
776 if (! last_deptype)
777 {
778 di->depends = rc_xmalloc (sizeof (rc_deptype_t));
779 dt = di->depends;
780 }
781 else
782 {
783 last_deptype->next = rc_xmalloc (sizeof (rc_deptype_t));
784 dt = last_deptype->next;
785 }
786 memset (dt, 0, sizeof (rc_deptype_t));
787 dt->type = strdup (deppairs[i].addto);
788 }
789
790 already_added = false;
791 STRLIST_FOREACH (dt->services, service, k)
792 if (strcmp (service, depinfo->service) == 0)
793 {
794 already_added = true;
795 break;
796 }
797
798 if (! already_added)
799 dt->services = rc_strlist_addsort (dt->services,
800 depinfo->service);
801 }
802 }
803 }
804
805 /* Phase 5 - save to disk
806 Now that we're purely in C, do we need to keep a shell parseable file?
807 I think yes as then it stays human readable
808 This works and should be entirely shell parseable provided that depend
809 names don't have any non shell variable characters in
810 */
811 if (! (fp = fopen (RC_DEPTREE, "w")))
812 eerror ("fopen `%s': %s", RC_DEPTREE, strerror (errno));
813 else
814 {
815 i = 0;
816 for (depinfo = deptree; depinfo; depinfo = depinfo->next)
817 {
818 fprintf (fp, "depinfo_%d_service='%s'\n", i, depinfo->service);
819 for (deptype = depinfo->depends; deptype; deptype = deptype->next)
820 {
821 k = 0;
822 STRLIST_FOREACH (deptype->services, service, j)
823 {
824 fprintf (fp, "depinfo_%d_%s_%d='%s'\n", i, deptype->type,
825 k, service);
826 k++;
827 }
828 }
829 i++;
830 }
831 fclose (fp);
832 }
833
834 rc_free_deptree (deptree);
835
836 eend (retval, "Failed to update the service dependency tree");
837 return (retval);
838 }

  ViewVC Help
Powered by ViewVC 1.1.20