~ubuntu-core-dev/update-notifier/ubuntu

« back to all changes in this revision

Viewing changes to src/update-notifier.c

  • Committer: Michael Vogt
  • Date: 2008-11-10 18:04:02 UTC
  • Revision ID: michael.vogt@ubuntu.com-20081110180402-lvolg0ct1xr4vqoi
* debian/update-notifier-common.install:
  - move apt-check, apt-cdrom-check and cdromdistupgrade
    into update-notifier-common

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * Copyright (C) 2004 Lukas Lipka <lukas@pmad.net>
3
3
 *           (C) 2004 Michael Vogt <mvo@debian.org>
4
4
 *           (C) 2004 Michiel Sikkes <michiel@eyesopened.nl>
5
 
 *           (C) 2004-2009 Canonical
 
5
 *           (C) 2004-2006 Canonical
6
6
 *
7
7
 * This library is free software; you can redistribute it and/or
8
8
 * modify it under the terms of the GNU Lesser General Public
16
16
 *
17
17
 * You should have received a copy of the GNU Lesser General Public
18
18
 * License along with this library; if not, write to the
19
 
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor
20
 
 * Boston, MA  02110-1301 USA.
 
19
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
20
 * Boston, MA 02111-1307, USA.
21
21
 */
22
22
 
23
23
#ifdef HAVE_CONFIG_H
24
24
#include "config.h"
25
25
#endif
26
26
 
27
 
#include <unistd.h>
28
 
#include <sys/types.h>
29
 
#include <stdlib.h>
30
27
#include <signal.h>
31
28
#include <grp.h>
32
29
#include <pwd.h>
34
31
#include <glib.h>
35
32
#include <glib/gstdio.h>
36
33
#include <gtk/gtk.h>
37
 
#include <gdk/gdkx.h>
 
34
#include <glade/glade.h>
38
35
#include <gio/gio.h>
39
36
 
40
37
#include "update-notifier.h"
 
38
#include "hal.h"
41
39
#include "update.h"
42
40
#include "hooks.h"
43
 
#include "gdu.h"
44
41
#include "reboot.h"
45
 
#include "uevent.h"
46
42
#include "crash.h"
47
43
#include "avahi.h"
48
44
 
59
55
 
60
56
// the timeout (in sec) when a further activity from dpkg/apt
61
57
// causes the applet to "ungray"
62
 
#define TIMEOUT_APT_RUN 600 /* 600 sec */
 
58
#define TIMEOUT_APT_RUN 120 /* 120 sec */
63
59
 
64
 
// force startup even if the user is not in the admin group
 
60
// force statup even if the user is not in the admin group
65
61
static gboolean FORCE_START=FALSE;
66
62
 
67
63
// force gksu for all menu actions
68
64
static gboolean FORCE_GKSU=FALSE;
69
65
 
70
66
// delay on startup (to make session startup faster)
71
 
static int STARTUP_DELAY=1;
72
 
 
73
 
// make the release upgrader check for a devel release
74
 
gboolean DEVEL_RELEASE=FALSE;
75
 
 
76
 
// force release check
77
 
static gboolean FORCE_RELEASE_CHECK=FALSE;
78
 
 
79
 
// global debug options
80
 
int HOOK_DEBUG = 0;
81
 
int UPDATE_DEBUG = 0;
82
 
int INOTIFY_DEBUG = 0;
83
 
int UEVENT_DEBUG = 0;
84
 
int RELEASE_DEBUG = 0;
85
 
int MISC_DEBUG = 0;
86
 
 
87
 
// logging stuff
88
 
static void debug_log_handler (const gchar   *log_domain,
89
 
                              GLogLevelFlags log_level,
90
 
                              const gchar   *message,
91
 
                              gpointer       user_data)
92
 
