blob: f68e6bf78a860a3b31c8811e32b6a83fc06d65bf [file] [log] [blame]
Scott James Remnant07336532008-04-29 19:45:51 +01001/* upstart
2 *
3 * job_class.c - job class definition handling
4 *
Scott James Remnant91da63a2011-08-11 13:47:00 -07005 * Copyright © 2011 Canonical Ltd.
Scott James Remnant7d5b2ea2009-05-22 15:20:12 +02006 * Author: Scott James Remnant <scott@netsplit.com>.
Scott James Remnant07336532008-04-29 19:45:51 +01007 *
Scott James Remnant0c0c5a52009-06-23 10:29:35 +01008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2, as
Scott James Remnant75123022009-05-22 13:27:56 +020010 * published by the Free Software Foundation.
Scott James Remnant07336532008-04-29 19:45:51 +010011 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
Scott James Remnant0c0c5a52009-06-23 10:29:35 +010017 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Scott James Remnant07336532008-04-29 19:45:51 +010020 */
21
22#ifdef HAVE_CONFIG_H
23# include <config.h>
24#endif /* HAVE_CONFIG_H */
25
26
Scott James Remnant94d75a12008-06-08 04:08:56 +010027#include <errno.h>
Scott James Remnant07336532008-04-29 19:45:51 +010028#include <string.h>
Marc A. Dahlhaus48ea1fe2011-05-05 11:04:21 +020029#include <signal.h>
Scott James Remnant07336532008-04-29 19:45:51 +010030
31#include <nih/macros.h>
32#include <nih/alloc.h>
33#include <nih/string.h>
34#include <nih/list.h>
35#include <nih/hash.h>
Scott James Remnantda28a632010-12-10 02:43:11 +000036#include <nih/tree.h>
Scott James Remnant07336532008-04-29 19:45:51 +010037#include <nih/logging.h>
38
Scott James Remnant8269cac2009-01-28 01:31:02 +000039#include <nih-dbus/dbus_error.h>
40#include <nih-dbus/dbus_message.h>
41#include <nih-dbus/dbus_object.h>
42#include <nih-dbus/dbus_util.h>
Scott James Remnant0464dc12008-05-08 19:21:54 +010043
Scott James Remnant02606132009-07-02 18:31:25 +010044#include "dbus/upstart.h"
45
Scott James Remnant07336532008-04-29 19:45:51 +010046#include "environ.h"
47#include "process.h"
Scott James Remnantf2f69d02008-04-29 23:38:23 +010048#include "job_class.h"
Scott James Remnant0464dc12008-05-08 19:21:54 +010049#include "job.h"
Scott James Remnant6f02f542008-04-29 23:59:12 +010050#include "event_operator.h"
Scott James Remnant3fb48382008-06-08 02:03:40 +010051#include "blocked.h"
Scott James Remnant07336532008-04-29 19:45:51 +010052#include "conf.h"
53#include "control.h"
54
Scott James Remnant01735c02008-06-05 00:38:56 +010055#include "com.ubuntu.Upstart.h"
Scott James Remnant8877f442008-05-08 23:30:40 +010056#include "com.ubuntu.Upstart.Job.h"
57
Scott James Remnant07336532008-04-29 19:45:51 +010058
Scott James Remnant0464dc12008-05-08 19:21:54 +010059/* Prototypes for static functions */
Scott James Remnant9a7282e2008-05-16 00:04:52 +020060static void job_class_add (JobClass *class);
61static int job_class_remove (JobClass *class);
Scott James Remnant0464dc12008-05-08 19:21:54 +010062
63
Scott James Remnant07336532008-04-29 19:45:51 +010064/**
65 * job_classes:
66 *
67 * This hash table holds the list of known job classes indexed by their name.
68 * Each entry is a JobClass structure; multiple entries with the same name
69 * are not permitted.
70 **/
71NihHash *job_classes = NULL;
72
73
74/**
75 * job_class_init:
76 *
77 * Initialise the job classes hash table.
78 **/
79void
80job_class_init (void)
81{
82 if (! job_classes)
Scott James Remnant56954112009-02-20 22:18:57 +000083 job_classes = NIH_MUST (nih_hash_string_new (NULL, 0));
Scott James Remnant07336532008-04-29 19:45:51 +010084}
85
86
87/**
88 * job_class_new:
Scott James Remnant041e7cd2009-01-28 03:41:47 +000089 * @parent: parent for new job class,
Scott James Remnant07336532008-04-29 19:45:51 +010090 * @name: name of new job class.
91 *
92 * Allocates and returns a new JobClass structure with the @name given.
93 * It will not be automatically added to the job classes table, it is up
94 * to the caller to ensure this is done using job_class_register() once
95 * the class has been set up.
96 *
Scott James Remnant041e7cd2009-01-28 03:41:47 +000097 * If @parent is not NULL, it should be a pointer to another object which
98 * will be used as a parent for the returned job class. When all parents
99 * of the returned job class are freed, the returned job class will also be
100 * freed.
Scott James Remnant07336532008-04-29 19:45:51 +0100101 *
102 * Returns: newly allocated JobClass structure or NULL if insufficient memory.
103 **/
104JobClass *
105job_class_new (const void *parent,
106 const char *name)
107{
108 JobClass *class;
109 int i;
110
111 nih_assert (name != NULL);
112 nih_assert (strlen (name) > 0);
113
114 class = nih_new (parent, JobClass);
115 if (! class)
116 return NULL;
117
118 nih_list_init (&class->entry);
119
Scott James Remnant750c0b12009-01-29 02:24:21 +0000120 nih_alloc_set_destructor (class, nih_list_destroy);
Scott James Remnant07336532008-04-29 19:45:51 +0100121
122 class->name = nih_strdup (class, name);
123 if (! class->name)
124 goto error;
125
Scott James Remnant02606132009-07-02 18:31:25 +0100126 class->path = nih_dbus_path (class, DBUS_PATH_UPSTART, "jobs",
Scott James Remnant07336532008-04-29 19:45:51 +0100127 class->name, NULL);
128 if (! class->path)
129 goto error;
130
Scott James Remnant27d71f12008-05-09 02:35:26 +0100131 class->instance = nih_strdup (class, "");
132 if (! class->instance)
133 goto error;
134
Scott James Remnant6fa0b492008-05-09 02:58:41 +0100135 class->instances = nih_hash_string_new (class, 0);
136 if (! class->instances)
137 goto error;
Scott James Remnant07336532008-04-29 19:45:51 +0100138
139 class->description = NULL;
140 class->author = NULL;
141 class->version = NULL;
142
143 class->env = NULL;
144 class->export = NULL;
Mattias Nissler90b71b62018-03-12 16:41:26 +0100145 class->import = NULL;
Scott James Remnant07336532008-04-29 19:45:51 +0100146
147 class->start_on = NULL;
148 class->stop_on = NULL;
149 class->emits = NULL;
150
151 class->process = nih_alloc (class, sizeof (Process *) * PROCESS_LAST);
152 if (! class->process)
153 goto error;
154
155 for (i = 0; i < PROCESS_LAST; i++)
156 class->process[i] = NULL;
157
158 class->expect = EXPECT_NONE;
159 class->task = FALSE;
160
161 class->kill_timeout = JOB_DEFAULT_KILL_TIMEOUT;
Marc A. Dahlhaus48ea1fe2011-05-05 11:04:21 +0200162 class->kill_signal = SIGTERM;
Scott James Remnant07336532008-04-29 19:45:51 +0100163
164 class->respawn = FALSE;
165 class->respawn_limit = JOB_DEFAULT_RESPAWN_LIMIT;
166 class->respawn_interval = JOB_DEFAULT_RESPAWN_INTERVAL;
167
168 class->normalexit = NULL;
169 class->normalexit_len = 0;
170
Scott James Remnant07336532008-04-29 19:45:51 +0100171 class->console = CONSOLE_NONE;
172
173 class->umask = JOB_DEFAULT_UMASK;
Scott James Remnantc4371b32011-08-10 17:57:42 -0700174 class->nice = JOB_DEFAULT_NICE;
175 class->oom_score_adj = JOB_DEFAULT_OOM_SCORE_ADJ;
Scott James Remnant07336532008-04-29 19:45:51 +0100176
177 for (i = 0; i < RLIMIT_NLIMITS; i++)
178 class->limits[i] = NULL;
179
180 class->chroot = NULL;
181 class->chdir = NULL;
182
183 class->deleted = FALSE;
James Hunt4c626b72011-06-06 13:52:08 +0100184 class->debug = FALSE;
Scott James Remnant07336532008-04-29 19:45:51 +0100185
186 return class;
187
188error:
189 nih_free (class);
190 return NULL;
191}
192
193
194/**
195 * job_class_consider:
196 * @class: job class to consider.
197 *
198 * Considers adding @class to the job classes hash table as the best
199 * available class, if there is no existing class with the name or the
200 * existing class can be replaced.
201 *
202 * Returns: TRUE if @class is now the registered class, FALSE otherwise.
203 **/
204int
205job_class_consider (JobClass *class)
206{
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200207 JobClass *registered, *best;
Scott James Remnant07336532008-04-29 19:45:51 +0100208
209 nih_assert (class != NULL);
210
211 job_class_init ();
212
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200213 best = conf_select_job (class->name);
214 nih_assert (best != NULL);
215
Scott James Remnant07336532008-04-29 19:45:51 +0100216 registered = (JobClass *)nih_hash_lookup (job_classes, class->name);
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200217 if (registered != best) {
218 if (registered)
219 if (! job_class_remove (registered))
220 return FALSE;
Scott James Remnant07336532008-04-29 19:45:51 +0100221
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200222 job_class_add (best);
223 }
Scott James Remnant07336532008-04-29 19:45:51 +0100224
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200225 return (class == best ? TRUE : FALSE);
Scott James Remnant07336532008-04-29 19:45:51 +0100226}
227
228/**
229 * job_class_reconsider:
230 * @class: job class to reconsider.
231 *
232 * Reconsiders whether @class should be the best available class in the
233 * job classes hash table, if it is the existing class and can be
234 * replaced by a better then it will be.
235 *
236 * Note that the best class may be itself unless you have first removed
237 * @class from any configuration sources before calling.
238 *
239 * Returns: FALSE if @class is still the hash table member, TRUE otherwise.
240 **/
241int
242job_class_reconsider (JobClass *class)
243{
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200244 JobClass *registered, *best;
Scott James Remnant07336532008-04-29 19:45:51 +0100245
246 nih_assert (class != NULL);
247
248 job_class_init ();
249
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200250 best = conf_select_job (class->name);
251
Scott James Remnant07336532008-04-29 19:45:51 +0100252 registered = (JobClass *)nih_hash_lookup (job_classes, class->name);
253 if (registered == class) {
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200254 if (class != best) {
255 if (! job_class_remove (class))
256 return FALSE;
257
258 job_class_add (best);
259
260 return TRUE;
261 } else {
Scott James Remnant07336532008-04-29 19:45:51 +0100262 return FALSE;
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200263 }
Scott James Remnant07336532008-04-29 19:45:51 +0100264 }
265
266 return TRUE;
267}
268
Scott James Remnant0464dc12008-05-08 19:21:54 +0100269/**
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200270 * job_class_add:
271 * @class: new class to select.
Scott James Remnant0464dc12008-05-08 19:21:54 +0100272 *
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200273 * Adds @class to the hash table and registers it with all current D-Bus
274 * connections. @class may be NULL.
Scott James Remnant0464dc12008-05-08 19:21:54 +0100275 **/
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200276static void
277job_class_add (JobClass *class)
Scott James Remnant0464dc12008-05-08 19:21:54 +0100278{
Scott James Remnant0464dc12008-05-08 19:21:54 +0100279 control_init ();
280
Scott James Remnant0464dc12008-05-08 19:21:54 +0100281 if (! class)
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200282 return;
Scott James Remnant0464dc12008-05-08 19:21:54 +0100283
284 nih_hash_add (job_classes, &class->entry);
285
286 NIH_LIST_FOREACH (control_conns, iter) {
287 NihListEntry *entry = (NihListEntry *)iter;
288 DBusConnection *conn = (DBusConnection *)entry->data;
289
Scott James Remnant01735c02008-06-05 00:38:56 +0100290 job_class_register (class, conn, TRUE);
Scott James Remnant0464dc12008-05-08 19:21:54 +0100291 }
Scott James Remnant0464dc12008-05-08 19:21:54 +0100292}
293
294/**
295 * job_class_remove:
296 * @class: class to remove.
297 *
298 * Removes @class from the hash table and unregisters it from all current
299 * D-Bus connections.
300 *
301 * Returns: TRUE if class could be unregistered, FALSE if there are
302 * active instances that prevent unregistration.
303 **/
304static int
305job_class_remove (JobClass *class)
306{
307 nih_assert (class != NULL);
308
309 control_init ();
310
Scott James Remnant6fa0b492008-05-09 02:58:41 +0100311 /* Return if we have any active instances */
312 NIH_HASH_FOREACH (class->instances, iter)
Scott James Remnant0464dc12008-05-08 19:21:54 +0100313 return FALSE;
314
315 nih_list_remove (&class->entry);
316
317 NIH_LIST_FOREACH (control_conns, iter) {
318 NihListEntry *entry = (NihListEntry *)iter;
319 DBusConnection *conn = (DBusConnection *)entry->data;
320
321 job_class_unregister (class, conn);
322 }
323
324 return TRUE;
325}
326
327/**
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200328 * job_class_register:
329 * @class: class to register,
Scott James Remnant01735c02008-06-05 00:38:56 +0100330 * @conn: connection to register for
331 * @signal: emit the JobAdded signal.
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200332 *
333 * Register the job @class with the D-Bus connection @conn, using the
334 * path set when the class was created. Since multiple classes with the
335 * same name may exist, this should only ever be called with the current
336 * class of that name, and job_class_unregister() should be used before
337 * registering a new one with the same name.
338 **/
339void
340job_class_register (JobClass *class,
Scott James Remnant01735c02008-06-05 00:38:56 +0100341 DBusConnection *conn,
342 int signal)
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200343{
344 nih_assert (class != NULL);
345 nih_assert (conn != NULL);
346
347 NIH_MUST (nih_dbus_object_new (class, conn, class->path,
348 job_class_interfaces, class));
349
350 nih_debug ("Registered job %s", class->path);
351
Scott James Remnant01735c02008-06-05 00:38:56 +0100352 if (signal)
Scott James Remnant02606132009-07-02 18:31:25 +0100353 NIH_ZERO (control_emit_job_added (conn, DBUS_PATH_UPSTART,
354 class->path));
Scott James Remnant01735c02008-06-05 00:38:56 +0100355
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200356 NIH_HASH_FOREACH (class->instances, iter) {
357 Job *job = (Job *)iter;
358
Scott James Remnant01735c02008-06-05 00:38:56 +0100359 job_register (job, conn, signal);
Scott James Remnant9a7282e2008-05-16 00:04:52 +0200360 }
361}
362
363/**
Scott James Remnant0464dc12008-05-08 19:21:54 +0100364 * job_class_unregister:
365 * @class: class to unregistered,
366 * @conn: connection to unregister from.
367 *
368 * Unregister the job @class from the D-Bus connection @conn, which must
369 * have already been registered with job_class_register().
370 **/
371void
372job_class_unregister (JobClass *class,
373 DBusConnection *conn)
374{
375 nih_assert (class != NULL);
376 nih_assert (conn != NULL);
Scott James Remnant6fa0b492008-05-09 02:58:41 +0100377 NIH_HASH_FOREACH (class->instances, iter)
378 nih_assert_not_reached ();
Scott James Remnant0464dc12008-05-08 19:21:54 +0100379
380 NIH_MUST (dbus_connection_unregister_object_path (conn, class->path));
381
382 nih_debug ("Unregistered job %s", class->path);
Scott James Remnant01735c02008-06-05 00:38:56 +0100383
Scott James Remnant02606132009-07-02 18:31:25 +0100384 NIH_ZERO (control_emit_job_removed (conn, DBUS_PATH_UPSTART,
385 class->path));
Scott James Remnant0464dc12008-05-08 19:21:54 +0100386}
387
Scott James Remnant07336532008-04-29 19:45:51 +0100388
389/**
390 * job_class_environment:
Scott James Remnant041e7cd2009-01-28 03:41:47 +0000391 * @parent: parent object for new table,
Scott James Remnant07336532008-04-29 19:45:51 +0100392 * @class: job class,
393 * @len: pointer to variable to store table length.
394 *
395 * Constructs an environment table containing the standard environment
396 * variables and defined in the job's @class.
397 *
398 * This table is suitable for storing in @job's env member so that it is
399 * used for all processes spawned by the job.
400 *
Scott James Remnant07336532008-04-29 19:45:51 +0100401 * If @len is not NULL it will be updated to contain the new array length.
402 *
Scott James Remnant041e7cd2009-01-28 03:41:47 +0000403 * If @parent is not NULL, it should be a pointer to another object which
404 * will be used as a parent for the returned array. When all parents
405 * of the returned array are freed, the returned array will also be
406 * freed.
407 *
Scott James Remnant07336532008-04-29 19:45:51 +0100408 * Returns: new environment table or NULL if insufficient memory.
409 **/
410char **
411job_class_environment (const void *parent,
412 JobClass *class,
413 size_t *len)
414{
Scott James Remnanta175f3b2008-06-07 20:20:11 +0100415 char * const builtin[] = { JOB_DEFAULT_ENVIRONMENT, NULL };
416 char **env;
Scott James Remnant07336532008-04-29 19:45:51 +0100417
418 nih_assert (class != NULL);
419
420 env = nih_str_array_new (parent);
421 if (! env)
422 return NULL;
423 if (len)
424 *len = 0;
425
426 /* Copy the builtin set of environment variables, usually these just
427 * pick up the values from init's own environment.
428 */
Scott James Remnanta175f3b2008-06-07 20:20:11 +0100429 if (! environ_append (&env, parent, len, TRUE, builtin))
430 goto error;
Scott James Remnant07336532008-04-29 19:45:51 +0100431
432 /* Copy the set of environment variables from the job configuration,
433 * these often have values but also often don't and we want them to
434 * override the builtins.
435 */
Scott James Remnanta175f3b2008-06-07 20:20:11 +0100436 if (! environ_append (&env, parent, len, TRUE, class->env))
437 goto error;
Scott James Remnant07336532008-04-29 19:45:51 +0100438
439 return env;
440
441error:
442 nih_free (env);
443 return NULL;
444}
Scott James Remnantb0ce81e2008-05-09 03:04:29 +0100445
Mattias Nissler90b71b62018-03-12 16:41:26 +0100446/**
447 * job_class_import_environment:
448 * @class: class to import environment for.
449 * @env: pointer to environment table,
450 * @len: length of @env,
451 * @new_env: environment table to append to import into @env.
452 *
453 * Updates the environment table @env to add any entries in @new_env
454 * that are imported per import declarations in @class.
455 *
456 * Both the array and the new strings within it are allocated using
457 * nih_alloc().
458 *
459 * @len will be updated to contain the new array length and @env will
460 * be updated to point to the new array pointer; use the return value
461 * simply to check for success.
462 *
463 * Returns: new array pointer or NULL if insufficient memory.
464 **/
465char**
466job_class_import_environment (JobClass *class,
467 char ***env,
468 void *parent,
469 size_t *len,
470 char * const *new_env)
471{
472 char * const *e;
473
474 nih_assert (env != NULL);
475
476 if (! *env) {
477 *env = nih_str_array_new (parent);
478 if (! *env)
479 return NULL;
480 if (len)
481 *len = 0;
482 }
483
484 for (e = new_env; e && *e; e++) {
485 char * const *match = NULL;
486 size_t elen;
487
488 if (environ_is_upstart_key (*e))
489 continue;
490
491 elen = strcspn(*e, "=");
492 for (match = class->import; match && *match; match++) {
493 if ((strncmp (*match, *e, elen) == 0) && !match[elen])
494 break;
495 }
496
Mattias Nisslerc4b38282018-06-13 14:41:03 +0200497 if (! match)
Mattias Nisslerf22b9772018-04-17 14:55:19 +0200498 continue;
Mattias Nissler90b71b62018-03-12 16:41:26 +0100499
500 if (! environ_add (env, parent, len, TRUE, *e))
501 return NULL;
502 }
503
504 return *env;
505}
506
Scott James Remnantb0ce81e2008-05-09 03:04:29 +0100507
508/**
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100509 * job_class_get_instance:
510 * @class: job class to be query,
511 * @message: D-Bus connection and message received,
512 * @env: NULL-terminated array of environment variables,
513 * @instance: pointer for instance name.
514 *
515 * Implements the GetInstance method of the com.ubuntu.Upstart.Job
516 * interface.
517 *
518 * Called to obtain the path of an instance based on @env, which is used
519 * to locate the instance in the same way that Start, Stop and Restart do.
520 *
521 * If no such instance is found, the com.ubuntu.Upstart.Error.UnknownInstance
522 * D-Bus error will be returned immediately.
523 *
524 * Returns: zero on success, negative value on raised error.
525 **/
526int
527job_class_get_instance (JobClass *class,
528 NihDBusMessage *message,
529 char * const *env,
530 char **instance)
531{
Scott James Remnantd3df7ee2009-01-29 04:20:42 +0000532 Job *job;
533 nih_local char **instance_env = NULL;
534 nih_local char *name = NULL;
535 size_t len;
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100536
537 nih_assert (class != NULL);
538 nih_assert (message != NULL);
539 nih_assert (env != NULL);
540
541 /* Verify that the environment is valid */
542 if (! environ_all_valid (env)) {
543 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
544 _("Env must be KEY=VALUE pairs"));
545 return -1;
546 }
547
548 /* Construct the full environment for the instance based on the class
549 * and that provided.
550 */
551 instance_env = job_class_environment (NULL, class, &len);
552 if (! instance_env)
553 nih_return_system_error (-1);
554
Mattias Nissler90b71b62018-03-12 16:41:26 +0100555 if (! job_class_import_environment (class, &instance_env, NULL, &len,
556 env))
Scott James Remnantd3df7ee2009-01-29 04:20:42 +0000557 nih_return_system_error (-1);
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100558
559 /* Use the environment to expand the instance name and look it up
560 * in the job.
561 */
562 name = environ_expand (NULL, class->instance, instance_env);
563 if (! name) {
564 NihError *error;
565
566 error = nih_error_get ();
567 if (error->number != ENOMEM) {
Scott James Remnant0ff734e2009-05-09 16:56:08 +0100568 error = nih_error_steal ();
Scott James Remnant3d7483b2009-05-09 16:36:03 +0100569 nih_dbus_error_raise (DBUS_ERROR_INVALID_ARGS,
Scott James Remnant0ff734e2009-05-09 16:56:08 +0100570 error->message);
571 nih_free (error);
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100572 }
573
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100574 return -1;
575 }
576
577 job = (Job *)nih_hash_lookup (class->instances, name);
578
579 if (! job) {
580 nih_dbus_error_raise_printf (
Scott James Remnant02606132009-07-02 18:31:25 +0100581 DBUS_INTERFACE_UPSTART ".Error.UnknownInstance",
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100582 _("Unknown instance: %s"), name);
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100583 return -1;
584 }
585
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100586 *instance = nih_strdup (message, job->path);
587 if (! *instance)
588 nih_return_system_error (-1);
589
590 return 0;
591}
592
593/**
Scott James Remnantb0ce81e2008-05-09 03:04:29 +0100594 * job_class_get_instance_by_name:
595 * @class: class to obtain instance from,
596 * @message: D-Bus connection and message received,
597 * @name: name of instance to get,
598 * @instance: pointer for object path reply.
599 *
600 * Implements the GetInstanceByName method of the com.ubuntu.Upstart.Job
601 * interface.
602 *
603 * Called to obtain the path to a D-Bus object for the instance named
604 * @name of this job which will be stored in @job. If no instance with
605 * that name exists, the com.ubuntu.Upstart.Error.UnknownInstance D-Bus
606 * error will be raised.
607 *
608 * Returns: zero on success, negative value on raised error.
609 **/
610int
611job_class_get_instance_by_name (JobClass *class,
612 NihDBusMessage *message,
613 const char *name,
Scott James Remnant8c69f7b2008-06-01 19:40:33 +0100614 char **instance)
Scott James Remnantb0ce81e2008-05-09 03:04:29 +0100615{
616 Job *job;
617
618 nih_assert (class != NULL);
619 nih_assert (message != NULL);
620 nih_assert (name != NULL);
621 nih_assert (instance != NULL);
622
623 job = (Job *)nih_hash_lookup (class->instances, name);
624 if (! job) {
625 nih_dbus_error_raise_printf (
Scott James Remnant02606132009-07-02 18:31:25 +0100626 DBUS_INTERFACE_UPSTART ".Error.UnknownInstance",
Scott James Remnantb0ce81e2008-05-09 03:04:29 +0100627 _("Unknown instance: %s"), name);
628 return -1;
629 }
630
631 *instance = nih_strdup (message, job->path);
632 if (! *instance)
633 nih_return_system_error (-1);
634
635 return 0;
636}
Scott James Remnant92f2cc42008-06-01 20:42:30 +0100637
638/**
639 * job_class_get_all_instances:
640 * @class: class to obtain instance from,
641 * @message: D-Bus connection and message received,
642 * @instances: pointer for array of object paths reply.
643 *
644 * Implements the GetAllInstances method of the com.ubuntu.Upstart.Job
645 * interface.
646 *
647 * Called to obtain the paths of all instances for the given @class, which
648 * will be stored in @instances. If no instances exist, @instances will
649 * point to an empty array.
650 *
651 * Returns: zero on success, negative value on raised error.
652 **/
653int
654job_class_get_all_instances (JobClass *class,
655 NihDBusMessage *message,
656 char ***instances)
657{
658 char **list;
659 size_t len;
660
661 nih_assert (class != NULL);
662 nih_assert (message != NULL);
663 nih_assert (instances != NULL);
664
665 len = 0;
666 list = nih_str_array_new (message);
667 if (! list)
668 nih_return_system_error (-1);
669
670 NIH_HASH_FOREACH (class->instances, iter) {
671 Job *job = (Job *)iter;
672
673 if (! nih_str_array_add (&list, message, &len, job->path)) {
674 nih_error_raise_system ();
675 nih_free (list);
676 return -1;
677 }
678 }
679
680 *instances = list;
681
682 return 0;
683}
Scott James Remnant3fb48382008-06-08 02:03:40 +0100684
685
686/**
687 * job_class_start:
688 * @class: job class to be started,
689 * @message: D-Bus connection and message received,
Scott James Remnantf2926f02009-07-03 17:28:21 +0100690 * @env: NULL-terminated array of environment variables,
691 * @wait: whether to wait for command to finish before returning.
Scott James Remnant3fb48382008-06-08 02:03:40 +0100692 *
693 * Implements the top half of the Start method of the com.ubuntu.Upstart.Job
694 * interface, the bottom half may be found in job_finished().
695 *
696 * This is the primary method to start new instances of jobs. The given
697 * @env will be used to locate an existing instance, or create a new one
698 * if necessary; in either case, the instance will be set to be started
699 * (or restarted if it is currently stopping) with @env as its new
700 * environment.
701 *
702 * If the instance goal is already start,
703 * the com.ubuntu.Upstart.Error.AlreadyStarted D-Bus error will be returned
704 * immediately. If the instance fails to start, the
705 * com.ubuntu.Upstart.Error.JobFailed D-BUs error will be returned when the
706 * problem occurs.
707 *
Scott James Remnantf2926f02009-07-03 17:28:21 +0100708 * When @wait is TRUE the method call will not return until the job has
709 * finished starting (running for tasks); when @wait is FALSE, the method
710 * call returns once the command has been processed and the goal changed.
711 *
Scott James Remnant3fb48382008-06-08 02:03:40 +0100712 * Returns: zero on success, negative value on raised error.
713 **/
714int
715job_class_start (JobClass *class,
716 NihDBusMessage *message,
Scott James Remnantf2926f02009-07-03 17:28:21 +0100717 char * const *env,
718 int wait)
Scott James Remnant3fb48382008-06-08 02:03:40 +0100719{
Scott James Remnantf2926f02009-07-03 17:28:21 +0100720 Blocked *blocked = NULL;
Scott James Remnant75fb8382009-01-29 00:01:08 +0000721 Job *job;
722 nih_local char **start_env = NULL;
723 nih_local char *name = NULL;
724 size_t len;
Scott James Remnant3fb48382008-06-08 02:03:40 +0100725
726 nih_assert (class != NULL);
727 nih_assert (message != NULL);
728 nih_assert (env != NULL);
729
730 /* Verify that the environment is valid */
731 if (! environ_all_valid (env)) {
732 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
733 _("Env must be KEY=VALUE pairs"));
734 return -1;
735 }
736
737 /* Construct the full environment for the instance based on the class
738 * and that provided.
739 */
740 start_env = job_class_environment (NULL, class, &len);
741 if (! start_env)
742 nih_return_system_error (-1);
743
Mattias Nissler90b71b62018-03-12 16:41:26 +0100744 if (! job_class_import_environment (class, &start_env, NULL, &len, env))
Scott James Remnant50643372009-01-28 03:49:56 +0000745 nih_return_system_error (-1);
Scott James Remnant3fb48382008-06-08 02:03:40 +0100746
747 /* Use the environment to expand the instance name and look it up
748 * in the job.
749 */
750 name = environ_expand (NULL, class->instance, start_env);
751 if (! name) {
752 NihError *error;
753
754 error = nih_error_get ();
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100755 if (error->number != ENOMEM) {
Scott James Remnant0ff734e2009-05-09 16:56:08 +0100756 error = nih_error_steal ();
Scott James Remnant3d7483b2009-05-09 16:36:03 +0100757 nih_dbus_error_raise (DBUS_ERROR_INVALID_ARGS,
Scott James Remnant0ff734e2009-05-09 16:56:08 +0100758 error->message);
759 nih_free (error);
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100760 }
Scott James Remnant3fb48382008-06-08 02:03:40 +0100761
Scott James Remnant3fb48382008-06-08 02:03:40 +0100762 return -1;
763 }
764
765 job = (Job *)nih_hash_lookup (class->instances, name);
766
Scott James Remnant3fb48382008-06-08 02:03:40 +0100767 /* If no instance exists with the expanded name, create a new
768 * instance.
769 */
770 if (! job) {
771 job = job_new (class, name);
Scott James Remnant50643372009-01-28 03:49:56 +0000772 if (! job)
773 nih_return_system_error (-1);
Scott James Remnant3fb48382008-06-08 02:03:40 +0100774 }
775
Scott James Remnant3fb48382008-06-08 02:03:40 +0100776 if (job->goal == JOB_START) {
777 nih_dbus_error_raise_printf (
Scott James Remnant02606132009-07-02 18:31:25 +0100778 DBUS_INTERFACE_UPSTART ".Error.AlreadyStarted",
Scott James Remnant3fb48382008-06-08 02:03:40 +0100779 _("Job is already running: %s"),
780 job_name (job));
Scott James Remnant3fb48382008-06-08 02:03:40 +0100781 return -1;
782 }
783
Scott James Remnantf2926f02009-07-03 17:28:21 +0100784 if (wait)
785 blocked = NIH_MUST (blocked_new (job, BLOCKED_JOB_START_METHOD,
786 message));
Scott James Remnant3fb48382008-06-08 02:03:40 +0100787
788 if (job->start_env)
Scott James Remnantd3df7ee2009-01-29 04:20:42 +0000789 nih_unref (job->start_env, job);
Scott James Remnant3fb48382008-06-08 02:03:40 +0100790
Scott James Remnant3fb48382008-06-08 02:03:40 +0100791 job->start_env = start_env;
Scott James Remnant50643372009-01-28 03:49:56 +0000792 nih_ref (job->start_env, job);
Scott James Remnant3fb48382008-06-08 02:03:40 +0100793
794 job_finished (job, FALSE);
Scott James Remnantb175de82009-07-09 12:50:19 +0100795 if (blocked)
Scott James Remnantf2926f02009-07-03 17:28:21 +0100796 nih_list_add (&job->blocking, &blocked->entry);
Scott James Remnant3fb48382008-06-08 02:03:40 +0100797
798 job_change_goal (job, JOB_START);
799
Scott James Remnantf2926f02009-07-03 17:28:21 +0100800 if (! wait)
801 NIH_ZERO (job_class_start_reply (message, job->path));
Scott James Remnant75fb8382009-01-29 00:01:08 +0000802
Scott James Remnant3fb48382008-06-08 02:03:40 +0100803 return 0;
804}
805
806/**
807 * job_class_stop:
808 * @class: job class to be stopped,
809 * @message: D-Bus connection and message received,
Scott James Remnantf2926f02009-07-03 17:28:21 +0100810 * @env: NULL-terminated array of environment variables,
811 * @wait: whether to wait for command to finish before returning.
Scott James Remnant3fb48382008-06-08 02:03:40 +0100812 *
813 * Implements the top half of the Stop method of the com.ubuntu.Upstart.Job
814 * interface, the bottom half may be found in job_finished().
815 *
816 * This is the primary method to stop instances of jobs. The given @env
817 * will be used to locate an existing instance which will be set to be
818 * stopped with @env as the environment passed to the pre-stop script.
819 *
820 * If no such instance is found, the com.ubuntu.Upstart.Error.UnknownInstance
821 * D-Bus error will be returned immediately. If the instance goal is already
822 * stop, the com.ubuntu.Upstart.Error.AlreadyStopped D-Bus error will be
823 * returned immediately. If the instance fails to stop, the
824 * com.ubuntu.Upstart.Error.JobFailed D-Bus error will be returned when the
825 * problem occurs.
826 *
Scott James Remnantf2926f02009-07-03 17:28:21 +0100827 * When @wait is TRUE the method call will not return until the job has
828 * finished stopping; when @wait is FALSE, the method call returns once
829 * the command has been processed and the goal changed.
830 *
Scott James Remnant3fb48382008-06-08 02:03:40 +0100831 * Returns: zero on success, negative value on raised error.
832 **/
833int
834job_class_stop (JobClass *class,
835 NihDBusMessage *message,
Scott James Remnantf2926f02009-07-03 17:28:21 +0100836 char * const *env,
837 int wait)
Scott James Remnant3fb48382008-06-08 02:03:40 +0100838{
Scott James Remnant50643372009-01-28 03:49:56 +0000839 Blocked *blocked = NULL;
840 Job *job;
841 nih_local char **stop_env = NULL;
842 nih_local char *name = NULL;
843 size_t len;
Scott James Remnant3fb48382008-06-08 02:03:40 +0100844
845 nih_assert (class != NULL);
846 nih_assert (message != NULL);
847 nih_assert (env != NULL);
848
849 /* Verify that the environment is valid */
850 if (! environ_all_valid (env)) {
851 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
852 _("Env must be KEY=VALUE pairs"));
853 return -1;
854 }
855
856 /* Construct the full environment for the instance based on the class
857 * and that provided; while we don't pass this to the instance itself,
858 * we need this to look up the instance in the first place.
859 */
860 stop_env = job_class_environment (NULL, class, &len);
861 if (! stop_env)
862 nih_return_system_error (-1);
863
Mattias Nissler90b71b62018-03-12 16:41:26 +0100864 if (! job_class_import_environment (class, &stop_env, NULL, &len, env))
Scott James Remnant50643372009-01-28 03:49:56 +0000865 nih_return_system_error (-1);
Scott James Remnant3fb48382008-06-08 02:03:40 +0100866
867 /* Use the environment to expand the instance name and look it up
868 * in the job.
869 */
870 name = environ_expand (NULL, class->instance, stop_env);
871 if (! name) {
872 NihError *error;
873
874 error = nih_error_get ();
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100875 if (error->number != ENOMEM) {
Scott James Remnant0ff734e2009-05-09 16:56:08 +0100876 error = nih_error_steal ();
Scott James Remnant3d7483b2009-05-09 16:36:03 +0100877 nih_dbus_error_raise (DBUS_ERROR_INVALID_ARGS,
Scott James Remnant0ff734e2009-05-09 16:56:08 +0100878 error->message);
879 nih_free (error);
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100880 }
Scott James Remnant3fb48382008-06-08 02:03:40 +0100881
Scott James Remnant3fb48382008-06-08 02:03:40 +0100882 return -1;
883 }
884
885 job = (Job *)nih_hash_lookup (class->instances, name);
886
887 if (! job) {
888 nih_dbus_error_raise_printf (
Scott James Remnant02606132009-07-02 18:31:25 +0100889 DBUS_INTERFACE_UPSTART ".Error.UnknownInstance",
Scott James Remnant3fb48382008-06-08 02:03:40 +0100890 _("Unknown instance: %s"), name);
Scott James Remnant3fb48382008-06-08 02:03:40 +0100891 return -1;
892 }
893
Scott James Remnant3fb48382008-06-08 02:03:40 +0100894
895 if (job->goal == JOB_STOP) {
896 nih_dbus_error_raise_printf (
Scott James Remnant02606132009-07-02 18:31:25 +0100897 DBUS_INTERFACE_UPSTART ".Error.AlreadyStopped",
Scott James Remnant3fb48382008-06-08 02:03:40 +0100898 _("Job has already been stopped: %s"),
899 job_name (job));
900
901 return -1;
902 }
903
Scott James Remnantf2926f02009-07-03 17:28:21 +0100904 if (wait)
905 blocked = NIH_MUST (blocked_new (job, BLOCKED_JOB_STOP_METHOD,
906 message));
Scott James Remnant3fb48382008-06-08 02:03:40 +0100907
908 if (job->stop_env)
Scott James Remnantd3df7ee2009-01-29 04:20:42 +0000909 nih_unref (job->stop_env, job);
Scott James Remnant3fb48382008-06-08 02:03:40 +0100910
Mattias Nissler90b71b62018-03-12 16:41:26 +0100911 job->stop_env = stop_env;
Scott James Remnant50643372009-01-28 03:49:56 +0000912 nih_ref (job->stop_env, job);
Scott James Remnant3fb48382008-06-08 02:03:40 +0100913
914 job_finished (job, FALSE);
Scott James Remnantb175de82009-07-09 12:50:19 +0100915 if (blocked)
Scott James Remnantf2926f02009-07-03 17:28:21 +0100916 nih_list_add (&job->blocking, &blocked->entry);
Scott James Remnant3fb48382008-06-08 02:03:40 +0100917
918 job_change_goal (job, JOB_STOP);
919
Scott James Remnantf2926f02009-07-03 17:28:21 +0100920 if (! wait)
921 NIH_ZERO (job_class_stop_reply (message));
922
Scott James Remnant3fb48382008-06-08 02:03:40 +0100923 return 0;
924}
925
926/**
927 * job_restart:
928 * @class: job class to be restarted,
929 * @message: D-Bus connection and message received,
Scott James Remnantf2926f02009-07-03 17:28:21 +0100930 * @env: NULL-terminated array of environment variables,
931 * @wait: whether to wait for command to finish before returning.
Scott James Remnant3fb48382008-06-08 02:03:40 +0100932 *
933 * Implements the top half of the Restart method of the com.ubuntu.Upstart.Job
934 * interface, the bottom half may be found in job_finished().
935 *
936 * This is the primary method to restart existing instances of jobs; while
937 * calling both "Stop" and "Start" may have the same effect, there is no
938 * guarantee of atomicity.
939 *
940 * The given @env will be used to locate the existing instance, which will
941 * be stopped and then restarted with @env as its new environment.
942 *
943 * If no such instance is found, the com.ubuntu.Upstart.Error.UnknownInstance
944 * D-Bus error will be returned immediately. If the instance goal is already
945 * stop, the com.ubuntu.Upstart.Error.AlreadyStopped D-Bus error will be
946 * returned immediately. If the instance fails to restart, the
947 * com.ubuntu.Upstart.Error.JobFailed D-Bus error will be returned when the
948 * problem occurs.
949 *
Scott James Remnantf2926f02009-07-03 17:28:21 +0100950 * When @wait is TRUE the method call will not return until the job has
951 * finished starting again (running for tasks); when @wait is FALSE, the
952 * method call returns once the command has been processed and the goal
953 * changed.
954
Scott James Remnant3fb48382008-06-08 02:03:40 +0100955 * Returns: zero on success, negative value on raised error.
956 **/
957int
958job_class_restart (JobClass *class,
959 NihDBusMessage *message,
Scott James Remnantf2926f02009-07-03 17:28:21 +0100960 char * const *env,
961 int wait)
Scott James Remnant3fb48382008-06-08 02:03:40 +0100962{
Scott James Remnant50643372009-01-28 03:49:56 +0000963 Blocked *blocked = NULL;
964 Job *job;
965 nih_local char **restart_env = NULL;
966 nih_local char *name = NULL;
967 size_t len;
Scott James Remnant3fb48382008-06-08 02:03:40 +0100968
969 nih_assert (class != NULL);
970 nih_assert (message != NULL);
971 nih_assert (env != NULL);
972
973 /* Verify that the environment is valid */
974 if (! environ_all_valid (env)) {
975 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
976 _("Env must be KEY=VALUE pairs"));
977 return -1;
978 }
979
980 /* Construct the full environment for the instance based on the class
981 * and that provided.
982 */
983 restart_env = job_class_environment (NULL, class, &len);
984 if (! restart_env)
985 nih_return_system_error (-1);
986
Mattias Nissler90b71b62018-03-12 16:41:26 +0100987 if (! job_class_import_environment (class, &restart_env, NULL, &len,
988 env))
Scott James Remnant50643372009-01-28 03:49:56 +0000989 nih_return_system_error (-1);
Scott James Remnant3fb48382008-06-08 02:03:40 +0100990
991 /* Use the environment to expand the instance name and look it up
992 * in the job.
993 */
994 name = environ_expand (NULL, class->instance, restart_env);
995 if (! name) {
996 NihError *error;
997
998 error = nih_error_get ();
Scott James Remnantb40e4dd2008-06-08 03:26:36 +0100999 if (error->number != ENOMEM) {
Scott James Remnant0ff734e2009-05-09 16:56:08 +01001000 error = nih_error_steal ();
Scott James Remnant3d7483b2009-05-09 16:36:03 +01001001 nih_dbus_error_raise (DBUS_ERROR_INVALID_ARGS,
Scott James Remnant0ff734e2009-05-09 16:56:08 +01001002 error->message);
1003 nih_free (error);
Scott James Remnantb40e4dd2008-06-08 03:26:36 +01001004 }
Scott James Remnant3fb48382008-06-08 02:03:40 +01001005
Scott James Remnant3fb48382008-06-08 02:03:40 +01001006 return -1;
1007 }
1008
1009 job = (Job *)nih_hash_lookup (class->instances, name);
1010
1011 if (! job) {
1012 nih_dbus_error_raise_printf (
Scott James Remnant02606132009-07-02 18:31:25 +01001013 DBUS_INTERFACE_UPSTART ".Error.UnknownInstance",
Scott James Remnant3fb48382008-06-08 02:03:40 +01001014 _("Unknown instance: %s"), name);
Scott James Remnant3fb48382008-06-08 02:03:40 +01001015 return -1;
1016 }
1017
Scott James Remnant3fb48382008-06-08 02:03:40 +01001018
1019 if (job->goal == JOB_STOP) {
1020 nih_dbus_error_raise_printf (
Scott James Remnant02606132009-07-02 18:31:25 +01001021 DBUS_INTERFACE_UPSTART ".Error.AlreadyStopped",
Scott James Remnant3fb48382008-06-08 02:03:40 +01001022 _("Job has already been stopped: %s"), job->name);
1023
Scott James Remnant3fb48382008-06-08 02:03:40 +01001024 return -1;
1025 }
1026
Scott James Remnantf2926f02009-07-03 17:28:21 +01001027 if (wait)
1028 blocked = NIH_MUST (blocked_new (job,
1029 BLOCKED_JOB_RESTART_METHOD,
1030 message));
Scott James Remnant3fb48382008-06-08 02:03:40 +01001031
1032 if (job->start_env)
Scott James Remnantd3df7ee2009-01-29 04:20:42 +00001033 nih_unref (job->start_env, job);
Scott James Remnant3fb48382008-06-08 02:03:40 +01001034
Scott James Remnant3fb48382008-06-08 02:03:40 +01001035 job->start_env = restart_env;
Scott James Remnant50643372009-01-28 03:49:56 +00001036 nih_ref (job->start_env, job);
Scott James Remnant3fb48382008-06-08 02:03:40 +01001037
1038 if (job->stop_env)
Scott James Remnantd3df7ee2009-01-29 04:20:42 +00001039 nih_unref (job->stop_env, job);
Scott James Remnant3fb48382008-06-08 02:03:40 +01001040 job->stop_env = NULL;
1041
1042 job_finished (job, FALSE);
Scott James Remnantb175de82009-07-09 12:50:19 +01001043 if (blocked)
Scott James Remnantf2926f02009-07-03 17:28:21 +01001044 nih_list_add (&job->blocking, &blocked->entry);
Scott James Remnant3fb48382008-06-08 02:03:40 +01001045
1046 job_change_goal (job, JOB_STOP);
1047 job_change_goal (job, JOB_START);
1048
Scott James Remnantf2926f02009-07-03 17:28:21 +01001049 if (! wait)
1050 NIH_ZERO (job_class_restart_reply (message, job->path));
1051
Scott James Remnant3fb48382008-06-08 02:03:40 +01001052 return 0;
1053}
Scott James Remnant6f49af02009-06-17 17:41:09 +01001054
1055
1056/**
1057 * job_class_get_name:
1058 * @class: class to obtain name from,
1059 * @message: D-Bus connection and message received,
1060 * @name: pointer for reply string.
1061 *
1062 * Implements the get method for the name property of the
1063 * com.ubuntu.Upstart.Job interface.
1064 *
1065 * Called to obtain the name of the given @class, which will be stored in
1066 * @name.
1067 *
1068 * Returns: zero on success, negative value on raised error.
1069 **/
1070int
1071job_class_get_name (JobClass *class,
1072 NihDBusMessage *message,
1073 char **name)
1074{
1075 nih_assert (class != NULL);
1076 nih_assert (message != NULL);
1077 nih_assert (name != NULL);
1078
1079 *name = class->name;
1080 nih_ref (*name, message);
1081
1082 return 0;
1083}
1084
1085/**
1086 * job_class_get_description:
1087 * @class: class to obtain name from,
1088 * @message: D-Bus connection and message received,
1089 * @description: pointer for reply string.
1090 *
1091 * Implements the get method for the description property of the
1092 * com.ubuntu.Upstart.Job interface.
1093 *
1094 * Called to obtain the description of the given @class, which will be stored
1095 * in @description.
1096 *
1097 * Returns: zero on success, negative value on raised error.
1098 **/
1099int
1100job_class_get_description (JobClass *class,
1101 NihDBusMessage *message,
1102 char **description)
1103{
1104 nih_assert (class != NULL);
1105 nih_assert (message != NULL);
1106 nih_assert (description != NULL);
1107
1108 if (class->description) {
1109 *description = class->description;
1110 nih_ref (*description, message);
1111 } else {
1112 *description = nih_strdup (message, "");
1113 if (! *description)
1114 nih_return_no_memory_error (-1);
1115 }
1116
1117 return 0;
1118}
1119
1120/**
1121 * job_class_get_author:
1122 * @class: class to obtain name from,
1123 * @message: D-Bus connection and message received,
1124 * @author: pointer for reply string.
1125 *
1126 * Implements the get method for the author property of the
1127 * com.ubuntu.Upstart.Job interface.
1128 *
1129 * Called to obtain the author of the given @class, which will be stored
1130 * in @author.
1131 *
1132 * Returns: zero on success, negative value on raised error.
1133 **/
1134int
1135job_class_get_author (JobClass *class,
1136 NihDBusMessage *message,
1137 char **author)
1138{
1139 nih_assert (class != NULL);
1140 nih_assert (message != NULL);
1141 nih_assert (author != NULL);
1142
1143 if (class->author) {
1144 *author = class->author;
1145 nih_ref (*author, message);
1146 } else {
1147 *author = nih_strdup (message, "");
1148 if (! *author)
1149 nih_return_no_memory_error (-1);
1150 }
1151
1152 return 0;
1153}
1154
1155/**
1156 * job_class_get_version:
1157 * @class: class to obtain name from,
1158 * @message: D-Bus connection and message received,
1159 * @version: pointer for reply string.
1160 *
1161 * Implements the get method for the version property of the
1162 * com.ubuntu.Upstart.Job interface.
1163 *
1164 * Called to obtain the version of the given @class, which will be stored
1165 * in @version.
1166 *
1167 * Returns: zero on success, negative value on raised error.
1168 **/
1169int
1170job_class_get_version (JobClass *class,
1171 NihDBusMessage *message,
1172 char **version)
1173{
1174 nih_assert (class != NULL);
1175 nih_assert (message != NULL);
1176 nih_assert (version != NULL);
1177
1178 if (class->version) {
1179 *version = class->version;
1180 nih_ref (*version, message);
1181 } else {
1182 *version = nih_strdup (message, "");
1183 if (! *version)
1184 nih_return_no_memory_error (-1);
1185 }
1186
1187 return 0;
1188}
Scott James Remnantda28a632010-12-10 02:43:11 +00001189
1190
Scott James Remnant01d658c2010-12-14 15:09:52 +00001191/**
1192 * job_class_get_start_on:
1193 * @class: class to obtain events from,
1194 * @message: D-Bus connection and message received,
1195 * @start_on: pointer for reply array.
1196 *
1197 * Implements the get method for the start_on property of the
1198 * com.ubuntu.Upstart.Job interface.
1199 *
1200 * Called to obtain the set of events that will start jobs of the given
1201 * @class, this is returned as an array of the event tree flattened into
1202 * reverse polish form.
1203 *
1204 * Each array element is an array of strings representing the events,
1205 * or a single element containing "/OR" or "/AND" to represent the
1206 * operators.
1207 *
1208 * Returns: zero on success, negative value on raised error.
1209 **/
Scott James Remnantda28a632010-12-10 02:43:11 +00001210int
1211job_class_get_start_on (JobClass * class,
1212 NihDBusMessage *message,
1213 char **** start_on)
1214{
1215 size_t len = 0;
1216
1217 nih_assert (class != NULL);
1218 nih_assert (message != NULL);
1219 nih_assert (start_on != NULL);
1220
1221 *start_on = nih_alloc (message, sizeof (char ***));
1222 if (! *start_on)
1223 nih_return_no_memory_error (-1);
1224
1225 len = 0;
1226 (*start_on)[len] = NULL;
1227
1228 if (class->start_on) {
1229 NIH_TREE_FOREACH_POST (&class->start_on->node, iter) {
1230 EventOperator *oper = (EventOperator *)iter;
1231
1232 *start_on = nih_realloc (*start_on, message,
1233 sizeof (char ***) * (len + 2));
1234 if (! *start_on)
1235 nih_return_no_memory_error (-1);
1236
1237 (*start_on)[len] = nih_str_array_new (*start_on);
1238 if (! (*start_on)[len])
1239 nih_return_no_memory_error (-1);
1240
1241 switch (oper->type) {
1242 case EVENT_OR:
1243 if (! nih_str_array_add (&(*start_on)[len], *start_on,
1244 NULL, "/OR"))
1245 nih_return_no_memory_error (-1);
1246 break;
1247 case EVENT_AND:
1248 if (! nih_str_array_add (&(*start_on)[len], *start_on,
1249 NULL, "/AND"))
1250 nih_return_no_memory_error (-1);
1251 break;
1252 case EVENT_MATCH:
1253 if (! nih_str_array_add (&(*start_on)[len], *start_on,
1254 NULL, oper->name))
1255 nih_return_no_memory_error (-1);
1256 if (oper->env)
1257 if (! nih_str_array_append (&(*start_on)[len], *start_on,
1258 NULL, oper->env))
1259 nih_return_no_memory_error (-1);
1260 break;
1261 }
1262
1263 (*start_on)[++len] = NULL;
1264 }
1265 }
1266
1267 return 0;
1268}
1269
Scott James Remnant01d658c2010-12-14 15:09:52 +00001270/**
1271 * job_class_get_stop_on:
1272 * @class: class to obtain events from,
1273 * @message: D-Bus connection and message received,
1274 * @stop_on: pointer for reply array.
1275 *
1276 * Implements the get method for the stop_on property of the
1277 * com.ubuntu.Upstart.Job interface.
1278 *
1279 * Called to obtain the set of events that will stop jobs of the given
1280 * @class, this is returned as an array of the event tree flattened into
1281 * reverse polish form.
1282 *
1283 * Each array element is an array of strings representing the events,
1284 * or a single element containing "/OR" or "/AND" to represent the
1285 * operators.
1286 *
1287 * Returns: zero on success, negative value on raised error.
1288 **/
Scott James Remnantda28a632010-12-10 02:43:11 +00001289int
1290job_class_get_stop_on (JobClass * class,
1291 NihDBusMessage *message,
1292 char **** stop_on)
1293{
1294 size_t len = 0;
1295
1296 nih_assert (class != NULL);
1297 nih_assert (message != NULL);
1298 nih_assert (stop_on != NULL);
1299
1300 *stop_on = nih_alloc (message, sizeof (char ***));
1301 if (! *stop_on)
1302 nih_return_no_memory_error (-1);
1303
1304 len = 0;
1305 (*stop_on)[len] = NULL;
1306
1307 if (class->stop_on) {
1308 NIH_TREE_FOREACH_POST (&class->stop_on->node, iter) {
1309 EventOperator *oper = (EventOperator *)iter;
1310
1311 *stop_on = nih_realloc (*stop_on, message,
1312 sizeof (char ***) * (len + 2));
1313 if (! *stop_on)
1314 nih_return_no_memory_error (-1);
1315
1316 (*stop_on)[len] = nih_str_array_new (*stop_on);
1317 if (! (*stop_on)[len])
1318 nih_return_no_memory_error (-1);
1319
1320 switch (oper->type) {
1321 case EVENT_OR:
1322 if (! nih_str_array_add (&(*stop_on)[len], *stop_on,
1323 NULL, "/OR"))
1324 nih_return_no_memory_error (-1);
1325 break;
1326 case EVENT_AND:
1327 if (! nih_str_array_add (&(*stop_on)[len], *stop_on,
1328 NULL, "/AND"))
1329 nih_return_no_memory_error (-1);
1330 break;
1331 case EVENT_MATCH:
1332 if (! nih_str_array_add (&(*stop_on)[len], *stop_on,
1333 NULL, oper->name))
1334 nih_return_no_memory_error (-1);
1335 if (oper->env)
1336 if (! nih_str_array_append (&(*stop_on)[len], *stop_on,
1337 NULL, oper->env))
1338 nih_return_no_memory_error (-1);
1339 break;
1340 }
1341
1342 (*stop_on)[++len] = NULL;
1343 }
1344 }
1345
1346 return 0;
1347}
1348
Scott James Remnant01d658c2010-12-14 15:09:52 +00001349/**
1350 * job_class_get_emits:
1351 * @class: class to obtain events from,
1352 * @message: D-Bus connection and message received,
1353 * @emits: pointer for reply array.
1354 *
1355 * Implements the get method for the emits property of the
1356 * com.ubuntu.Upstart.Job interface.
1357 *
1358 * Called to obtain the list of additional events of the given @class
1359 * which will be stored as an array in @emits.
1360 *
1361 * Returns: zero on success, negative value on raised error.
1362 **/
Scott James Remnantda28a632010-12-10 02:43:11 +00001363int
1364job_class_get_emits (JobClass * class,
1365 NihDBusMessage *message,
1366 char *** emits)
1367{
1368 nih_assert (class != NULL);
1369 nih_assert (message != NULL);
1370 nih_assert (emits != NULL);
1371
1372 if (class->emits) {
1373 *emits = nih_str_array_copy (message, NULL, class->emits);
1374 if (! *emits)
1375 nih_return_no_memory_error (-1);
1376 } else {
1377 *emits = nih_str_array_new (message);
1378 if (! *emits)
1379 nih_return_no_memory_error (-1);
1380 }
1381
1382 return 0;
1383}