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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2547 - (hide annotations) (download) (as text)
Thu Apr 5 11:18:42 2007 UTC (10 years, 8 months ago) by uberlord
File MIME type: text/x-csrc
File size: 21319 byte(s)
    Rewrite the core parts in C. We now provide librc so other programs can
    query runlevels, services and state without using bash. We also provide
    libeinfo so other programs can easily use our informational functions.

    As such, we have dropped the requirement of using bash as the init script
    shell. We now use /bin/sh and have strived to make the scripts as portable
    as possible. Shells that work are bash and dash. busybox works provided
    you disable s-s-d. If you have WIPE_TMP set to yes in conf.d/bootmisc you
    should disable find too.
    zsh and ksh do not work at this time.

    Networking support is currently being re-vamped also as it was heavily bash
    array based. As such, a new config format is available like so
    config_eth0="1.2.3.4/24 5.6.7.8/16"
    or like so
    config_eth0="'1.2.3.4 netmask 255.255.255.0' '5.6.7.8 netmask 255.255.0.0'"

    We will still support the old bash array format provided that /bin/sh IS
    a link it bash.

    ChangeLog for baselayout-1 can be found in our SVN repo.
1 uberlord 2547 /*
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, 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     int 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, 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")) == NULL)
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")) == NULL)
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