{
93
 
   if (log_domain && strcmp(log_domain, "hooks") == 0) {
94
 
      if (HOOK_DEBUG > 0)
95
 
         g_log_default_handler (log_domain, log_level, message, user_data);
96
 
   }
97
 
   else if (log_domain && strcmp(log_domain, "update") == 0) {
98
 
      if (UPDATE_DEBUG > 0)
99
 
         g_log_default_handler (log_domain, log_level, message, user_data);
100
 
   }
101
 
   else if (log_domain && strcmp(log_domain, "inotify") == 0) {
102
 
      if (INOTIFY_DEBUG > 0) 
103
 
          g_log_default_handler (log_domain, log_level, message, user_data);
104
 
   }
105
 
   else if (log_domain && strcmp(log_domain, "uevent") == 0) {
106
 
      if (UEVENT_DEBUG > 0)
107
 
         g_log_default_handler (log_domain, log_level, message, user_data);
108
 
   }
109
 
   else if (log_domain && strcmp(log_domain, "release") == 0) {
110
 
      if (RELEASE_DEBUG > 0)
111
 
         g_log_default_handler (log_domain, log_level, message, user_data);
112
 
   }
113
 
   else if (MISC_DEBUG > 0)
114
 
      g_log_default_handler (log_domain, log_level, message, user_data);
115
 
}
116
 
 
117
 
static inline void
118
 
g_debug_inotify(const char *msg, ...)
119
 
{
120
 
   va_list va;
121
 
   va_start(va, msg);
122
 
   g_logv("inotify",G_LOG_LEVEL_DEBUG, msg, va);
123
 
   va_end(va);
124
 
}
125
 
 
126
 
// launch async scripts one after another
127
 
static void start_next_script(GPid pid,
128
 
                              gint status,
129
 
                              GSList *remaining_scripts_to_run)
130
 
{
131
 
    if(remaining_scripts_to_run) {
132
 
        gboolean     ret = False;
133
 
        gchar*       full_path = remaining_scripts_to_run->data;
134
 
        gchar       *argv[] = { full_path, NULL };
135
 
 
136
 
        g_debug_inotify ("executing: %s\n", full_path);
137
 
        if (g_file_test(full_path, G_FILE_TEST_IS_EXECUTABLE ))
138
 
            ret = g_spawn_async("/", argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL);
139
 
        remaining_scripts_to_run = g_slist_remove(remaining_scripts_to_run, full_path);
140
 
        g_free(full_path);
141
 
        if(!ret)
142
 
        {
143
 
            g_warning("script execution failed or not executable");
144
 
            start_next_script(0, 0, remaining_scripts_to_run);
145
 
            return;
146
 
        }
147
 
        g_child_watch_add(pid, (GChildWatchFunc)start_next_script, remaining_scripts_to_run);
148
 
    }
149
 
 
150
 
}
151
 
 
152
 
void invoke(const gchar *cmd, const gchar *desktop, gboolean with_gksu)
153
 
