blob: eafc3f6c2f3409eba1dcb6797cbb08ed4bd667c5 [file] [log] [blame]
James Hunteec19232011-06-01 12:13:42 +01001/* upstart
2 *
3 * Copyright © 2011 Canonical Ltd.
4 * Author: James Hunt <james.hunt@canonical.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#ifndef INITCTL_H
21#define INITCTL_H
22
23/**
24 * IS_OP_AND:
25 * @token: string token to check.
26 *
27 * Return TRUE if @token is an 'AND' operator, else FALSE.
28 **/
29#define IS_OP_AND(token) \
30 (! strcmp ((token), "/AND"))
31
32/**
33 * IS_OP_OR:
34 * @token: string token to check.
35 *
36 * Return TRUE if @token is an 'OR' operator, else FALSE.
37 **/
38#define IS_OP_OR(token) \
39 (! strcmp ((token), "/OR"))
40
41/**
42 * IS_OPERATOR
43 * @token: string token to check.
44 *
45 * Return TRUE if @token is either an 'AND' or an 'OR' operator,
46 * else FALSE.
47 **/
48#define IS_OPERATOR(token) \
49 IS_OP_AND (token) || IS_OP_OR (token)
50
51
52/**
53 * GET_JOB_NAME:
54 *
55 * @var: char pointer variable which will be set to the name
56 * of a job, or NULL,
57 * @index: zero-based index of tokens where zero represents
58 * the first token after the initial token,
59 * @token: string to check.
60 *
61 * Determine name of job considering the specified token and its
62 * index. If not a job, sets @name to NULL.
63 *
64 * Handles the following cases:
65 *
66 * [start|stop] on <job_event> foo
67 * (index==0, job="foo" => name="foo")
68 *
69 * [start|stop] on <job_event> JOB=foo
70 * (index==0, job="JOB=foo" => name="foo")
71 *
72 * [start|stop] on <job_event> A=B JOB=foo
73 * (index==1, job="JOB=foo" => name="foo")
74 *
75 * [start|stop] on <job_event> A=B c=hello JOB=foo
76 * (index==2, job="JOB=foo" => name="foo")
77 *
78 * [start|stop] on <job_event> $JOB A=B c=hello
79 * (index==0, job="$JOB" => name="$JOB")
80 *
81 **/
82#define GET_JOB_NAME(var, index, token) \
83{ \
84 char *_##var; \
85 \
86 nih_assert (index >= 0); \
87 nih_assert (token); \
88 \
89 var = NULL; \
90 \
91 _##var = strstr (token, "JOB="); \
92 \
93 if (_##var && _##var == token) \
94 var = _##var + strlen ("JOB="); \
95 else if (index == 0 ) { \
96 if (!strstr (token, "=")) \
97 var = token; \
98 } \
99}
100
101
102/**
103 * IS_JOB_EVENT:
104 * @token: string to check.
105 *
106 * Return TRUE if specified token refers to a standard job event, else
107 * FALSE.
108 **/
109#define IS_JOB_EVENT(token) \
110 (!strcmp (token, JOB_STARTING_EVENT) || \
111 !strcmp (token, JOB_STARTED_EVENT) || \
112 !strcmp (token, JOB_STOPPING_EVENT) || \
113 !strcmp (token, JOB_STOPPED_EVENT))
114
115/**
116 * IS_INIT_EVENT:
117 * @token: string to check.
118 *
119 * Return TRUE if specified token refers to an event emitted internally,
120 * else FALSE.
121 *
122 * Note: the raw string entries below are required to accommodate
123 * production versus debug builds (STARTUP_EVENT changes name depending
124 * on build type).
125 **/
126#define IS_INIT_EVENT(token) \
127 (!strcmp (token, STARTUP_EVENT) || \
128 !strcmp (token, "debug") || \
129 !strcmp (token, "startup") || \
130 !strcmp (token, CTRLALTDEL_EVENT) || \
131 !strcmp (token, KBDREQUEST_EVENT) || \
132 !strcmp (token, PWRSTATUS_EVENT) || \
133 IS_JOB_EVENT (token))
134
135/**
136 * STACK_EMPTY:
137 * @stack: address of stack to check.
138 *
139 * Return TRUE if @stack is empty, else FALSE.
140 **/
141#define STACK_EMPTY(stack) \
142 (NIH_LIST_EMPTY (stack))
143
144/**
145 * STACK_CREATE:
146 * @name: nih_list variable to assign stack to.
147 **/
148#define STACK_CREATE(name) \
149 name = NIH_MUST (nih_list_new (NULL))
150/**
151 * STACK_SHOW_POP:
152 * @stack: Address of stack,
153 * @str: string representing element popped off stack.
154 *
155 * Display message to denote that @str has been popped off @stack.
156 * Does nothing if debug build not enabled.
157 *
158 * Note: we cannot assert that stack is not empty since a caller may
159 * have just removed the last entry before calling us. Thus, it is up to
160 * the caller to perform such checks.
161 *
162 * Does nothing if debug build not enabled.
163 **/
164#ifdef DEBUG_STACK
165#define STACK_SHOW_POP(stack, str) \
166 STACK_SHOW_CHANGE (stack, "popped", str)
167#else
168#define STACK_SHOW_POP(stack, str)
169#endif
170
171/**
172 * STACK_SHOW_PUSH:
173 * @stack: Address of stack,
174 * @str: string representing element pushed onto stack.
175 *
176 * Display message to denote that @str has been pushed onto @stack.
177 *
178 * Does nothing if debug build not enabled.
179 **/
180#ifdef DEBUG_STACK
181#define STACK_SHOW_PUSH(stack, str) \
182 STACK_SHOW_CHANGE (stack, "pushed", str) \
183 \
184 nih_assert (! STACK_EMPTY (stack))
185#else
186#define STACK_SHOW_PUSH(stack, str)
187#endif
188
189/**
190 * STACK_SHOW:
191 * @stack: Address of stack.
192 *
193 * Display contents of @stack.
194 *
195 * Does nothing if debug build not enabled.
196 **/
197#ifdef DEBUG_STACK
198#define STACK_SHOW(stack) \
199{ \
200 size_t depth = 0; \
201 \
202 nih_assert (stack); \
203 \
204 NIH_LIST_FOREACH (stack, iter) { \
205 depth++; \
206 } \
207 \
208 if (STACK_EMPTY (stack)) { \
209 nih_message ("STACK@%p: empty", stack); \
210 } else { \
211 for (NihList *iter = (stack)->next; \
212 iter != (stack) && \
213 ((NihListEntry *)iter)->str; \
214 iter = iter->next, depth--) { \
215 nih_message ("STACK@%p[%u]='%s'", \
216 (void *)stack, \
217 (unsigned int)(depth-1), \
218 ((NihListEntry *)iter)->str); \
219 } \
220 } \
221}
222#else
223#define STACK_SHOW(stack)
224#endif
225
226/**
227 * STACK_SHOW_CHANGE:
228 * @stack: Address of stack,
229 * @msg: message to show a stack change,
230 * @element_str: string representing element changed on @stack.
231 *
232 * Display a message showing that the stack has been changed.
233 *
234 * Does nothing if debug build not enabled.
235 **/
236#ifdef DEBUG_STACK
237#define STACK_SHOW_CHANGE(stack, msg, element_str) \
238 nih_assert (msg); \
239 nih_assert (element_str); \
240 \
241 nih_message ("STACK@%p: %s '%s'", \
242 (void *)stack, msg, element_str); \
243 \
244 STACK_SHOW (stack); \
245 \
246 nih_message (" "); /* spacer */
247#else
248#define STACK_SHOW_CHANGE(stack, msg, element_str)
249#endif
250
251/**
252 * STACK_PUSH:
253 * @stack: Address of stack,
254 * @elem: element of type NihListEntry to add to stack.
255 *
256 * Add @elem to @stack and display message showing how stack changed.
257 **/
258#define STACK_PUSH(stack, elem) \
259 nih_list_add_after (stack, &(elem)->entry); \
260 \
261 STACK_SHOW_PUSH (stack, \
262 ((NihListEntry *)(elem))->str); \
263 \
264 nih_assert (! STACK_EMPTY (stack))
265
266/**
267 * STACK_PUSH_NEW_ELEM:
268 * @stack: Address of stack,
269 * @string: String to convert into a new NihListEntry
270 * stack element and push onto @stack.
271 *
272 * Create new stack element from @string and push onto @stack,
273 * displaying a message showing how stack changed.
274 **/
275#define STACK_PUSH_NEW_ELEM(stack, string) \
276{ \
277 NihListEntry *e; \
278 \
279 nih_assert (stack); \
280 nih_assert (string); \
281 \
282 e = NIH_MUST (nih_new (stack, NihListEntry)); \
283 nih_list_init (&e->entry); \
284 e->str = NIH_MUST (nih_strdup (e, string)); \
285 STACK_PUSH (stack, e); \
286}
287
288/**
289 * STACK_POP:
290 * @stack: Address of stack,
291 * @list: list which top stack element will be added to.
292 *
293 * Remove top element from @stack, returning to caller as @list
294 * and display message showing how stack changed.
295 *
296 * Note that @list is assumed to have had nih_list_new() called
297 * on it already.
298 **/
299#define STACK_POP(stack, list) \
300 nih_assert (stack); \
301 nih_assert ((stack)->next); \
302 \
303 list = nih_list_add (list, (stack)->next); \
304 STACK_SHOW_POP (stack, \
305 ((NihListEntry *)(list))->str)
306
307/**
308 * STACK_PEEK:
309 * @stack: Address of stack.
310 *
311 * Return string value of top element on stack.
312 **/
313#define STACK_PEEK(stack) \
314 (((NihListEntry *)(stack)->next)->str)
315
316/**
317 * ConditionHandlerData:
318 *
319 * @condition_name: "start on" or "stop on",
320 * @job_class_name: name of *.conf file less the extension.
321 *
322 * Used to pass multiple values to job_class_get_start_on() /
323 * job_class_get_stop_on() handlers.
324 *
325 **/
326typedef struct condition_handler_data {
327 const char *condition_name;
328 const char *job_class_name;
329} ConditionHandlerData;
330#endif /* INITCTL_H */