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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20