{
154
 
   GdkAppLaunchContext *context;
155
 
   GAppInfo *appinfo;
156
 
   GError *error = NULL;
157
 
   static GtkWidget *w = NULL;
158
 
 
159
 
   // gksu
160
 
   if(with_gksu || FORCE_GKSU) {
 
67
static int STARTUP_DELAY=5;
 
68
 
 
69
void invoke(gchar *cmd, gchar *desktop, gboolean with_gksu)
 
70
{
 
71
   if(with_gksu || FORCE_GKSU)
161
72
      invoke_with_gksu(cmd, desktop, FALSE);
162
 
      return;
163
 
   }
164
 
 
165
 
   // fake window to get the current server time *urgh*
166
 
   if (!w) {
167
 
      w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
168
 
      gtk_widget_realize (w);
169
 
   }
170
 
 
171
 
   // normal launch
172
 
   context = gdk_app_launch_context_new ();
173
 
   guint32 timestamp =  gdk_x11_get_server_time (gtk_widget_get_window (w));
174
 
   appinfo = g_app_info_create_from_commandline(cmd, 
175
 
                                                cmd, 
176
 
                                                G_APP_INFO_CREATE_NONE,
177
 
                                                &error);
178
 
   gdk_app_launch_context_set_timestamp (context, timestamp);
179
 
   if (!g_app_info_launch (appinfo, NULL, (GAppLaunchContext*)context, &error))
180
 
      g_warning ("Launching failed: %s\n", error->message);
181
 
   g_object_unref (context);
182
 
   g_object_unref (appinfo);
183
 
 
 
73
   else
 
74
      g_spawn_command_line_async(cmd, NULL);
184
75
}
185
76
 
186
77
void
187
 
invoke_with_gksu(const gchar *cmd, const gchar *descr, gboolean whole_message)
 
78
invoke_with_gksu(gchar *cmd, gchar *descr, gboolean whole_message)
188
79
{
189
 
        g_debug("invoke_update_manager ()\n");
190
 
        gchar *argv[5];
 
80
        //g_print("invoke_update_manager ()\n");
 
81
        gchar *argv[5];
191
82
        argv[0] = "/usr/bin/gksu";
192
83
        argv[1] = whole_message ? "--message" : "--desktop";
193
 
        argv[2] = (gchar*)descr;
194
 
        argv[3] = (gchar*)cmd;
 
84
        argv[2] = descr;
 
85
        argv[3] = cmd;
195
86
        argv[4] = NULL;
196
87
 
197
88
        g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, NULL);
202
93
gboolean
203
94
trayapplet_create (TrayApplet *un, char *name)
204
95
{
205
 
        g_debug("trayicon_create()\n");
 
96
        //g_print("trayicon_create()\n");
206
97
 
207
98
        /* setup widgets */
208
99
        un->tray_icon = gtk_status_icon_new_from_icon_name (name);
236
127
 
237
128
   gchar *info_uri = g_file_get_path(monitor_f);
238
129
#if 0
239
 
   g_debug_inotify("info_uri: %s\n", info_uri);
240
 
   g_debug_inotify("event_type: %i\n",event_type);
 
130
   g_print("info_uri: %s\n", info_uri);
 
131
   g_print("event_type: %i\n",event_type);
241
132
#endif
242
133
 
243
134
   // we ignore lock file events because we can only get 
249
140
   if(g_str_has_prefix(info_uri,"/var/lib/apt/") 
250
141
      || g_str_has_prefix(info_uri,"/var/cache/apt/")
251
142
      || strcmp(info_uri,"/var/lib/dpkg/status") == 0) {
252
 
      g_debug_inotify("apt_get_running=TRUE");
253
143
      un->apt_get_runing=TRUE;
254
144
   } 
255
145
   if(strstr(info_uri, "/var/lib/update-notifier/dpkg-run-stamp") ||
256
146
      strstr(info_uri, "/var/lib/apt/periodic/update-success-stamp")) {
257
 
      g_debug_inotify("dpkg_was_run=TRUE");
258
147
      un->dpkg_was_run = TRUE;
259
148
   } 
260
149
   if(strstr(info_uri, REBOOT_FILE)) {
261
 
      g_debug_inotify("reboot required\n");
 
150
      //g_print("reboot required\n");
262
151
      un->reboot_pending = TRUE;
263
152
   }
264
153
   if(strstr(info_uri, HOOKS_DIR)) {
265
 
      g_debug_inotify("new hook!\n");
 
154
      //g_print("new hook!\n");
266
155
      un->hook_pending = TRUE;
267
156
   }
268
157
   if(strstr(info_uri, CRASHREPORT_DIR)) {
269
 
      g_debug_inotify("crashreport found\n");
 
158
      //g_print("crashreport found\n");
270
159
      un->crashreport_pending = TRUE;
271
160
   }
272
161
   if(strstr(info_uri, UNICAST_LOCAL_AVAHI_FILE)) {
273
 
      g_debug_inotify("avahi disabled due to unicast .local domain\n");
 
162
      //g_print("avahi disabled due to unicast .local domain\n");
274
163
      un->unicast_local_avahi_pending = TRUE;
275
164
   }
276
165
}
303
192
      // check updates
304
193
      update_check(un->update);
305
194
 
306
 
      // run cache-changed plugin scripts
307
 
      GDir *dir = g_dir_open(CACHE_CHANGED_PLUGIN_DIR, 0, NULL);
308
 
      const gchar *fname, *full_path;
309
 
      GSList *cache_changed_scripts = NULL;
310
 
      while ( (fname = g_dir_read_name(dir)) != NULL ) {
311
 
        full_path = g_build_filename(CACHE_CHANGED_PLUGIN_DIR, fname, NULL);
312
 
        cache_changed_scripts = g_slist_insert_sorted(cache_changed_scripts,
313
 
                                 (gpointer)full_path, (GCompareFunc)g_strcmp0);
314
 
      }
315
 
      // launch first script and queue others
316
 
      start_next_script(0, 0, cache_changed_scripts);
317
 
 
318
195
      // any apt-get update  must be finished, otherwise 
319
196
      // apt-get install wouldn't be finished
320
197
      update_apt_is_running(un->update, FALSE);
362
239
   }
