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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20