4 * Copyright 2000-2008 Werner Fink, 2000 SuSE GmbH Nuernberg, Germany,
5 * 2003 SuSE Linux AG, Germany.
6 * 2007-2008 SuSE Linux Products GmbH Nuernberg, Germany
8 * This source is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
20 #include <sys/types.h>
24 int maxstart = 0; /* Maximum start order of runlevels 0 upto 6 and S */
25 int maxstop = 0; /* Maximum stop order of runlevels 0 upto 6 and S */
26 static int *maxorder; /* Pointer to one of above */
28 /* See listing.c for list_t and list_entry() macro */
29 #define getdir(list) list_entry((list), dir_t, d_list)
30 #define getlink(list) list_entry((list), link_t, l_list)
31 #define getnextlink(list) (list_empty(list) ? (dir_t*)0 : getlink((list)->next)->target)
34 * We handle services (aka scripts) as directories because
35 * dependencies can be handels as symbolic links therein.
36 * A provided service will be linked into a required service.
37 * For the general type of linked lists see listing.h.
40 typedef struct dir_struct dir_t;
42 typedef struct link_struct {
43 list_t l_list; /* The linked list of symbolic links */
44 dir_t *restrict target;
45 } __align link_t; /* This is a "symbolic link" */
47 typedef struct handle_struct {
48 list_t link; /* The linked list of symbolic start/stop links in the directory */
51 uchar mindeep; /* Default start/stop deep if any */
52 uchar deep; /* Current start/stop deep */
57 list_t d_list; /* The peg into linked list to other directories */
60 service_t *restrict serv;
64 } __align; /* This is a "directory" */
66 #define attof(dir) (&(dir)->serv->attr)
69 * The linked list off all directories, note that the s_list
70 * entry within the dir_struct is used as the peg pointer.
72 static list_t dirs = { &dirs, &dirs };
73 static list_t * d_start = &dirs;
75 #define DIR_SCAN 0x0001
76 #define DIR_LOOP 0x0002
77 #define DIR_LOOPREPORT 0x0004
78 #define DIR_MAXDEEP 0x0008
81 * The linked list off all services, note that the d_list
82 * entry within the service_struct is used as the peg pointer.
84 static list_t servs = { &servs, &servs };
85 list_t * s_start = &servs;
88 * Provide or find a service dir, set initial states and
89 * link it into the maintaining if a new one.
92 static inline dir_t * providedir(const char *restrict const name) attribute((malloc,always_inline,nonnull(1)));
93 static inline dir_t * providedir(const char *restrict const name)
95 dir_t *restrict dir = (dir_t*)0;
96 service_t *restrict serv;
99 list_for_each_prev(ptr, d_start) {
101 if (!strcmp(dir->name, name))
105 if (posix_memalign((void*)&serv, sizeof(void*), alignof(service_t)+strsize(name)) != 0)
106 error("%s", strerror(errno));
108 memset(serv, 0, alignof(service_t)+strsize(name));
109 insert(&serv->s_list, s_start->prev);
110 serv->name = ((char*)serv)+alignof(service_t);
112 if (posix_memalign((void*)&dir, sizeof(void*), alignof(dir_t)) != 0)
113 error("%s", strerror(errno));
115 memset(dir, 0, alignof(dir_t));
116 insert(&dir->d_list, d_start->prev);
119 serv->dir = (void*)dir;
122 initial(&dir->start.link);
123 initial(&dir->stopp.link);
125 initial(&serv->sort.req);
126 initial(&serv->sort.rev);
128 strcpy(serv->name, name);
129 dir->name = serv->name;
130 dir->start.name = serv->name;
131 dir->stopp.name = serv->name;
133 dir->start.mindeep = 1;
134 dir->stopp.mindeep = 1;
136 serv->start = &dir->start.run;
137 serv->stopp = &dir->stopp.run;
143 * Find or add and initialize a service
145 service_t * addservice(const char *restrict const serv) attribute((malloc,nonnull(1)));
146 service_t * addservice(const char *restrict const serv)
152 list_for_each_prev(ptr, s_start) {
153 this = getservice(ptr);
154 if (!strcmp(this->name, serv))
157 dir = providedir(serv);
164 * Always return the address of the original service
166 service_t * getorig(service_t *restrict const serv)
168 dir_t *const dir = (dir_t *)serv->dir;
173 * Find a service dir by its script name.
175 static inline dir_t * findscript(const char *restrict const script) attribute((always_inline,nonnull(1)));
176 static inline dir_t * findscript(const char *restrict const script)
178 dir_t * ret = (dir_t*)0;
181 list_for_each_prev(ptr, d_start) {
182 dir_t * dir = getdir(ptr);
187 if (!strcmp(dir->script, script)) {
197 * Link the current service into the required service.
198 * If the services do not exist, they will be created.
200 static void ln_sf(dir_t *restrict cur, dir_t *restrict req, const char mode) attribute((nonnull(1,2)));
201 static void ln_sf(dir_t *restrict cur, dir_t *restrict req, const char mode)
203 list_t * dent, * l_list = (mode == 'K') ? &req->stopp.link : &req->start.link;
204 link_t *restrict this;
209 list_for_each_prev(dent, l_list) {
210 dir_t * target = getlink(dent)->target;
211 if (!strcmp(target->name, cur->name))
215 if (posix_memalign((void*)&this, sizeof(void*), alignof(link_t)) == 0) {
216 insert(&this->l_list, l_list->prev);
221 error("%s", strerror(errno));
227 * Remember loops to warn only once
229 static inline boolean remembernode (handle_t *restrict const peg) attribute((always_inline,nonnull(1)));
230 static inline boolean remembernode (handle_t *restrict const peg)
232 register boolean ret = true;
234 if (peg->flags & DIR_LOOP)
238 peg->flags |= DIR_LOOP;
244 * Recursively called function to follow all
245 * links within a service dir.
246 * Just like a `find * -follow' within a directory tree
247 * of depth one with cross linked dependencies.
249 * Be warned: the direction is naturally reversed. That
250 * means that the most requested services have the lowest
251 * order. In other word, an empty link list of a service
252 * indicates that this service has a higher order number.
254 #if defined(DEBUG) && (DEBUG > 0)
255 # define loop_warn_two(a,b,o) \
256 warn("There is a loop between service %s and %s if %s (list:%d)\n", \
257 (a)->name, (b)->name, o, __LINE__)
258 # define loop_warn_one(a,o) \
259 warn("There is a loop at service %s if %s (list:%d)\n", \
260 (a)->name, o, __LINE__)
262 # define loop_warn_two(a,b,o) \
263 warn("There is a loop between service %s and %s if %s\n", (a)->name, (b)->name, o)
264 # define loop_warn_one(a,o) \
265 warn("There is a loop at service %s if %s\n", (a)->name, o)
267 #define loop_check(a) \
268 ((a) && (a)->flags & DIR_LOOP)
270 static void __follow (dir_t *restrict dir, dir_t *restrict skip, const int, const char, const char)
271 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
272 attribute((noinline,flatten,nonnull(1)));
274 attribute((noinline,nonnull(1)));
276 static void __follow (dir_t *restrict dir, dir_t *restrict skip, const int level, const char mode, const char reportloop)
280 register int deep = level; /* Link depth, maybe we're called recursively */
281 register int loop = 0; /* Count number of links in symbolic list */
282 handle_t * peg, * pskp = (handle_t*)0;
287 if (skip) pskp = &skip->stopp;
291 if (skip) pskp = &skip->start;
295 prefetch(l_list->next);
297 if (peg->flags & DIR_SCAN) {
299 if (!remembernode(pskp) || !remembernode(peg))
300 loop_warn_two(peg, pskp, act);
302 /* Does this happen? */
303 if (!remembernode(pskp))
304 loop_warn_one(peg, act);
309 if (deep < (peg->mindeep)) /* Default deep of this tree is higher */
310 deep = (peg->mindeep);
312 if (deep > MAX_DEEP) {
313 if ((peg->flags & DIR_MAXDEEP) == 0)
314 warn("Max recursions depth %d for %s reached\n", MAX_DEEP, peg->name);
315 peg->flags |= DIR_MAXDEEP;
319 for (tmp = dir; tmp; tmp = getnextlink(l_list)) {
320 register boolean recursion = true;
321 handle_t * ptmp = (mode == 'K') ? &tmp->stopp : &tmp->start;
322 uchar * order = &ptmp->deep;
325 if (loop++ > MAX_DEEP) {
327 if (!remembernode(pskp) || !remembernode(ptmp))
328 loop_warn_two(ptmp, pskp, act);
330 if (!remembernode(ptmp))
331 loop_warn_one(ptmp, act);
333 break; /* Loop detected, stop recursion */
335 l_list = &ptmp->link; /* List of symbolic links for getnextlink() */
336 prefetch(l_list->next);
338 if (!((peg->run.lvl) & (ptmp->run.lvl)))
339 continue; /* Not same boot level */
341 if (pskp && pskp == ptmp) {
342 if (!remembernode(pskp) || !remembernode(ptmp))
343 loop_warn_one(pskp, act);
344 break; /* Loop detected, stop recursion */
348 * As higher the link depth, as higher the start order.
355 if ((ptmp->run.lvl) & LVL_ALL) {
356 if (maxorder && (*maxorder < *order))
360 if (list_empty(l_list))
361 break; /* No further service requires this one */
364 * Do not count the dependcy deep of the system facilities
365 * but follow them to count the replacing provides.
367 if (*ptmp->name == '$')
368 warn("System facilities not fully expanded, see %s!\n", dir->name);
369 else if (++deep > MAX_DEEP) {
370 if ((ptmp->flags & DIR_MAXDEEP) == 0)
371 warn("Max recursions depth %d reached\n", MAX_DEEP);
372 ptmp->flags |= DIR_MAXDEEP;
376 ptmp->flags |= DIR_SCAN; /* Mark this service for loop detection */
379 * If there are links in the links included, follow them
381 np_list_for_each(dent, l_list) {
382 dir_t * target = getlink(dent)->target;
383 handle_t * ptrg = (mode == 'K') ? &target->stopp : &target->start;
385 if ((peg->run.lvl & ptrg->run.lvl) == 0)
386 continue; /* Not same boot level */
389 break; /* Loop avoided */
392 break; /* Loop avoided */
394 if (skip && skip == target) {
395 if (!remembernode(pskp) || !remembernode(ptmp))
396 loop_warn_two(pskp, ptmp, act);
398 break; /* Loop detected, stop recursion */
401 if (ptrg->deep >= deep) /* Nothing new */
403 /* The inner recursion */
404 __follow(target, tmp, deep, mode, reportloop);
405 prefetch(dent->next);
407 /* Just for the case an inner recursion was stopped */
408 if (loop_check(ptrg) || loop_check(ptmp) || loop_check(pskp)) {
410 break; /* Loop detected, stop recursion */
414 ptmp->flags &= ~DIR_SCAN; /* Remove loop detection mark */
415 prefetch(l_list->next);
418 if (reportloop && !(ptmp->flags & DIR_LOOPREPORT)) {
419 warn(" loop involving service %s at depth %d\n", tmp->name, level);
420 ptmp->flags |= DIR_LOOPREPORT;
422 break; /* Loop detected, stop recursion */
426 return; /* Make compiler happy */
434 * Helper for follow_all: start with depth one.
436 static inline void follow(dir_t *restrict dir, const char mode, const char reportloop) attribute((always_inline,nonnull(1)));
437 static inline void follow(dir_t *restrict dir, const char mode, const char reportloop)
439 const int deep = (mode == 'K') ? (dir->stopp.mindeep) : (dir->start.mindeep);
440 /* Link depth starts here with one */
441 __follow(dir, (dir_t*)0, deep, mode, reportloop);
445 * Put not existing services into a guessed order.
446 * The maximal order of not existing services can be
447 * set if they are required by existing services.
449 static void guess_order(dir_t *restrict dir, const char mode) attribute((nonnull(1)));
450 static void guess_order(dir_t *restrict dir, const char mode)
452 handle_t * peg = (mode == 'K') ? &dir->stopp : &dir->start;
453 list_t * l_list = &peg->link;
454 register int min = 99;
455 register int deep = 0;
458 if (dir->script) /* Skip it because we have read it */
461 if (*dir->name == '$') { /* Don't touch our system facilities */
462 warn("System facilities not fully expanded, see %s!\n", dir->name);
466 /* No full loop required because we seek for the lowest order */
467 if (!list_empty(l_list)) {
468 dir_t * target = getnextlink(l_list);
469 handle_t * ptrg = (mode == 'K') ? &target->stopp : &target->start;
470 uchar * order = &ptrg->deep;
476 lvl |= ptrg->run.lvl;
478 list_for_each_prev(dent, l_list) {
479 dir_t * tmp = getlink(dent)->target;
480 handle_t * ptmp = (mode == 'K') ? &tmp->stopp : &tmp->start;
481 uchar * order = &ptmp->deep;
483 if (++deep > MAX_DEEP)
487 break; /* Loop detected */
492 lvl |= ptmp->run.lvl;
494 if (min > 1) { /* Set guessed order of this unknown script */
495 uchar * order = &peg->deep;
497 peg->run.lvl |= lvl; /* Set guessed runlevels of this unknown script */
499 peg->run.lvl = LVL_BOOT;
507 * Sort linked list of provides into start or stop order
508 * during this set new start or stop order of the serives.
511 void lsort(const char type)
513 list_t sort = { &sort, &sort };
516 #endif /* SORT_REQUESTS */
521 for (order = 0; order <= maxstop; order++) {
522 list_t * ptr, * safe;
523 list_for_each_safe(ptr, safe, d_start) {
524 dir_t * dir = getdir(ptr);
525 if (dir->stopp.deep == order)
526 move_tail(ptr, &sort);
529 join(&sort, d_start);
531 list_for_each(this, s_start) {
532 service_t * serv = getservice(this);
533 if (serv->attr.flags & SERV_DUPLET)
536 for (order = 0; order <= maxstop; order++) {
537 list_t * ptr, * safe;
538 list_for_each_safe(ptr, safe, &serv->sort.rev) {
539 req_t * rev = getreq(ptr);
540 dir_t * dir = (dir_t*)rev->serv->dir;
541 if (dir->stopp.deep == order)
542 move_tail(ptr, &sort);
545 join(&sort, &serv->sort.rev);
547 #endif /* SORT_REQUESTS */
550 for (order = 0; order <= maxstart; order++) {
551 list_t * ptr, * safe;
552 list_for_each_safe(ptr, safe, d_start) {
553 dir_t * dir = getdir(ptr);
554 if (dir->start.deep == order)
555 move_tail(ptr, &sort);
558 join(&sort, d_start);
560 list_for_each(this, s_start) {
561 service_t * serv = getservice(this);
562 if (serv->attr.flags & SERV_DUPLET)
565 for (order = 0; order <= maxstart; order++) {
566 list_t * ptr, * safe;
567 list_for_each_safe(ptr, safe, &serv->sort.req) {
568 req_t * req = getreq(ptr);
569 dir_t * dir = (dir_t*)req->serv->dir;
570 if (dir->start.deep == order)
571 move_tail(ptr, &sort);
574 join(&sort, &serv->sort.req);
576 #endif /* SORT_REQUESTS */
584 * Clear out aliases of existing services, that is that for *one* script there
585 * exist several provides which could have have been required different by
586 * other services. This avoids doing the same work several times.
588 void nickservice(service_t *restrict orig, service_t *restrict nick)
590 dir_t * dir = (dir_t*)orig->dir;
591 dir_t * cmp = (dir_t*)nick->dir;
592 list_t * dent, * safe;
597 if (cmp->script && cmp->script != dir->script)
600 list_for_each_safe(dent, safe, &cmp->start.link) {
601 link_t * link = getlink(dent);
602 dir_t * target = link->target;
607 ln_sf(target, dir, 'S');
609 /* remove the link from local link list but never free the target */
615 list_for_each_safe(dent, safe, &cmp->stopp.link) {
616 link_t * link = getlink(dent);
617 dir_t * target = link->target;
622 ln_sf(target, dir, 'K');
624 /* remove the link from local link list but never free the target */
630 delete(&cmp->d_list); /* remove alias entry from global service list */
632 /* remember levels of old start handle */
633 dir->start.run.lvl |= cmp->start.run.lvl;
634 dir->start.flags |= cmp->start.flags;
636 /* remember levels of old stop handle */
637 dir->stopp.run.lvl |= cmp->stopp.run.lvl;
638 dir->stopp.flags |= cmp->stopp.flags;
640 /* remember global flags of old provide */
641 orig->attr.flags |= nick->attr.flags;
642 nick->attr.flags |= SERV_DUPLET;
644 if (cmp->script && cmp->script != dir->script) {
645 free(nick->attr.script);
646 nick->attr.script = orig->attr.script;
649 nick->dir = (void*)dir; /* remember main provide */
650 nick->start = &dir->start.run;
651 nick->stopp = &dir->stopp.run;
653 if (--cmp->ref <= 0) free(cmp);
655 list_for_each_safe(dent, safe, &nick->sort.req) {
656 req_t * this = getreq(dent);
659 list_for_each(req, &orig->sort.req) {
660 if (!strcmp(this->serv->name,getreq(req)->serv->name)) {
669 move_tail(dent, &orig->sort.req);
672 list_for_each_safe(dent, safe, &nick->sort.rev) {
673 req_t * this = getreq(dent);
676 list_for_each(rev, &orig->sort.rev) {
677 if (!strcmp(this->serv->name,getreq(rev)->serv->name)) {
686 move_tail(dent, &orig->sort.rev);
695 * Find dangling links in global service list and remove them
696 * if we by detect the remove bit from set above in the flags.
699 list_for_each(this, d_start) {
700 dir_t *dir = getdir(this);
703 list_for_each_safe(dent, hold, &dir->start.link) {
704 link_t * link = getlink(dent);
705 dir_t * target = link->target;
710 if ((attof(target)->flags & SERV_DUPLET) == 0)
713 /* remove the link from local link list */
719 * Do not free allocated strings and structure if in use
720 * never free cmp->attr.script as this remains always in use.
723 if (--target->ref <= 0) free(target);
726 list_for_each_safe(dent, hold, &dir->stopp.link) {
727 link_t * link = getlink(dent);
728 dir_t * target = link->target;
733 if ((attof(target)->flags & SERV_DUPLET) == 0)
736 /* remove the link from local link list */
742 * Do not free allocated strings and structure if in use
743 * never free cmp->attr.script as this remains always in use.
746 if (--target->ref <= 0) free(target);
749 #if defined(DEBUG) && (DEBUG > 0)
750 list_for_each(this, s_start) {
751 service_t * srv = getservice(this);
752 list_t * nxt, * hold;
754 if (srv->attr.flags & SERV_DUPLET)
757 list_for_each_safe(nxt, hold, s_start) {
758 list_t * dent, * safe;
761 orv = getservice(nxt);
763 if ((orv->attr.flags & SERV_DUPLET) == 0)
766 if (srv->dir != orv->dir)
769 srv->attr.flags |= orv->attr.flags;
770 srv->attr.flags &= ~SERV_DUPLET;
772 list_for_each_safe(dent, safe, &orv->sort.req) {
773 req_t * this = getreq(dent);
776 list_for_each(req, &srv->sort.req) {
777 if (!strcmp(this->serv->name,getreq(req)->serv->name)) {
783 fprintf(stderr, "BUG: removed %s from start list of %s, missed getorig()?\n",
784 this->serv->name, orv->name);
788 fprintf(stderr, "BUG: moved %s from start list of %s to %s, missed getorig()?\n",
789 this->serv->name, orv->name, srv->name);
790 move_tail(dent, &srv->sort.req);
794 list_for_each_safe(dent, safe, &orv->sort.rev) {
795 req_t * this = getreq(dent);
798 list_for_each(rev, &srv->sort.rev) {
799 if (!strcmp(this->serv->name,getreq(rev)->serv->name)) {
805 fprintf(stderr, "BUG: removed %s from start list of %s, missed getorig()?\n",
806 this->serv->name, orv->name);
810 fprintf(stderr, "BUG: moved %s from start list of %s to %s, missed getorig()?\n",
811 this->serv->name, orv->name, srv->name);
812 move_tail(dent, &srv->sort.rev);
821 * Follow all services and their dependencies recursivly.
823 void follow_all(void)
828 * Follow all scripts and calculate the main ordering.
830 list_for_each(tmp, d_start) {
831 maxorder = &maxstart;
832 follow(getdir(tmp), 'S', 1);
834 follow(getdir(tmp), 'K', 1);
838 * Guess order of not installed scripts in comparision
839 * to the well known scripts.
841 list_for_each(tmp, d_start) {
842 maxorder = &maxstart;
843 guess_order(getdir(tmp), 'S');
844 maxorder = &maxstart;
845 guess_order(getdir(tmp), 'K');
849 boolean is_loop_detected(void)
852 list_for_each(tmp, d_start) {
853 dir_t * dir = getdir(tmp);
854 if (dir->start.flags & DIR_LOOPREPORT)
856 if (dir->stopp.flags & DIR_LOOPREPORT)
863 * For debuging: show all services
865 #if defined(DEBUG) && (DEBUG > 0)
869 if (maxstop > 0) list_for_each(tmp, d_start) {
870 char * script, *name, *lvlstr;
871 dir_t * dir = getdir(tmp);
881 if (attof(dir)->script)
882 script = attof(dir)->script;
883 else if (*name == '$')
887 lvlstr = lvl2str(lvl);
888 info("K%.2d %s 0x%.2x '%s' (%s)\n", deep, name, lvl, lvlstr, script);
891 if (maxstart > 0) list_for_each(tmp, d_start) {
892 char * script, *name, *lvlstr;
893 dir_t * dir = getdir(tmp);
903 if (attof(dir)->script)
904 script = attof(dir)->script;
905 else if (*name == '$')
909 lvlstr = lvl2str(lvl);
910 info("S%.2d %s 0x%.2x '%s' (%s)\n", deep, name, lvl, lvlstr, script);
917 * Used within loops to get scripts not included in this runlevel
919 boolean notincluded(const char *restrict const script, const char mode, const int runlevel)
923 const ushort lvl = map_runlevel_to_lvl (runlevel);
925 list_for_each_prev(tmp, d_start) {
926 dir_t * dir = getdir(tmp);
927 level_t * run = (mode == 'K') ? &dir->stopp.run : &dir->start.run;
929 if (run->lvl & lvl) /* Same runlevel */
932 if (dir->script == (char*)0) /* No such file */
935 if (strcmp(script, dir->script))
936 continue; /* Not this file */
938 ret = true; /* Not included */
946 * Used within loops to list services an for a given runlevel bit mask.
948 service_t * listscripts(const char **restrict script, const char mode, const ushort lvl)
959 serv = (service_t*)0;
965 attof(dir)->korder = dir->stopp.deep;
966 attof(dir)->sorder = dir->start.deep;
969 *script = serv->attr.script;
973 level = (dir->stopp.run.lvl|dir->start.run.lvl);
976 level = dir->stopp.run.lvl;
979 level = dir->start.run.lvl;
985 } while ((*script == (char*)0) || (level & lvl) == 0);
991 * THIS services DEPENDS on that service befor startup or shutdown.
993 void requires(service_t *restrict this, service_t *restrict dep, const char mode)
995 ln_sf((dir_t*)this->dir, (dir_t*)dep->dir, mode);
999 * Set the runlevels of a service.
1001 void runlevels(service_t *restrict serv, const char mode, const char *restrict lvl)
1003 dir_t * dir = (dir_t *)serv->dir;
1004 handle_t * peg = (mode == 'K') ? &dir->stopp : &dir->start;
1005 peg->run.lvl |= str2lvl(lvl);
1009 * Reorder all services starting with a service
1010 * being in same runlevels.
1012 void setorder(const char *restrict script, const char mode, const int order, const boolean recursive)
1014 dir_t * dir = findscript(script);
1023 maxorder = &maxstop;
1026 maxorder = &maxstart;
1029 if (peg->mindeep < order)
1030 peg->mindeep = order; /* Remember lowest default order deep */
1032 if (peg->deep >= peg->mindeep) /* Nothing to do */
1036 peg->deep = peg->mindeep;
1041 * Follow the script and re-calculate the ordering.
1043 __follow(dir, (dir_t*)0, peg->mindeep, mode, 0);
1046 * Guess order of not installed scripts in comparision
1047 * to the well known scripts.
1049 list_for_each(tmp, d_start)
1050 guess_order(getdir(tmp), mode);
1056 * Get the order of a script.
1058 int getorder(const char *restrict script, const char mode)
1060 dir_t * dir = findscript(script);
1064 handle_t * peg = (mode == 'K') ? &dir->stopp : &dir->start;
1072 * Provide a service if the corresponding script
1073 * was read and the scripts name was remembered.
1074 * A given script name marks a service as a readed one.
1075 * One script and several provided facilities leads
1076 * to the same order for those facilities.
1078 boolean makeprov(service_t *restrict serv, const char *restrict script)
1080 dir_t *restrict alias = findscript(script);
1081 dir_t *restrict dir = (dir_t *restrict)serv->dir;
1087 serv->attr.script = xstrdup(script);
1088 serv->attr.flags |= SERV_SCRIPT;
1089 dir->script = serv->attr.script;
1091 dir->script = alias->script;
1093 list_for_each(ptr, s_start) {
1094 service_t * tmp = getservice(ptr);
1097 if (tmp->dir != serv->dir)
1099 if (tmp->attr.script)
1101 tmp->attr.script = dir->script;
1102 tmp->attr.flags |= SERV_SCRIPT;
1105 } else if (strcmp(dir->script, script))
1112 * Find the script name of a provided feature
1114 const char * getscript(const char *restrict prov)
1116 char * script = (char*)0;
1119 list_for_each(ptr, s_start) {
1120 service_t * this = getservice(ptr);
1121 if (!strcmp(this->name, prov)) {
1122 if (this->attr.script)
1123 script = this->attr.script;
1131 * Return the provided service of a given script
1133 const char * getprovides(const char *restrict script)
1135 const dir_t * dir = findscript(script);
1136 const char * prov = (const char*)0;
1144 * Find a specific service by its name
1146 service_t * findservice(const char *restrict const name)
1149 service_t * ret = (service_t*)0;
1151 if (name == (const char*)0)
1154 list_for_each(ptr, s_start) {
1155 service_t * this = getservice(ptr);
1156 if (!strcmp(this->name, name)) {