4 * Copyright 2000,2008 Werner Fink, 2000 SuSE GmbH Nuernberg, Germany.
5 * 2008 SuSE Linux Products GmbH Nuernberg, Germany
7 * This source is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
14 #include <sys/types.h>
17 typedef enum _boolean {false, true} boolean;
18 typedef unsigned char uchar;
20 typedef unsigned short ushort;
21 typedef unsigned int uint;
25 # warning This will not compile without -O at least
27 #if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
29 # define inline __inline__
32 # define restrict __restrict__
35 # define volatile __volatile__
41 # define extension __extension__
45 # define attribute(attr) __attribute__(attr)
49 * This is lent from the kernel by e.g. using
51 * echo '#include <asm-i386/processor.h>\nint main () { prefetch(); return 0; }' | \
52 * gcc -I/usr/src/linux/include -D__KERNEL__ -x c -E -P - | \
53 * sed -rn '/void[[:blank:]]+prefetch[[:blank:]]*\(/,/^}/p'
55 * on the appropiate architecture (here on i686 for i586).
57 static inline void prefetch(const void *restrict x) attribute((used,always_inline));
58 static inline void prefetch(const void *restrict x)
60 #if defined(__x86_64__)
61 asm volatile ("prefetcht0 %0" :: "m" (*(unsigned long *)x))
62 #elif defined(__ia64__)
63 asm volatile ("lfetch [%0]" :: "r" (x))
64 #elif defined(__powerpc64__)
65 asm volatile ("dcbt 0,%0" :: "r" (x))
66 #elif 1 && defined(__i386__)
67 asm volatile ("661:\n\t"
68 ".byte 0x8d,0x74,0x26,0x00\n"
70 ".section .altinstructions,\"a\"\n"
78 ".section .altinstr_replacement,\"ax\"\n"
83 :: "i" ((0*32+25)), "r" (x))
88 #if defined(DEBUG) && (DEBUG > 0)
89 # define __align attribute((packed))
91 # define __align attribute((aligned(sizeof(struct list_struct*))))
93 #define __packed attribute((packed))
95 #define alignof(type) (sizeof(type)+(sizeof(type)%sizeof(void*)))
96 #define strsize(string) ((strlen(string)+1)*sizeof(char))
98 typedef struct list_struct {
99 struct list_struct * next, * prev;
103 * Linked list handling
104 * ====================
105 * The structures which will be linked into such lists have to be of the
106 * same type. The structures may have alway a list identifier of the type
107 * `list_t' as very first element. With this the macro list_entry() can
108 * be used to cast the memory address of a list member to the corresponding
109 * allocated structure.
113 * Insert new entry as next member.
115 static inline void insert(list_t *restrict new, list_t *restrict here) attribute((always_inline,nonnull(1,2)));
116 static inline void insert(list_t *restrict new, list_t *restrict here)
118 list_t * prev = here;
119 list_t * next = here->next;
130 static inline void initial(list_t *restrict head) attribute((always_inline,nonnull(1)));
131 static inline void initial(list_t *restrict head)
133 head->prev = head->next = head;
137 * Remove entries, note that the pointer its self remains.
139 static inline void delete(list_t *restrict entry) attribute((always_inline,nonnull(1)));
140 static inline void delete(list_t *restrict entry)
142 list_t * prev = entry->prev;
143 list_t * next = entry->next;
151 static inline void join(list_t *restrict list, list_t *restrict head) attribute((always_inline,nonnull(1,2)));
152 static inline void join(list_t *restrict list, list_t *restrict head)
154 list_t * first = list->next;
157 list_t * last = list->prev;
158 list_t * at = head->next;
168 static inline boolean list_empty(list_t *restrict head) attribute((always_inline,nonnull(1)));
169 static inline boolean list_empty(list_t *restrict head)
171 return head->next == head;
174 static inline void move_tail(list_t *restrict entry, list_t *restrict head) attribute((always_inline,nonnull(1,2)));
175 static inline void move_tail(list_t *restrict entry, list_t *restrict head)
177 list_t * prev = entry->prev;
178 list_t * next = entry->next;
180 next->prev = prev; /* remove enty from old list */
186 next->prev = entry; /* and add it at tail of new list */
193 #define list_entry(ptr, type, member) (__extension__ ({ \
194 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
195 ((type *)( (char *)(__mptr) - offsetof(type,member) )); }))
196 #define list_for_each(pos, head) \
197 for (pos = (head)->next; prefetch(pos->next), pos != (head); pos = pos->next)
198 #define np_list_for_each(pos, head) \
199 for (pos = (head)->next; pos != (head); pos = pos->next)
200 #define list_for_each_safe(pos, safe, head) \
201 for (pos = (head)->next, safe = pos->next; pos != (head); pos = safe, safe = pos->next)
202 #define list_for_each_prev(pos, head) \
203 for (pos = (head)->prev; prefetch(pos->prev), pos != (head); pos = pos->prev)
204 #define np_list_for_each_prev(pos, head) \
205 for (pos = (head)->prev; pos != (head); pos = pos->prev)
208 * The runlevel bits within own struct
210 typedef struct level_struct {
217 typedef struct attr_struct {
226 * Linked list of required services (start/stop)
228 typedef struct sort_struct {
233 * Objects of linked list of required services
235 typedef struct service_struct service_t;
236 typedef struct req_serv {
239 service_t *restrict serv;
241 #define getreq(arg) list_entry((arg), struct req_serv, list)
244 * Used by findservice()
246 struct service_struct {
250 level_t *restrict start;
251 level_t *restrict stopp;
255 #define getservice(list) list_entry((list), service_t, s_list)
257 extern list_t * s_start;
261 extern void clear_all(void);
262 extern void nickservice(service_t *restrict orig, service_t *restrict nick) attribute((nonnull(1,2)));
263 extern void follow_all(void);
264 extern void show_all(void);
265 extern void requires(service_t *restrict this, service_t *restrict dep, const char mode) attribute((nonnull(1,2)));
266 extern void runlevels(service_t *restrict serv, const char mode, const char *restrict lvl) attribute((nonnull(1,3)));
267 extern boolean makeprov(service_t *restrict serv, const char *restrict script) attribute((nonnull(1,2)));
268 extern void setorder(const char *restrict script, const char mode, const int order, const boolean recursive) attribute((nonnull(1)));
269 extern int getorder(const char *restrict script, const char mode) attribute((nonnull(1)));
270 extern boolean notincluded(const char *restrict const script, const char mode, const int runlevel) attribute((nonnull(1)));
271 extern const char * getscript(const char *restrict prov) attribute((nonnull(1)));
272 extern const char * getprovides(const char *restrict script) attribute((nonnull(1)));
273 extern service_t * listscripts(const char **restrict script, const char mode, const ushort lvl);
274 extern boolean is_loop_detected(void);
275 extern service_t * addservice(const char *restrict const serv) attribute((malloc,nonnull(1)));
276 extern service_t * findservice(const char *restrict const name);
277 extern service_t * getorig(service_t *restrict serv) attribute((const,nonnull(1)));
278 extern void lsort(const char type);
283 extern const char *const delimeter;
284 extern void error(const char *restrict fmt, ...) attribute((noreturn,format(printf,1,2)));
285 extern void warn (const char *restrict fmt, ...) attribute((format(printf,1,2)));
286 extern void info (const char *restrict fmt, ...) attribute((format(printf,1,2)));
287 extern inline int map_has_runlevels(void) attribute((always_inline));
288 extern inline char map_runlevel_to_key(const int runlevel);
289 extern inline ushort map_key_to_lvl(const char key);
290 extern inline const char *map_runlevel_to_location(const int runlevel);
291 extern inline ushort map_runlevel_to_lvl(const int runlevel);
292 extern inline ushort map_runlevel_to_seek(const int runlevel);
293 extern ushort str2lvl(const char *restrict lvl) attribute((nonnull(1)));
294 extern char * lvl2str(const ushort lvl);
296 static inline char * xstrdup(const char *restrict s) attribute((always_inline,malloc));
297 static inline char * xstrdup(const char *restrict s)
301 error("%s", strerror(EINVAL));
302 if (!(r = strdup(s)))
303 error("%s", strerror(errno));
307 #define xreset(ptr) \
308 {char *restrict tmp = (char *restrict)ptr; if (ptr && *tmp) free(ptr);} ptr = NULL
310 #if defined(HAS_unlinkat) && defined(_ATFILE_SOURCE)
311 # define xremove(d,x) (__extension__ ({ if ((dryrun ? 0 : \
312 (unlinkat(d,x,0) != 0 && (errno != EISDIR || unlinkat(d,x,AT_REMOVEDIR) != 0)))) \
313 warn ("can not remove(%s%s): %s\n", rcd, x, strerror(errno)); \
315 info("remove service %s/%s%s\n", path, rcd, x); }))
317 # define xremove(d,x) (__extension__ ({ if ((dryrun ? 0 : (remove(x) != 0))) \
318 warn ("can not remove(%s%s): %s\n", rcd, x, strerror(errno)); \
320 info("remove service %s/%s%s\n", path, rcd, x); }))
322 #if defined(HAS_symlinkat) && defined(_ATFILE_SOURCE)
323 # define xsymlink(d,x,y) (__extension__ ({ if ((dryrun ? 0 : (symlinkat(x, d, y) != 0))) \
324 warn ("can not symlink(%s, %s%s): %s\n", x, rcd, y, strerror(errno)); \
326 info("enable service %s -> %s/%s%s\n", x, path, rcd, y); }))
328 # define xsymlink(d,x,y) (__extension__ ({ if ((dryrun ? 0 : (symlink(x, y) != 0))) \
329 warn ("can not symlink(%s, %s%s): %s\n", x, rcd, y, strerror(errno)); \
331 info("enable service %s -> %s/%s%s\n", x, path, rcd, y); }))
333 #if defined(HAS_fstatat) && defined(_ATFILE_SOURCE)
334 # define xstat(d,x,s) (__extension__ ({ fstatat(d,x,s, 0); }))
335 # define xlstat(d,x,s) (__extension__ ({ fstatat(d,x,s, AT_SYMLINK_NOFOLLOW); }))
337 # define xstat(d,x,s) (__extension__ ({ stat(x,s); }))
338 # define xlstat(d,x,s) (__extension__ ({ lstat(x,s); }))
340 #if defined(HAS_readlinkat) && defined(_ATFILE_SOURCE)
341 # define xreadlink(d,x,b,l) (__extension__ ({ readlinkat(d,x,b,l); }))
343 # define xreadlink(d,x,b,l) (__extension__ ({ readlink(x,b,l); }))
345 #if defined(HAS_openat) && defined(_ATFILE_SOURCE)
346 # define xopen(d,x,f) (__extension__ ({ openat(d,x,f); }))
348 # define xopen(d,x,f) (__extension__ ({ open(x,f); }))
352 * Bits of the requests
354 #define REQ_MUST 0x0001
355 #define REQ_SHLD 0x0002
356 #define REQ_KILL 0x0004
359 * Bits of the services
361 #define SERV_KNOWN 0x0001
362 #define SERV_NOTLSB 0x0002
363 #define SERV_ALREADY 0x0004
364 #define SERV_INTRACT 0x0008
365 #define SERV_ENABLED 0x0010
366 #define SERV_ALL 0x0020
367 #define SERV_DUPLET 0x0040
368 #define SERV_SCRIPT 0x0080
369 #define SERV_NOSTOP 0x0100
370 #define SERV_CMDLINE 0x0200
373 * Bits of the runlevels
375 #define LVL_HALT 0x0001
376 #define LVL_ONE 0x0002
377 #define LVL_TWO 0x0004
378 #define LVL_THREE 0x0008
379 #define LVL_FOUR 0x0010
380 #define LVL_FIVE 0x0020
381 #define LVL_REBOOT 0x0040
383 # define LVL_SINGLE 0x0080
384 # define LVL_BOOT 0x0100
386 # define LVL_SINGLE 0x0000
387 # define LVL_BOOT 0x0080
391 * LVL_BOOT is already done if one of the LVL_ALL will be entered.
393 #define LVL_ALL (LVL_HALT|LVL_ONE|LVL_TWO|LVL_THREE|LVL_FOUR|LVL_FIVE|LVL_REBOOT|LVL_SINGLE)
396 * Normal runlevels which are _direct_ available by shutdown/reboot/halt
398 #define LVL_NORM (LVL_HALT|LVL_ONE|LVL_TWO|LVL_THREE|LVL_FOUR|LVL_FIVE|LVL_REBOOT)
401 * Oneway runlevels at shutdown/reboot/halt/single
403 #define LVL_ONEWAY (LVL_HALT|LVL_ONE|LVL_REBOOT|LVL_SINGLE)
405 * Maximum start/stop level