Git init
[external/insserv.git] / listing.h
1 /*
2  * listing.h
3  *
4  * Copyright 2000,2008 Werner Fink, 2000 SuSE GmbH Nuernberg, Germany.
5  *                                  2008 SuSE Linux Products GmbH Nuernberg, Germany
6  *
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.
11  */
12
13 #include <stddef.h>
14 #include <sys/types.h>
15 #include "config.h"
16
17 typedef enum _boolean {false, true} boolean;
18 typedef unsigned char uchar;
19 #ifndef __USE_MISC
20 typedef unsigned short ushort;
21 typedef unsigned int uint;
22 #endif
23
24 #ifndef __OPTIMIZE__
25 # warning This will not compile without -O at least
26 #endif
27 #if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
28 # ifndef  inline
29 #  define inline                __inline__
30 # endif
31 # ifndef  restrict
32 #  define restrict              __restrict__
33 # endif
34 # ifndef  volatile
35 #  define volatile              __volatile__
36 # endif
37 # ifndef  asm
38 #  define asm                   __asm__
39 # endif
40 # ifndef  extension
41 #  define extension             __extension__
42 # endif
43 #endif
44 #ifndef  attribute
45 # define attribute(attr)        __attribute__(attr)
46 #endif
47
48 /*
49  * This is lent from the kernel by e.g. using
50  *
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'
54  *
55  * on the appropiate architecture (here on i686 for i586).
56  */
57 static inline void prefetch(const void *restrict x) attribute((used,always_inline));
58 static inline void prefetch(const void *restrict x)
59 {
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"
69                   "\n662:\n"
70                   ".section .altinstructions,\"a\"\n"
71                   "  .align 4\n"
72                   "  .long 661b\n"
73                   "  .long 663f\n"
74                   "  .byte %c0\n"
75                   "  .byte 662b-661b\n"
76                   "  .byte 664f-663f\n"
77                   ".previous\n"
78                   ".section .altinstr_replacement,\"ax\"\n"
79                   "   663:\n\t"
80                   "   prefetchnta (%1)"
81                   "   \n664:\n"
82                   ".previous"
83                   :: "i" ((0*32+25)), "r" (x))
84 #endif
85     ;
86 }
87
88 #if defined(DEBUG) && (DEBUG > 0)
89 # define __align attribute((packed))
90 #else
91 # define __align attribute((aligned(sizeof(struct list_struct*))))
92 #endif
93 #define __packed attribute((packed))
94
95 #define alignof(type)           (sizeof(type)+(sizeof(type)%sizeof(void*)))
96 #define strsize(string)         ((strlen(string)+1)*sizeof(char))
97
98 typedef struct list_struct {
99     struct list_struct * next, * prev;
100 } __align list_t;
101
102 /*
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.
110  */
111
112 /*
113  * Insert new entry as next member.
114  */
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)
117 {
118     list_t * prev = here;
119     list_t * next = here->next;
120
121     next->prev = new;
122     new->next = next;
123     new->prev = prev;
124     prev->next = new;
125 }
126
127 /*
128  * Set head
129  */
130 static inline void initial(list_t *restrict head) attribute((always_inline,nonnull(1)));
131 static inline void initial(list_t *restrict head)
132 {
133     head->prev = head->next = head;
134 }
135
136 /*
137  * Remove entries, note that the pointer its self remains.
138  */
139 static inline void delete(list_t *restrict entry) attribute((always_inline,nonnull(1)));
140 static inline void delete(list_t *restrict entry)
141 {
142     list_t * prev = entry->prev;
143     list_t * next = entry->next;
144
145     next->prev = prev;
146     prev->next = next;
147
148     initial(entry);
149 }
150
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)
153 {
154     list_t * first = list->next;
155
156     if (first != list) {
157         list_t * last = list->prev;
158         list_t * at = head->next;
159
160         first->prev = head;
161         head->next = first;
162
163         last->next = at;
164         at->prev = last;
165     }
166 }
167
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)
170 {
171      return head->next == head;
172 }
173
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)
176 {
177     list_t * prev = entry->prev;
178     list_t * next = entry->next;
179
180     next->prev = prev;          /* remove enty from old list */
181     prev->next = next;
182
183     prev = head->prev;
184     next = head;
185
186     next->prev = entry;         /* and add it at tail of new list */
187     entry->next = next;
188     entry->prev = prev;
189     prev->next = entry;
190 }
191
192
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)
206
207 /*
208  * The runlevel bits within own struct
209  */
210 typedef struct level_struct {
211     ushort                  lvl;
212 } __packed level_t;
213
214 /*
215  * Common attributes
216  */
217 typedef struct attr_struct {
218     ushort                flags;
219     short                   ref;
220     uchar                sorder;
221     uchar                korder;
222     char                *script;
223 } __packed attr_t;
224
225 /*
226  * Linked list of required services (start/stop)
227  */
228 typedef struct sort_struct {
229     list_t             req, rev;
230 } __align sort_t;
231
232 /*
233  * Objects of linked list of required services
234  */
235 typedef struct service_struct service_t;
236 typedef struct req_serv {
237     list_t                 list;
238     ushort                flags;
239     service_t    *restrict serv;
240 } __align req_t;
241 #define getreq(arg)     list_entry((arg), struct req_serv, list)
242
243 /*
244  * Used by findservice()
245  */
246 struct service_struct {
247     list_t               s_list;
248     sort_t                 sort;
249     void        *restrict   dir;
250     level_t     *restrict start;
251     level_t     *restrict stopp;
252     attr_t                 attr;
253     char                 * name;
254 } __align;
255 #define getservice(list)        list_entry((list), service_t, s_list)
256
257 extern list_t * s_start;
258 extern int maxstart;
259 extern int maxstop;
260
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);
279
280 /*
281  * Common short cuts
282  */
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);
295
296 static inline char * xstrdup(const char *restrict s) attribute((always_inline,malloc));
297 static inline char * xstrdup(const char *restrict s)
298 {
299     char * r;
300     if (!s)
301         error("%s", strerror(EINVAL));
302     if (!(r = strdup(s)))
303         error("%s", strerror(errno));
304     return r;
305
306
307 #define xreset(ptr)     \
308         {char *restrict tmp = (char *restrict)ptr; if (ptr && *tmp) free(ptr);} ptr = NULL
309
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)); \
314         else \
315         info("remove service %s/%s%s\n", path, rcd, x); }))
316 #else
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)); \
319         else \
320         info("remove service %s/%s%s\n", path, rcd, x); }))
321 #endif
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)); \
325         else \
326         info("enable service %s -> %s/%s%s\n", x, path, rcd, y); }))
327 #else
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)); \
330         else \
331         info("enable service %s -> %s/%s%s\n", x, path, rcd, y); }))
332 #endif
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); }))
336 #else
337 # define xstat(d,x,s)   (__extension__ ({ stat(x,s); }))
338 # define xlstat(d,x,s)  (__extension__ ({ lstat(x,s); }))
339 #endif
340 #if defined(HAS_readlinkat) && defined(_ATFILE_SOURCE)
341 # define xreadlink(d,x,b,l)     (__extension__ ({ readlinkat(d,x,b,l); }))
342 #else
343 # define xreadlink(d,x,b,l)     (__extension__ ({ readlink(x,b,l); }))
344 #endif
345 #if defined(HAS_openat) && defined(_ATFILE_SOURCE)
346 # define xopen(d,x,f)   (__extension__ ({ openat(d,x,f); }))
347 #else
348 # define xopen(d,x,f)   (__extension__ ({ open(x,f); }))
349 #endif
350
351 /*
352  * Bits of the requests
353  */
354 #define REQ_MUST        0x0001
355 #define REQ_SHLD        0x0002
356 #define REQ_KILL        0x0004
357
358 /*
359  * Bits of the services
360  */
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
371
372 /*
373  * Bits of the runlevels
374  */
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
382 #ifdef SUSE
383 # define LVL_SINGLE     0x0080
384 # define LVL_BOOT       0x0100
385 #else
386 # define LVL_SINGLE     0x0000
387 # define LVL_BOOT       0x0080
388 #endif
389
390 /*
391  * LVL_BOOT is already done if one of the LVL_ALL will be entered.
392  */
393 #define LVL_ALL         (LVL_HALT|LVL_ONE|LVL_TWO|LVL_THREE|LVL_FOUR|LVL_FIVE|LVL_REBOOT|LVL_SINGLE)
394
395 /*
396  * Normal runlevels which are _direct_ available by shutdown/reboot/halt
397  */
398 #define LVL_NORM        (LVL_HALT|LVL_ONE|LVL_TWO|LVL_THREE|LVL_FOUR|LVL_FIVE|LVL_REBOOT)
399
400 /*
401  * Oneway runlevels at shutdown/reboot/halt/single
402  */
403 #define LVL_ONEWAY      (LVL_HALT|LVL_ONE|LVL_REBOOT|LVL_SINGLE)
404 /*
405  * Maximum start/stop level
406  */
407 #define MAX_DEEP 99