device: renew dhcp leases on awake for software devices
[NetworkManager.git] / callouts / nm-dispatcher.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager -- Network link manager
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *
18  * Copyright (C) 2008 - 2012 Red Hat, Inc.
19  */
20
21 #include "nm-default.h"
22
23 #include <syslog.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <signal.h>
30 #include <sys/stat.h>
31 #include <sys/wait.h>
32 #include <errno.h>
33 #include <arpa/inet.h>
34 #include <glib-unix.h>
35
36 #include "nm-dispatcher-api.h"
37 #include "nm-dispatcher-utils.h"
38
39 #include "nmdbus-dispatcher.h"
40
41 static GMainLoop *loop = NULL;
42 static gboolean debug = FALSE;
43 static gboolean persist = FALSE;
44 static guint quit_id;
45 static guint request_id_counter = 0;
46
47 typedef struct Request Request;
48
49 typedef struct {
50         GObject parent;
51
52         /* Private data */
53         NMDBusDispatcher *dbus_dispatcher;
54
55         Request *current_request;
56         GQueue *requests_waiting;
57         gint num_requests_pending;
58 } Handler;
59
60 typedef struct {
61   GObjectClass parent;
62 } HandlerClass;
63
64 GType handler_get_type (void);
65
66 #define HANDLER_TYPE         (handler_get_type ())
67 #define HANDLER(object)      (G_TYPE_CHECK_INSTANCE_CAST ((object), HANDLER_TYPE, Handler))
68 #define HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), HANDLER_TYPE, HandlerClass))
69
70 G_DEFINE_TYPE(Handler, handler, G_TYPE_OBJECT)
71
72 static gboolean
73 handle_action (NMDBusDispatcher *dbus_dispatcher,
74                GDBusMethodInvocation *context,
75                const char *str_action,
76                GVariant *connection_dict,
77                GVariant *connection_props,
78                GVariant *device_props,
79                GVariant *device_ip4_props,
80                GVariant *device_ip6_props,
81                GVariant *device_dhcp4_props,
82                GVariant *device_dhcp6_props,
83                const char *vpn_ip_iface,
84                GVariant *vpn_ip4_props,
85                GVariant *vpn_ip6_props,
86                gboolean request_debug,
87                gpointer user_data);
88
89 static void
90 handler_init (Handler *h)
91 {
92         h->requests_waiting = g_queue_new ();
93         h->dbus_dispatcher = nmdbus_dispatcher_skeleton_new ();
94         g_signal_connect (h->dbus_dispatcher, "handle-action",
95                           G_CALLBACK (handle_action), h);
96 }
97
98 static void
99 handler_class_init (HandlerClass *h_class)
100 {
101 }
102
103 static gboolean dispatch_one_script (Request *request);
104
105 typedef struct {
106         Request *request;
107
108         char *script;
109         GPid pid;
110         DispatchResult result;
111         char *error;
112         gboolean wait;
113         gboolean dispatched;
114         guint watch_id;
115         guint timeout_id;
116 } ScriptInfo;
117
118 struct Request {
119         Handler *handler;
120
121         guint request_id;
122
123         GDBusMethodInvocation *context;
124         char *action;
125         char *iface;
126         char **envp;
127         gboolean debug;
128
129         GPtrArray *scripts;  /* list of ScriptInfo */
130         guint idx;
131         gint num_scripts_done;
132         gint num_scripts_nowait;
133 };
134
135 /*****************************************************************************/
136
137 #define __LOG_print(print_cmd, _request, _script, ...) \
138         G_STMT_START { \
139                 nm_assert ((_request) && (!(_script) || (_script)->request == (_request))); \
140                 print_cmd ("req:%u '%s'%s%s%s%s%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
141                            (_request)->request_id, \
142                            (_request)->action, \
143                            (_request)->iface ? " [" : "", \
144                            (_request)->iface ? (_request)->iface : "", \
145                            (_request)->iface ? "]" : "", \
146                            (_script) ? ", \"" : "", \
147                            (_script) ? (_script)->script : "", \
148                            (_script) ? "\"" : "" \
149                            _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
150         } G_STMT_END
151
152 #define _LOG(_request, _script, log_always, print_cmd, ...) \
153         G_STMT_START { \
154                 const Request *__request = (_request); \
155                 const ScriptInfo *__script = (_script); \
156                 \
157                 if (!__request) \
158                         __request = __script->request; \
159                 nm_assert (__request && (!__script || __script->request == __request)); \
160                 if ((log_always) || _LOG_R_D_enabled (__request)) { \
161                         if (FALSE) { \
162                                 /* g_message() alone does not warn about invalid format. Add a dummy printf() statement to
163                                  * get a compiler warning about wrong format. */ \
164                                 __LOG_print (printf, __request, __script, __VA_ARGS__); \
165                         } \
166                         __LOG_print (print_cmd, __request, __script, __VA_ARGS__); \
167                 } \
168         } G_STMT_END
169
170 static gboolean
171 _LOG_R_D_enabled (const Request *request)
172 {
173         return request->debug;
174 }
175
176 #define _LOG_R_D(_request, ...) _LOG(_request, NULL, FALSE, g_debug,   __VA_ARGS__)
177 #define _LOG_R_I(_request, ...) _LOG(_request, NULL, TRUE,  g_info,    __VA_ARGS__)
178 #define _LOG_R_W(_request, ...) _LOG(_request, NULL, TRUE,  g_warning, __VA_ARGS__)
179
180 #define _LOG_S_D(_script, ...)  _LOG(NULL, _script,  FALSE, g_debug,   __VA_ARGS__)
181 #define _LOG_S_I(_script, ...)  _LOG(NULL, _script,  TRUE,  g_info,    __VA_ARGS__)
182 #define _LOG_S_W(_script, ...)  _LOG(NULL, _script,  TRUE,  g_warning, __VA_ARGS__)
183
184 /*****************************************************************************/
185
186 static void
187 script_info_free (gpointer ptr)
188 {
189         ScriptInfo *info = ptr;
190
191         g_free (info->script);
192         g_free (info->error);
193         g_slice_free (ScriptInfo, info);
194 }
195
196 static void
197 request_free (Request *request)
198 {
199         g_assert_cmpuint (request->num_scripts_done, ==, request->scripts->len);
200         g_assert_cmpuint (request->num_scripts_nowait, ==, 0);
201
202         g_free (request->action);
203         g_free (request->iface);
204         g_strfreev (request->envp);
205         g_ptr_array_free (request->scripts, TRUE);
206
207         g_slice_free (Request, request);
208 }
209
210 static gboolean
211 quit_timeout_cb (gpointer user_data)
212 {
213         g_main_loop_quit (loop);
214         return FALSE;
215 }
216
217 static void
218 quit_timeout_reschedule (void)
219 {
220         if (!persist) {
221                 nm_clear_g_source (&quit_id);
222                 quit_id = g_timeout_add_seconds (10, quit_timeout_cb, NULL);
223         }
224 }
225
226 /**
227  * next_request:
228  *
229  * @h: the handler
230  * @request: (allow-none): the request to set as next. If %NULL, dequeue the next
231  * waiting request. Otherwise, try to set the given request.
232  *
233  * Sets the currently active request (@current_request). The current request
234  * is a request that has at least on "wait" script, because requests that only
235  * consist of "no-wait" scripts are handled right away and not enqueued to
236  * @requests_waiting nor set as @current_request.
237  *
238  * Returns: %TRUE, if there was currently not request in process and it set
239  * a new request as current.
240  */
241 static gboolean
242 next_request (Handler *h, Request *request)
243 {
244         if (request) {
245                 if (h->current_request) {
246                         g_queue_push_tail (h->requests_waiting, request);
247                         return FALSE;
248                 }
249         } else {
250                 /* when calling next_request() without explicit @request, we always
251                  * forcefully clear @current_request. That one is certainly
252                  * handled already. */
253                 h->current_request = NULL;
254
255                 request = g_queue_pop_head (h->requests_waiting);
256                 if (!request)
257                         return FALSE;
258         }
259
260         _LOG_R_I (request, "start running ordered scripts...");
261
262         h->current_request = request;
263
264         return TRUE;
265 }
266
267 /**
268  * complete_request:
269  * @request: the request
270  *
271  * Checks if all the scripts for the request have terminated and in such case
272  * it sends the D-Bus response and releases the request resources.
273  *
274  * It also decreases @num_requests_pending and possibly does quit_timeout_reschedule().
275  */
276 static void
277 complete_request (Request *request)
278 {
279         GVariantBuilder results;
280         GVariant *ret;
281         guint i;
282         Handler *handler = request->handler;
283
284         nm_assert (request);
285
286         /* Are there still pending scripts? Then do nothing (for now). */
287         if (request->num_scripts_done < request->scripts->len)
288                 return;
289
290         g_variant_builder_init (&results, G_VARIANT_TYPE ("a(sus)"));
291         for (i = 0; i < request->scripts->len; i++) {
292                 ScriptInfo *script = g_ptr_array_index (request->scripts, i);
293
294                 g_variant_builder_add (&results, "(sus)",
295                                        script->script,
296                                        script->result,
297                                        script->error ? script->error : "");
298         }
299
300         ret = g_variant_new ("(a(sus))", &results);
301         g_dbus_method_invocation_return_value (request->context, ret);
302
303         _LOG_R_D (request, "completed (%u scripts)", request->scripts->len);
304
305         if (handler->current_request == request)
306                 handler->current_request = NULL;
307
308         request_free (request);
309
310         g_assert_cmpuint (handler->num_requests_pending, >, 0);
311         if (--handler->num_requests_pending <= 0) {
312                 nm_assert (!handler->current_request && !g_queue_peek_head (handler->requests_waiting));
313                 quit_timeout_reschedule ();
314         }
315 }
316
317 static void
318 complete_script (ScriptInfo *script)
319 {
320         Handler *handler;
321         Request *request;
322         gboolean wait = script->wait;
323
324         request = script->request;
325
326         if (wait) {
327                 /* for "wait" scripts, try to schedule the next blocking script.
328                  * If that is successful, return (as we must wait for its completion). */
329                 if (dispatch_one_script (request))
330                         return;
331         }
332
333         handler = request->handler;
334
335         nm_assert (!wait || handler->current_request == request);
336
337         /* Try to complete the request. @request will be possibly free'd,
338          * making @script and @request a dangling pointer. */
339         complete_request (request);
340
341         if (!wait) {
342                 /* this was a "no-wait" script. We either completed the request,
343                  * or there is nothing to do. Especially, there is no need to
344                  * queue the next_request() -- because no-wait scripts don't block
345                  * requests. However, if this was the last "no-wait" script and
346                  * there are "wait" scripts ready to run, launch them.
347                  */
348                 if (   handler->current_request == request
349                     && handler->current_request->num_scripts_nowait == 0) {
350
351                         if (dispatch_one_script (handler->current_request))
352                                 return;
353
354                         complete_request (handler->current_request);
355                 } else
356                         return;
357         } else {
358                 /* if the script is a "wait" script, we already tried above to
359                  * dispatch the next script. As we didn't do that, it means we
360                  * just completed the last script of @request and we can continue
361                  * with the next request...
362                  *
363                  * Also, it cannot be that there is another request currently being
364                  * processed because only requests with "wait" scripts can become
365                  * @current_request. As there can only be one "wait" script running
366                  * at any time, it means complete_request() above completed @request. */
367                 nm_assert (!handler->current_request);
368         }
369
370         while (next_request (handler, NULL)) {
371                 request = handler->current_request;
372
373                 if (dispatch_one_script (request))
374                         return;
375
376                 /* Try to complete the request. It will be either completed
377                  * now, or when all pending "no-wait" scripts return. */
378                 complete_request (request);
379
380                 /* We can immediately start next_request(), because our current
381                  * @request has obviously no more "wait" scripts either.
382                  * Repeat... */
383         }
384 }
385
386 static void
387 script_watch_cb (GPid pid, gint status, gpointer user_data)
388 {
389         ScriptInfo *script = user_data;
390         guint err;
391
392         g_assert (pid == script->pid);
393
394         script->watch_id = 0;
395         nm_clear_g_source (&script->timeout_id);
396         script->request->num_scripts_done++;
397         if (!script->wait)
398                 script->request->num_scripts_nowait--;
399
400         if (WIFEXITED (status)) {
401                 err = WEXITSTATUS (status);
402                 if (err == 0)
403                         script->result = DISPATCH_RESULT_SUCCESS;
404                 else {
405                         script->error = g_strdup_printf ("Script '%s' exited with error status %d.",
406                                                          script->script, err);
407                 }
408         } else if (WIFSTOPPED (status)) {
409                 script->error = g_strdup_printf ("Script '%s' stopped unexpectedly with signal %d.",
410                                                  script->script, WSTOPSIG (status));
411         } else if (WIFSIGNALED (status)) {
412                 script->error = g_strdup_printf ("Script '%s' died with signal %d",
413                                                  script->script, WTERMSIG (status));
414         } else {
415                 script->error = g_strdup_printf ("Script '%s' died from an unknown cause",
416                                                  script->script);
417         }
418
419         if (script->result == DISPATCH_RESULT_SUCCESS) {
420                 _LOG_S_D (script, "complete");
421         } else {
422                 script->result = DISPATCH_RESULT_FAILED;
423                 _LOG_S_W (script, "complete: failed with %s", script->error);
424         }
425
426         g_spawn_close_pid (script->pid);
427
428         complete_script (script);
429 }
430
431 static gboolean
432 script_timeout_cb (gpointer user_data)
433 {
434         ScriptInfo *script = user_data;
435
436         script->timeout_id = 0;
437         nm_clear_g_source (&script->watch_id);
438         script->request->num_scripts_done++;
439         if (!script->wait)
440                 script->request->num_scripts_nowait--;
441
442         _LOG_S_W (script, "complete: timeout (kill script)");
443
444         kill (script->pid, SIGKILL);
445 again:
446         if (waitpid (script->pid, NULL, 0) == -1) {
447                 if (errno == EINTR)
448                         goto again;
449         }
450
451         script->error = g_strdup_printf ("Script '%s' timed out.", script->script);
452         script->result = DISPATCH_RESULT_TIMEOUT;
453
454         g_spawn_close_pid (script->pid);
455
456         complete_script (script);
457
458         return FALSE;
459 }
460
461 static inline gboolean
462 check_permissions (struct stat *s, const char **out_error_msg)
463 {
464         g_return_val_if_fail (s != NULL, FALSE);
465         g_return_val_if_fail (out_error_msg != NULL, FALSE);
466         g_return_val_if_fail (*out_error_msg == NULL, FALSE);
467
468         /* Only accept regular files */
469         if (!S_ISREG (s->st_mode)) {
470                 *out_error_msg = "not a regular file.";
471                 return FALSE;
472         }
473
474         /* Only accept files owned by root */
475         if (s->st_uid != 0) {
476                 *out_error_msg = "not owned by root.";
477                 return FALSE;
478         }
479
480         /* Only accept files not writable by group or other, and not SUID */
481         if (s->st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) {
482                 *out_error_msg = "writable by group or other, or set-UID.";
483                 return FALSE;
484         }
485
486         /* Only accept files executable by the owner */
487         if (!(s->st_mode & S_IXUSR)) {
488                 *out_error_msg = "not executable by owner.";
489                 return FALSE;
490         }
491
492         return TRUE;
493 }
494
495 static gboolean
496 check_filename (const char *file_name)
497 {
498         static const char *bad_suffixes[] = {
499                 "~",
500                 ".rpmsave",
501                 ".rpmorig",
502                 ".rpmnew",
503                 ".swp",
504         };
505         char *tmp;
506         guint i;
507
508         /* File must not be a backup file, package management file, or start with '.' */
509
510         if (file_name[0] == '.')
511                 return FALSE;
512         for (i = 0; i < G_N_ELEMENTS (bad_suffixes); i++) {
513                 if (g_str_has_suffix (file_name, bad_suffixes[i]))
514                         return FALSE;
515         }
516         tmp = g_strrstr (file_name, ".dpkg-");
517         if (tmp && !strchr (&tmp[1], '.'))
518                 return FALSE;
519         return TRUE;
520 }
521
522 #define SCRIPT_TIMEOUT 600  /* 10 minutes */
523
524 static gboolean
525 script_dispatch (ScriptInfo *script)
526 {
527         GError *error = NULL;
528         gchar *argv[4];
529         Request *request = script->request;
530
531         if (script->dispatched)
532                 return FALSE;
533
534         script->dispatched = TRUE;
535
536         argv[0] = script->script;
537         argv[1] = request->iface
538                   ? request->iface
539                   : (!strcmp (request->action, NMD_ACTION_HOSTNAME) ? "none" : "");
540         argv[2] = request->action;
541         argv[3] = NULL;
542
543         _LOG_S_D (script, "run script%s", script->wait ? "" : " (no-wait)");
544
545         if (g_spawn_async ("/", argv, request->envp, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &script->pid, &error)) {
546                 script->watch_id = g_child_watch_add (script->pid, (GChildWatchFunc) script_watch_cb, script);
547                 script->timeout_id = g_timeout_add_seconds (SCRIPT_TIMEOUT, script_timeout_cb, script);
548                 if (!script->wait)
549                         request->num_scripts_nowait++;
550                 return TRUE;
551         } else {
552                 _LOG_S_W (script, "complete: failed to execute script: %s", error->message);
553                 script->result = DISPATCH_RESULT_EXEC_FAILED;
554                 script->error = g_strdup (error->message);
555                 request->num_scripts_done++;
556                 g_clear_error (&error);
557                 return FALSE;
558         }
559 }
560
561 static gboolean
562 dispatch_one_script (Request *request)
563 {
564         if (request->num_scripts_nowait > 0)
565                 return TRUE;
566
567         while (request->idx < request->scripts->len) {
568                 ScriptInfo *script;
569
570                 script = g_ptr_array_index (request->scripts, request->idx++);
571                 if (script_dispatch (script))
572                         return TRUE;
573         }
574         return FALSE;
575 }
576
577 static GSList *
578 find_scripts (const char *str_action)
579 {
580         GDir *dir;
581         const char *filename;
582         GSList *sorted = NULL;
583         GError *error = NULL;
584         const char *dirname;
585
586         if (   strcmp (str_action, NMD_ACTION_PRE_UP) == 0
587             || strcmp (str_action, NMD_ACTION_VPN_PRE_UP) == 0)
588                 dirname = NMD_SCRIPT_DIR_PRE_UP;
589         else if (   strcmp (str_action, NMD_ACTION_PRE_DOWN) == 0
590                  || strcmp (str_action, NMD_ACTION_VPN_PRE_DOWN) == 0)
591                 dirname = NMD_SCRIPT_DIR_PRE_DOWN;
592         else
593                 dirname = NMD_SCRIPT_DIR_DEFAULT;
594
595         if (!(dir = g_dir_open (dirname, 0, &error))) {
596                 g_message ("find-scripts: Failed to open dispatcher directory '%s': %s",
597                            dirname, error->message);
598                 g_error_free (error);
599                 return NULL;
600         }
601
602         while ((filename = g_dir_read_name (dir))) {
603                 char *path;
604                 struct stat     st;
605                 int err;
606                 const char *err_msg = NULL;
607
608                 if (!check_filename (filename))
609                         continue;
610
611                 path = g_build_filename (dirname, filename, NULL);
612
613                 err = stat (path, &st);
614                 if (err)
615                         g_warning ("find-scripts: Failed to stat '%s': %d", path, err);
616                 else if (S_ISDIR (st.st_mode))
617                         ; /* silently skip. */
618                 else if (!check_permissions (&st, &err_msg))
619                         g_warning ("find-scripts: Cannot execute '%s': %s", path, err_msg);
620                 else {
621                         /* success */
622                         sorted = g_slist_insert_sorted (sorted, path, (GCompareFunc) g_strcmp0);
623                         path = NULL;
624                 }
625                 g_free (path);
626         }
627         g_dir_close (dir);
628
629         return sorted;
630 }
631
632 static gboolean
633 script_must_wait (const char *path)
634 {
635         gs_free char *link = NULL;
636         gs_free char *dir = NULL;
637         gs_free char *real = NULL;
638         char *tmp;
639
640         link = g_file_read_link (path, NULL);
641         if (link) {
642                 if (!g_path_is_absolute (link)) {
643                         dir = g_path_get_dirname (path);
644                         tmp = g_build_path ("/", dir, link, NULL);
645                         g_free (link);
646                         g_free (dir);
647                         link = tmp;
648                 }
649
650                 dir = g_path_get_dirname (link);
651                 real = realpath (dir, NULL);
652
653                 if (real && !strcmp (real, NMD_SCRIPT_DIR_NO_WAIT))
654                         return FALSE;
655         }
656
657         return TRUE;
658 }
659
660 static gboolean
661 handle_action (NMDBusDispatcher *dbus_dispatcher,
662                GDBusMethodInvocation *context,
663                const char *str_action,
664                GVariant *connection_dict,
665                GVariant *connection_props,
666                GVariant *device_props,
667                GVariant *device_ip4_props,
668                GVariant *device_ip6_props,
669                GVariant *device_dhcp4_props,
670                GVariant *device_dhcp6_props,
671                const char *vpn_ip_iface,
672                GVariant *vpn_ip4_props,
673                GVariant *vpn_ip6_props,
674                gboolean request_debug,
675                gpointer user_data)
676 {
677         Handler *h = user_data;
678         GSList *sorted_scripts = NULL;
679         GSList *iter;
680         Request *request;
681         char **p;
682         guint i, num_nowait = 0;
683         const char *error_message = NULL;
684
685         sorted_scripts = find_scripts (str_action);
686
687         request = g_slice_new0 (Request);
688         request->request_id = ++request_id_counter;
689         request->handler = h;
690         request->debug = request_debug || debug;
691         request->context = context;
692         request->action = g_strdup (str_action);
693
694         request->envp = nm_dispatcher_utils_construct_envp (str_action,
695                                                             connection_dict,
696                                                             connection_props,
697                                                             device_props,
698                                                             device_ip4_props,
699                                                             device_ip6_props,
700                                                             device_dhcp4_props,
701                                                             device_dhcp6_props,
702                                                             vpn_ip_iface,
703                                                             vpn_ip4_props,
704                                                             vpn_ip6_props,
705                                                             &request->iface,
706                                                             &error_message);
707
708         request->scripts = g_ptr_array_new_full (5, script_info_free);
709         for (iter = sorted_scripts; iter; iter = g_slist_next (iter)) {
710                 ScriptInfo *s;
711
712                 s = g_slice_new0 (ScriptInfo);
713                 s->request = request;
714                 s->script = iter->data;
715                 s->wait = script_must_wait (s->script);
716                 g_ptr_array_add (request->scripts, s);
717         }
718         g_slist_free (sorted_scripts);
719
720         _LOG_R_I (request, "new request (%u scripts)", request->scripts->len);
721         if (   _LOG_R_D_enabled (request)
722             && request->envp) {
723                 for (p = request->envp; *p; p++)
724                         _LOG_R_D (request, "environment: %s", *p);
725         }
726
727         if (error_message || request->scripts->len == 0) {
728                 GVariant *results;
729
730                 if (error_message)
731                         _LOG_R_W (request, "completed: invalid request: %s", error_message);
732                 else
733                         _LOG_R_I (request, "completed: no scripts");
734
735                 results = g_variant_new_array (G_VARIANT_TYPE ("(sus)"), NULL, 0);
736                 g_dbus_method_invocation_return_value (context, g_variant_new ("(@a(sus))", results));
737                 request->num_scripts_done = request->scripts->len;
738                 request_free (request);
739                 return TRUE;
740         }
741
742         nm_clear_g_source (&quit_id);
743
744         h->num_requests_pending++;
745
746         for (i = 0; i < request->scripts->len; i++) {
747                 ScriptInfo *s = g_ptr_array_index (request->scripts, i);
748
749                 if (!s->wait) {
750                         script_dispatch (s);
751                         num_nowait++;
752                 }
753         }
754
755         if (num_nowait < request->scripts->len) {
756                 /* The request has at least one wait script.
757                  * Try next_request() to schedule the request for
758                  * execution. This either enqueues the request or
759                  * sets it as h->current_request. */
760                 if (next_request (h, request)) {
761                         /* @request is now @current_request. Go ahead and
762                          * schedule the first wait script. */
763                         if (!dispatch_one_script (request)) {
764                                 /* If that fails, we might be already finished with the
765                                  * request. Try complete_request(). */
766                                 complete_request (request);
767
768                                 if (next_request (h, NULL)) {
769                                         /* As @request was successfully scheduled as next_request(), there is no
770                                          * other request in queue that can be scheduled afterwards. Assert against
771                                          * that, but call next_request() to clear current_request. */
772                                         g_assert_not_reached ();
773                                 }
774                         }
775                 }
776         } else {
777                 /* The request contains only no-wait scripts. Try to complete
778                  * the request right away (we might have failed to schedule any
779                  * of the scripts). It will be either completed now, or later
780                  * when the pending scripts return.
781                  * We don't enqueue it to h->requests_waiting.
782                  * There is no need to handle next_request(), because @request is
783                  * not the current request anyway and does not interfere with requests
784                  * that have any "wait" scripts. */
785                 complete_request (request);
786         }
787
788         return TRUE;
789 }
790
791 static gboolean ever_acquired_name = FALSE;
792
793 static void
794 on_name_acquired (GDBusConnection *connection,
795                   const char      *name,
796                   gpointer         user_data)
797 {
798         ever_acquired_name = TRUE;
799 }
800
801 static void
802 on_name_lost (GDBusConnection *connection,
803               const char      *name,
804               gpointer         user_data)
805 {
806         if (!connection) {
807                 if (!ever_acquired_name) {
808                         g_warning ("Could not get the system bus.  Make sure the message bus daemon is running!");
809                         exit (1);
810                 } else {
811                         g_message ("System bus stopped. Exiting");
812                         exit (0);
813                 }
814         } else if (!ever_acquired_name) {
815                 g_warning ("Could not acquire the " NM_DISPATCHER_DBUS_SERVICE " service.");
816                 exit (1);
817         } else {
818                 g_message ("Lost the " NM_DISPATCHER_DBUS_SERVICE " name. Exiting");
819                 exit (0);
820         }
821 }
822
823 static void
824 log_handler (const gchar *log_domain,
825              GLogLevelFlags log_level,
826              const gchar *message,
827              gpointer ignored)
828 {
829         int syslog_priority;
830
831         switch (log_level) {
832         case G_LOG_LEVEL_ERROR:
833                 syslog_priority = LOG_CRIT;
834                 break;
835         case G_LOG_LEVEL_CRITICAL:
836                 syslog_priority = LOG_ERR;
837                 break;
838         case G_LOG_LEVEL_WARNING:
839                 syslog_priority = LOG_WARNING;
840                 break;
841         case G_LOG_LEVEL_MESSAGE:
842                 syslog_priority = LOG_NOTICE;
843                 break;
844         case G_LOG_LEVEL_DEBUG:
845                 syslog_priority = LOG_DEBUG;
846                 break;
847         case G_LOG_LEVEL_INFO:
848         default:
849                 syslog_priority = LOG_INFO;
850                 break;
851         }
852
853         syslog (syslog_priority, "%s", message);
854 }
855
856
857 static void
858 logging_setup (void)
859 {
860         openlog (G_LOG_DOMAIN, LOG_CONS, LOG_DAEMON);
861         g_log_set_handler (G_LOG_DOMAIN,
862                            G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
863                            log_handler,
864                            NULL);
865 }
866
867 static void
868 logging_shutdown (void)
869 {
870         closelog ();
871 }
872
873 static gboolean
874 signal_handler (gpointer user_data)
875 {
876         int signo = GPOINTER_TO_INT (user_data);
877
878         g_message ("Caught signal %d, shutting down...", signo);
879         g_main_loop_quit (loop);
880
881         return G_SOURCE_REMOVE;
882 }
883
884 int
885 main (int argc, char **argv)
886 {
887         GOptionContext *opt_ctx;
888         GError *error = NULL;
889         GDBusConnection *bus;
890         Handler *handler;
891
892         GOptionEntry entries[] = {
893                 { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Output to console rather than syslog", NULL },
894                 { "persist", 0, 0, G_OPTION_ARG_NONE, &persist, "Don't quit after a short timeout", NULL },
895                 { NULL }
896         };
897
898         opt_ctx = g_option_context_new (NULL);
899         g_option_context_set_summary (opt_ctx, "Executes scripts upon actions by NetworkManager.");
900         g_option_context_add_main_entries (opt_ctx, entries, NULL);
901
902         if (!g_option_context_parse (opt_ctx, &argc, &argv, &error)) {
903                 g_warning ("Error parsing command line arguments: %s", error->message);
904                 g_error_free (error);
905                 return 1;
906         }
907
908         g_option_context_free (opt_ctx);
909
910         nm_g_type_init ();
911
912         g_unix_signal_add (SIGTERM, signal_handler, GINT_TO_POINTER (SIGTERM));
913         g_unix_signal_add (SIGINT, signal_handler, GINT_TO_POINTER (SIGINT));
914
915
916         if (debug) {
917                 if (!g_getenv ("G_MESSAGES_DEBUG")) {
918                         /* we log our regular messages using g_debug() and g_info().
919                          * When we redirect glib logging to syslog, there is no problem.
920                          * But in "debug" mode, glib will no print these messages unless
921                          * we set G_MESSAGES_DEBUG. */
922                         g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
923                 }
924         } else
925                 logging_setup ();
926
927         loop = g_main_loop_new (NULL, FALSE);
928
929         bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
930         if (!bus) {
931                 g_warning ("Could not get the system bus (%s).  Make sure the message bus daemon is running!",
932                            error->message);
933                 g_error_free (error);
934                 return 1;
935         }
936
937         handler = g_object_new (HANDLER_TYPE, NULL);
938         g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (handler->dbus_dispatcher),
939                                           bus,
940                                           NM_DISPATCHER_DBUS_PATH,
941                                           &error);
942         if (error) {
943                 g_warning ("Could not export Dispatcher D-Bus interface: %s", error->message);
944                 g_error_free (error);
945                 return 1;
946         }
947
948         g_bus_own_name_on_connection (bus,
949                                       NM_DISPATCHER_DBUS_SERVICE,
950                                       G_BUS_NAME_OWNER_FLAGS_NONE,
951                                       on_name_acquired,
952                                       on_name_lost,
953                                       NULL, NULL);
954         g_object_unref (bus);
955
956         quit_timeout_reschedule ();
957
958         g_main_loop_run (loop);
959
960         g_queue_free (handler->requests_waiting);
961         g_object_unref (handler);
962
963         if (!debug)
964                 logging_shutdown ();
965
966         return 0;
967 }
968