363
240
 
364
241
   if(un->crashreport_pending) {
365
 
      g_debug("checking for valid crashreport now\n");
 
242
      g_print("checking for valid crashreport now\n");
366
243
      crashreport_check (un->crashreport);
367
244
      un->crashreport_pending = FALSE;
368
245
   }
369
246
 
370
247
   if(un->unicast_local_avahi_pending) {
371
 
      g_debug("checking for disabled avahi due to unicast .local domain now\n");
 
248
      g_print("checking for disabled avahi due to unicast .local domain now\n");
372
249
      avahi_disabled_check ();
373
250
      un->unicast_local_avahi_pending = FALSE;
374
251
   }
387
264
 * End user might not understand the message at all */
388
265
void u_abort(gchar *msg)
389
266
{
390
 
   const char *fmt = "<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n";
391
 
   gtk_dialog_run(GTK_DIALOG(gtk_message_dialog_new_with_markup(NULL, 0,
 
267
   msg = g_strdup_printf("<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n", _("Internal error"), msg);
 
268
   gtk_dialog_run(GTK_DIALOG(gtk_message_dialog_new_with_markup(NULL,0,
392
269
                                                     GTK_MESSAGE_ERROR,
393
270
                                                     GTK_BUTTONS_CLOSE,
394
 
                                                     fmt,
395
 
                                                     _("Internal error"),
396
271
                                                     msg)));
397
272
   g_free(msg);
398
273
   exit(1);
399
274
}
400
275
 
401
276
// FIXME: get the apt directories with apt-config or something
402
 
gboolean 
403
 
monitor_init(UpgradeNotifier *un)
 
277
gboolean monitor_init(UpgradeNotifier *un)
404
278
{
405
279
   int i;
406
280
   GFileMonitor *monitor_handle;
413
287
      CRASHREPORT_DIR,
414
288
      NULL};
415
289
   for(i=0;monitor_dirs[i] != NULL;i++) {
416
 
      GError *error = NULL;
 
290
      GError err;
417
291
      GFile *gf = g_file_new_for_path(monitor_dirs[i]);
418
 
      monitor_handle = g_file_monitor_directory(gf, 0, NULL, &error);
 
292
      monitor_handle = g_file_monitor_directory(gf, 0, NULL, &err);
419
293
      if(monitor_handle)
420
 
         g_signal_connect(monitor_handle, "changed", (GCallback)monitor_cb, un);
 
294
         g_signal_connect(monitor_handle, "changed", monitor_cb, un);
421
295
      else
422
296
         g_warning("can not add '%s'\n", monitor_dirs[i]);
423
297
   }
431
305
      UNICAST_LOCAL_AVAHI_FILE,
432
306
      NULL};
433
307
   for(i=0;monitor_files[i] != NULL;i++) {
434
 
      GError *error = NULL;
 
308
      GError err;
435
309
      GFile *gf = g_file_new_for_path(monitor_files[i]);
436
 
      monitor_handle = g_file_monitor_file(gf, 0, NULL, &error);
 
310
      monitor_handle = g_file_monitor_file(gf, 0, NULL, &err);
437
311
      if(monitor_handle)
438
 
         g_signal_connect(monitor_handle, "changed", (GCallback)monitor_cb, un);
 
312
         g_signal_connect(monitor_handle, "changed", monitor_cb, un);
439
313
      else
440
314
         g_warning("can not add '%s'\n", monitor_dirs[i]);
441
315
   }
452
326
static gboolean
453
327
tray_icons_init(UpgradeNotifier *un)
454
328
{
455
 
   //g_debug_inotify("tray_icons_init");
 
329
   //g_debug("tray_icons_init");
456
330
 
457
331
   /* new upates tray icon */
458
332
   un->update = g_new0 (TrayApplet, 1);
488
362
   /* do not start for system users, e.g. the guest session 
489
363
    * (see /usr/share/gdm/guest-session/guest-session-setup.sh)
490
364
    */
491
 
   int end_system_uid = 500;
492
 
   GConfClient *gconf = gconf_client_get_default();
493
 
   if (gconf) {
494
 
      int i = gconf_client_get_int(gconf, GCONF_KEY_END_SYSTEM_UIDS, NULL);
495
 
      if (i>0)
496
 
         end_system_uid = i;
497
 
   }
498
 
 
499
365
   uid_t uid = getuid();
500
 
   if (uid < end_system_uid)
 
366
   if (uid < 500)
501
367
      return TRUE;
502
368
   return FALSE;
503
369
}
540
406
static GOptionEntry entries[] = 
541
407
{
542
408
   { "debug-hooks", 0, 0, G_OPTION_ARG_NONE, &HOOK_DEBUG, "Enable hooks debugging"},
543
 
   { "debug-updates", 0, 0, G_OPTION_ARG_NONE, &UPDATE_DEBUG, "Enable updates/autolaunch debugging"},
544
 
   { "debug-inotify", 0, 0, G_OPTION_ARG_NONE, &INOTIFY_DEBUG, "Enable inotify debugging"},
545
 
   { "debug-uevent", 0, 0, G_OPTION_ARG_NONE, &UEVENT_DEBUG, "Enable uevent debugging"},
546
 
   { "debug-new-release-check", 0, 0, G_OPTION_ARG_NONE, &RELEASE_DEBUG, "Enable new release check debugging"},
547
 
   { "debug-misc", 0, 0, G_OPTION_ARG_NONE, &MISC_DEBUG, "Enable uncategorized debug prints"},
548
409
   { "force", 0, 0, G_OPTION_ARG_NONE, &FORCE_START, "Force start even if the user is not in the admin group"},
549
410
   { "force-use-gksu", 0, 0, G_OPTION_ARG_NONE, &FORCE_GKSU, "Force running all commands (update-manager, synaptic) with gksu" },
550
 
   { "startup-delay", 0, 0, G_OPTION_ARG_INT, &STARTUP_DELAY, "Delay startup by given amount of seconds" },
551
 
   { "devel-release", 0, 0, G_OPTION_ARG_NONE, &DEVEL_RELEASE, "Make the release checker check for a new development release" },
552
 
   { "force-release-check", 0, 0, G_OPTION_ARG_NONE, &FORCE_RELEASE_CHECK, "Force release check" },
 
411
   { "startup-delay", 0, 0, G_OPTION_ARG_INT, &STARTUP_DELAY, "Delay statup by given amount of seconds" },
553
412
   { NULL }
554
413
};
555
414
 
556
415
int 
557
 
main (int argc, char **argv)
 
416
main (int argc, char *argv[])
558
417
{
559
418
        UpgradeNotifier *un;
560
 
        GError *error = NULL;
561
419
 
562
 
        // init
563
 
        if(!gtk_init_with_args (&argc, &argv, 
564
 
                                _("- inform about updates"), entries, 
565
 
                                "update-notifier", &error) ) {
566
 
           fprintf(stderr, _("Failed to init the UI: %s\n"), 
567
 
                   error ? error->message : _("unknown error"));
568
 
           exit(1);
569
 
        }
 
420
        // option parsing
 
421
        GOptionContext *context;
 
422
        context = g_option_context_new (" - inform about updates");
 
423
        g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
 
424
        gtk_init_with_args (&argc, &argv, "",
 
425
                            entries, PACKAGE, NULL);
570
426
 
571
427
        notify_init("update-notifier");
572
428
        bindtextdomain(PACKAGE, PACKAGE_LOCALE_DIR);
573
429
        bind_textdomain_codeset(PACKAGE, "UTF-8");
574
430
        textdomain(PACKAGE);
575
431
 
576
 
        // setup a custom debug log handler
577
 
        g_log_set_handler ("inotify", G_LOG_LEVEL_DEBUG,
578
 
                           debug_log_handler, NULL);
579
 
        g_log_set_handler ("hooks", G_LOG_LEVEL_DEBUG,
580
 
                           debug_log_handler, NULL);
581
 
        g_log_set_handler ("update", G_LOG_LEVEL_DEBUG,
582
 
                           debug_log_handler, NULL);
583
 
        g_log_set_handler ("uevent", G_LOG_LEVEL_DEBUG,
584
 
                           debug_log_handler, NULL);
585
 
        g_log_set_handler ("release", G_LOG_LEVEL_DEBUG,
586
 
                           debug_log_handler, NULL);
587
 
        g_log_set_handler (NULL, G_LOG_LEVEL_DEBUG,
588
 
                           debug_log_handler, NULL);
589
 
 
590
432
        g_set_application_name (_("update-notifier"));
591
433
        gtk_window_set_default_icon_name ("update-notifier");
592
434
 
593
435
        //g_print("starting update-notifier\n");
594
436
 
595
437
        // do not run as system user (e.g. guest user)
596
 
        if (system_user() && !FORCE_START) {
 
438
        if (system_user()) {
597
439
           g_warning("not starting for system user\n");
598
440
           exit(0);
599
441
        }
600
442
 
601
 
        // do not run as system user (e.g. guest user)
602
 
        if (FORCE_RELEASE_CHECK) {
603
 
           GConfClient *gconf = gconf_client_get_default();
604
 
           gconf_client_unset(gconf, GCONF_KEY_LAST_RELEASE_CHECK, NULL);
605
 
        }
606
 
 
607
443
        // check if it is running already
608
444
        if (!up_get_clipboard ()) {
609
445
           g_warning ("already running?\n");
613
449
        /* Create the UpgradeNotifier object */
614
450
        un = g_new0 (UpgradeNotifier, 1);
615
451
 
616
 
        // check for update-notifier dir and create if needed
617
 
        gchar *dirname = g_strdup_printf("%s/update-notifier",
618
 
                                         g_get_user_config_dir());
 
452
        // check for .update-notifier dir and create if needed
 
453
        gchar *dirname = g_strdup_printf("%s/.update-notifier",
 
454
                                         g_get_home_dir());
619
455
        if(!g_file_test(dirname, G_FILE_TEST_IS_DIR))
620
456
           g_mkdir(dirname, 0700);
621
457
        g_free(dirname);
622
458
 
623
459
        // delay icon creation for 30s so that the desktop 
624
460
        // login is not slowed down by update-notifier
625
 
        g_timeout_add_seconds(STARTUP_DELAY, 
626
 
                              (GSourceFunc)(tray_icons_init), un);
 
461
        g_timeout_add_seconds(STARTUP_DELAY, (GSourceFunc)(tray_icons_init), un);
627
462
 
628
463
        // initial check for avahi
629
464
        avahi_disabled_check();
630
 
        
 
465
 
 
466
        // init hal (needs to be done _after_ the icons are created)
631
467
        /* setup hal so that inserted cdroms can be checked */
632
 
        if(!up_do_hal_init(un)) {
633
 
           g_warning("initializing gdu failed");
 
468
        LibHalContext *hal_ctx = up_do_hal_init();
 
469
        if (!hal_ctx) {
 
470
           u_abort("failed to initialize HAL!\n");
 
471
           return 1;
634
472
        }
635
 
 
636
 
        // init release checker
637
 
        release_checker_init();
638
 
 
639
 
        // init uevent monitoring (missing firmware, etc.)
640
 
        uevent_init();
641
 
 
642
 
        // init gio file monitoring
643
 
        monitor_init (un);
 
473
        libhal_ctx_set_user_data(hal_ctx, un);
 
474
        
 
475
        // init fam
 
476
        monitor_init(un);
644
477
        
645
478
        /* Start the main gtk loop */
646
479
        gtk_main ();