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

« back to all changes in this revision

Viewing changes to src/update-notifier.c

  • Committer: Julian Andres Klode
  • Date: 2020-01-28 09:54:52 UTC
  • Revision ID: juliank@ubuntu.com-20200128095452-g0q3a1xg75a7k56j
Replace pep8 with pycodestyle

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
#include <sys/types.h>
29
29
#include <stdlib.h>
30
30
#include <signal.h>
 
31
#include <errno.h>
 
32
#include <sys/file.h>
31
33
#include <grp.h>
32
34
#include <pwd.h>
33
35
#include <limits.h>
34
36
#include <glib.h>
35
37
#include <glib/gstdio.h>
 
38
#include <glib-unix.h>
36
39
#include <gtk/gtk.h>
37
40
#include <gdk/gdkx.h>
38
41
#include <gio/gio.h>
39
42
 
40
43
#include "update-notifier.h"
 
44
#include "livepatch-tray.h"
41
45
#include "update.h"
42
46
#include "hooks.h"
43
 
#include "gdu.h"
44
 
#include "reboot.h"
45
 
#include "firmware.h"
 
47
#include "uevent.h"
46
48
#include "crash.h"
47
 
#include "avahi.h"
 
49
#include "release.h"
 
50
#include "trayappletui.h"
48
51
 
49
52
/* some prototypes */
50
 
extern gboolean up_get_clipboard (void);
51
53
gboolean update_timer_finished(gpointer data);
52
54
 
53
 
// the time when we check for fam events
54
 
#define TIMEOUT_FAM 1000*5 /* 5 sec */
55
 
 
56
 
// the timeout (in msec) for apt-get update (changes in 
57
 
// /var/lib/apt/lists{/partial})
58
 
#define TIMEOUT_APT_GET_UPDATE 1000*30 /* 30 sec */
 
55
// the time when we check for fam events, in seconds
 
56
#define TIMEOUT_FAM 180
59
57
 
60
58
// the timeout (in sec) when a further activity from dpkg/apt
61
59
// causes the applet to "ungray"
62
60
#define TIMEOUT_APT_RUN 600 /* 600 sec */
63
61
 
64
 
// force startup even if the user is not in the admin group
 
62
// force startup even if the user is not in the sudo/admin group
65
63
static gboolean FORCE_START=FALSE;
66
64
 
67
 
// force gksu for all menu actions
68
 
static gboolean FORCE_GKSU=FALSE;
 
65
// force pkexec for all menu actions
 
66
static gboolean FORCE_PKEXEC=FALSE;
69
67
 
70
68
// delay on startup (to make session startup faster)
71
69
static int STARTUP_DELAY=1;
77
75
static gboolean FORCE_RELEASE_CHECK=FALSE;
78
76
 
79
77
// global debug options
80
 
int HOOK_DEBUG = 0;
81
 
int UPDATE_DEBUG = 0;
82
 
int INOTIFY_DEBUG = 0;
83
 
int FIRMWARE_DEBUG = 0;
84
 
int RELEASE_DEBUG = 0;
 
78
static gboolean HOOK_DEBUG = FALSE;
 
79
static gboolean UPDATE_DEBUG = FALSE;
 
80
static gboolean INOTIFY_DEBUG = FALSE;
 
81
static gboolean UEVENT_DEBUG = FALSE;
 
82
static gboolean RELEASE_DEBUG = FALSE;
 
83
static gboolean MISC_DEBUG = FALSE;
85
84
 
86
85
// logging stuff
87
86
static void debug_log_handler (const gchar   *log_domain,
89
88
                              const gchar   *message,
90
89
                              gpointer       user_data)
91
90
{
92
 
   if (HOOK_DEBUG > 0 && strcmp(log_domain, "hooks") == 0)
93
 
       g_log_default_handler (log_domain, log_level, message, user_data);
94
 
   if (UPDATE_DEBUG > 0 && strcmp(log_domain, "update") == 0)
95
 
       g_log_default_handler (log_domain, log_level, message, user_data);
96
 
   if (INOTIFY_DEBUG > 0 && strcmp(log_domain, "inotify") == 0)
97
 
       g_log_default_handler (log_domain, log_level, message, user_data);
98
 
   if (FIRMWARE_DEBUG > 0 && strcmp(log_domain, "firmware") == 0)
99
 
       g_log_default_handler (log_domain, log_level, message, user_data);
100
 
   if (RELEASE_DEBUG > 0 && strcmp(log_domain, "release") == 0)
101
 
       g_log_default_handler (log_domain, log_level, message, user_data);
 
91
   if (log_domain && strcmp(log_domain, "hooks") == 0) {
 
92
      if (HOOK_DEBUG)
 
93
         g_log_default_handler (log_domain, log_level, message, user_data);
 
94
   }
 
95
   else if (log_domain && strcmp(log_domain, "update") == 0) {
 
96
      if (UPDATE_DEBUG)
 
97
         g_log_default_handler (log_domain, log_level, message, user_data);
 
98
   }
 
99
   else if (log_domain && strcmp(log_domain, "inotify") == 0) {
 
100
      if (INOTIFY_DEBUG)
 
101
          g_log_default_handler (log_domain, log_level, message, user_data);
 
102
   }
 
103
   else if (log_domain && strcmp(log_domain, "uevent") == 0) {
 
104
      if (UEVENT_DEBUG)
 
105
         g_log_default_handler (log_domain, log_level, message, user_data);
 
106
   }
 
107
   else if (log_domain && strcmp(log_domain, "release") == 0) {
 
108
      if (RELEASE_DEBUG)
 
109
         g_log_default_handler (log_domain, log_level, message, user_data);
 
110
   }
 
111
   else if (MISC_DEBUG)
 
112
      g_log_default_handler (log_domain, log_level, message, user_data);
102
113
}
103
114
 
104
115
static inline void
110
121
   va_end(va);
111
122
}
112
123
 
113
 
void invoke(const gchar *cmd, const gchar *desktop, gboolean with_gksu)
 
124
// launch async scripts one after another
 
125
static void start_next_script(GPid pid,
 
126
                              gint status,
 
127
                              GSList *remaining_scripts_to_run)
 
128
{
 
129
    if(remaining_scripts_to_run) {
 
130
        gboolean     ret = False;
 
131
        gchar*       full_path = remaining_scripts_to_run->data;
 
132
        gchar       *argv[] = { full_path, NULL };
 
133
 
 
134
        g_debug_inotify ("executing: %s", full_path);
 
135
        if (g_file_test(full_path, G_FILE_TEST_IS_EXECUTABLE ))
 
136
            ret = g_spawn_async("/", argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL);
 
137
        remaining_scripts_to_run = g_slist_remove(remaining_scripts_to_run, full_path);
 
138
        g_free(full_path);
 
139
        if(!ret)
 
140
        {
 
141
            g_warning("script execution failed or not executable");
 
142
            start_next_script(0, 0, remaining_scripts_to_run);
 
143
            return;
 
144
        }
 
145
        g_child_watch_add(pid, (GChildWatchFunc)start_next_script, remaining_scripts_to_run);
 
146
    }
 
147
 
 
148
}
 
149
 
 
150
void invoke(const gchar *cmd, const gchar *desktop, gboolean with_pkexec)
114
151
{
115
152
   GdkAppLaunchContext *context;
116
153
   GAppInfo *appinfo;
117
154
   GError *error = NULL;
118
155
   static GtkWidget *w = NULL;
119
156
 
120
 
   // gksu
121
 
   if(with_gksu || FORCE_GKSU) {
122
 
      invoke_with_gksu(cmd, desktop, FALSE);
 
157
   // pkexec
 
158
   if(with_pkexec || FORCE_PKEXEC) {
 
159
      invoke_with_pkexec(cmd);
123
160
      return;
124
161
   }
125
162
 
130
167
   }
131
168
 
132
169
   // normal launch
133
 
   context = gdk_app_launch_context_new ();
134
 
   guint32 timestamp =  gdk_x11_get_server_time (w->window);
 
170
   context = gdk_display_get_app_launch_context (gdk_display_get_default ());
 
171
   guint32 timestamp =  gdk_x11_get_server_time (gtk_widget_get_window (w));
135
172
   appinfo = g_app_info_create_from_commandline(cmd, 
136
173
                                                cmd, 
137
174
                                                G_APP_INFO_CREATE_NONE,
138
175
                                                &error);
139
176
   gdk_app_launch_context_set_timestamp (context, timestamp);
140
177
   if (!g_app_info_launch (appinfo, NULL, (GAppLaunchContext*)context, &error))
141
 
      g_warning ("Launching failed: %s\n", error->message);
 
178
      g_warning ("Launching failed: %s", error->message);
142
179
   g_object_unref (context);
143
180
   g_object_unref (appinfo);
144
181
 
145
182
}
146
183
 
147
184
void
148
 
invoke_with_gksu(const gchar *cmd, const gchar *descr, gboolean whole_message)
149
 
{
150
 
        //g_print("invoke_update_manager ()\n");
151
 
        gchar *argv[5];
152
 
        argv[0] = "/usr/bin/gksu";
153
 
        argv[1] = whole_message ? "--message" : "--desktop";
154
 
        argv[2] = (gchar*)descr;
155
 
        argv[3] = (gchar*)cmd;
156
 
        argv[4] = NULL;
157
 
 
158
 
        g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, NULL);
159
 
}
160
 
 
161
 
 
162
 
 
163
 
gboolean
164
 
trayapplet_create (TrayApplet *un, char *name)
165
 
{
166
 
        //g_print("trayicon_create()\n");
167
 
 
168
 
        /* setup widgets */
169
 
        un->tray_icon = gtk_status_icon_new_from_icon_name (name);
170
 
        un->name = name;
171
 
        gtk_status_icon_set_visible (un->tray_icon, FALSE);
 
185
invoke_with_pkexec(const gchar *cmd)
 
186
{
 
187
        g_debug("invoke_with_pkexec ()");
 
188
        gchar *argv[3];
 
189
        argv[0] = "/usr/bin/pkexec";
 
190
        argv[1] = (gchar*)cmd;
 
191
        argv[2] = NULL;
 
192
        g_spawn_async (NULL, argv, NULL, G_SPAWN_DEFAULT, NULL, NULL, NULL, NULL);
 
193
}
 
194
 
 
195
void
 
196
avahi_disabled()
 
197
{
 
198
        g_debug("avahi disabled ()");
 
199
        gchar *argv[2];
 
200
        argv[0] = "/usr/lib/update-notifier/local-avahi-notification";
 
201
        argv[1] = NULL;
 
202
        g_spawn_async (NULL, argv, NULL, G_SPAWN_DEFAULT, NULL, NULL, NULL, NULL);
 
203
}
 
204
 
 
205
void livepatch_check()
 
206
{
 
207
        g_debug("livepatch_check ()");
 
208
        gchar *argv[2];
 
209
        argv[0] = "/usr/lib/update-notifier/livepatch-notification";
 
210
        argv[1] = NULL;
 
211
        g_spawn_async (NULL, argv, NULL, G_SPAWN_DEFAULT, NULL, NULL, NULL, NULL);
 
212
}
 
213
 
 
214
static gboolean
 
215
trayapplet_create (TrayApplet *ta, UpgradeNotifier *un, char *name)
 
216
{
 
217
        g_debug("trayapplet_create()");
 
218
 
 
219
        ta->un = un;
 
220
        ta->name = name;
172
221
 
173
222
        return TRUE;
174
223
}
175
224
 
176
 
 
177
225
/* 
178
226
 the following files change:
179
227
 on "install":
186
234
  - /var/lib/dpkg/lock
187
235
  - /var/lib/apt/periodic/update-success-stamp
188
236
*/
189
 
void
 
237
static void
190
238
monitor_cb(GFileMonitor *handle,
191
239
           GFile *monitor_f,
192
240
           GFile *other_monitor_f,
197
245
 
198
246
   gchar *info_uri = g_file_get_path(monitor_f);
199
247
#if 0
200
 
   g_debug_inotify("info_uri: %s\n", info_uri);
201
 
   g_debug_inotify("event_type: %i\n",event_type);
 
248
   g_debug_inotify("info_uri: %s", info_uri);
 
249
   g_debug_inotify("event_type: %i",event_type);
202
250
#endif
203
251
 
204
 
   // we ignore lock file events because we can only get 
 
252
   // we ignore lock file events because we can only get
205
253
   // when a lock was taken, but not when it was removed
206
254
   if(g_str_has_suffix(info_uri, "lock"))
207
255
      return;
208
256
 
209
257
   // look for apt-get install/update
210
 
   if(g_str_has_prefix(info_uri,"/var/lib/apt/") 
 
258
   if(g_str_has_prefix(info_uri,"/var/lib/apt/")
211
259
      || g_str_has_prefix(info_uri,"/var/cache/apt/")
212
260
      || strcmp(info_uri,"/var/lib/dpkg/status") == 0) {
213
261
      g_debug_inotify("apt_get_running=TRUE");
214
 
      un->apt_get_runing=TRUE;
215
 
   } 
 
262
      un->apt_get_running=TRUE;
 
263
   }
216
264
   if(strstr(info_uri, "/var/lib/update-notifier/dpkg-run-stamp") ||
217
265
      strstr(info_uri, "/var/lib/apt/periodic/update-success-stamp")) {
218
266
      g_debug_inotify("dpkg_was_run=TRUE");
219
267
      un->dpkg_was_run = TRUE;
220
 
   } 
221
 
   if(strstr(info_uri, REBOOT_FILE)) {
222
 
      g_debug_inotify("reboot required\n");
223
 
      un->reboot_pending = TRUE;
224
268
   }
225
269
   if(strstr(info_uri, HOOKS_DIR)) {
226
 
      g_debug_inotify("new hook!\n");
 
270
      g_debug_inotify("new hook!");
227
271
      un->hook_pending = TRUE;
228
272
   }
229
273
   if(strstr(info_uri, CRASHREPORT_DIR)) {
230
 
      g_debug_inotify("crashreport found\n");
 
274
      g_debug_inotify("crashreport found");
231
275
      un->crashreport_pending = TRUE;
232
276
   }
233
277
   if(strstr(info_uri, UNICAST_LOCAL_AVAHI_FILE)) {
234
 
      g_debug_inotify("avahi disabled due to unicast .local domain\n");
 
278
      g_debug_inotify("avahi disabled due to unicast .local domain");
235
279
      un->unicast_local_avahi_pending = TRUE;
236
280
   }
 
281
   if(strstr(info_uri, LIVEPATCH_FILE)) {
 
282
      g_debug_inotify("livepatch status changed");
 
283
      un->livepatch_pending = TRUE;
 
284
   }
237
285
}
238
286
 
239
287
/*
240
 
 * We periodically check here what actions happend in this "time-slice". 
 
288
 * We periodically check here what actions happened in this "time-slice".
241
289
 * This can be:
242
290
 * - dpkg_was_run=TRUE: set when apt wrote the "dpkg-run-stamp" file
243
 
 * - apt_get_runing: set when apt/dpkg activity is detected (in the 
244
 
 *                   lists-dir, archive-cache, or /var/lib/dpkg/status
245
 
 * - hook_pending: we have new upgrade hoook information
246
 
 * - reboot_pending: we need to reboot
 
291
 * - apt_get_running: set when apt/dpkg activity is detected (in the
 
292
 *                    lists-dir, archive-cache, or /var/lib/dpkg/status)
 
293
 * - hook_pending: we have new upgrade hook information
247
294
 * - crashreport_pending: we have a new crashreport
248
295
 * - unicast_local_avahi_pending: avahi got disabled due to a unicast .local domain
 
296
 * - livepatch_pending: livepatch status changed
249
297
 *
250
298
 */
251
 
gboolean file_monitor_periodic_check(gpointer data)
252
 
 
 
299
static gboolean
 
300
file_monitor_periodic_check(gpointer data)
253
301
{
254
302
   UpgradeNotifier *un = (UpgradeNotifier *)data;
255
303
 
256
304
   // we are not ready yet, wait for the next timeslice
257
 
   if((un->reboot == NULL) || (un->crashreport == NULL))
 
305
   if(un->crashreport == NULL)
258
306
      return TRUE;
259
307
 
260
 
   // DPkg::Post-Invoke has written a stamp file, that means a install/remove
 
308
   // DPkg::Post-Invoke has written a stamp file, that means an install/remove
261
309
   // operation finished, we can show hooks/reboot notifications then
262
310
   if(un->dpkg_was_run) {
263
311
 
264
312
      // check updates
265
313
      update_check(un->update);
266
314
 
267
 
      // any apt-get update  must be finished, otherwise 
 
315
      // run cache-changed plugin scripts
 
316
      GDir *dir = g_dir_open(CACHE_CHANGED_PLUGIN_DIR, 0, NULL);
 
317
      const gchar *fname, *full_path;
 
318
      GSList *cache_changed_scripts = NULL;
 
319
      while ( (fname = g_dir_read_name(dir)) != NULL ) {
 
320
        full_path = g_build_filename(CACHE_CHANGED_PLUGIN_DIR, fname, NULL);
 
321
        cache_changed_scripts = g_slist_insert_sorted(cache_changed_scripts,
 
322
                                 (gpointer)full_path, (GCompareFunc)g_strcmp0);
 
323
      }
 
324
      g_dir_close(dir);
 
325
      // launch first script and queue others
 
326
      start_next_script(0, 0, cache_changed_scripts);
 
327
 
 
328
      // any apt-get update must be finished, otherwise
268
329
      // apt-get install wouldn't be finished
269
330
      update_apt_is_running(un->update, FALSE);
270
331
      if(un->update_finished_timer > 0) 
271
332
         g_source_remove(un->update_finished_timer);
272
 
      
273
 
      // show pending hooks/reboots
274
 
      if(un->hook_pending) {
275
 
         //g_print("checking hooks now\n");
276
 
         check_update_hooks(un->hook);
277
 
         un->hook_pending = FALSE;
278
 
      }
279
 
      if(un->reboot_pending) {
280
 
         //g_print("checking reboot now\n");
281
 
         reboot_check (un->reboot);
282
 
         un->reboot_pending = FALSE;
283
 
      }
284
333
 
285
 
      // apt must be finished when a new stamp file was writen, so we
286
 
      // reset the apt_get_runing time-slice field because its not 
287
 
      // important anymore (it finished runing)
 
334
      // apt must be finished when a new stamp file was written, so we
 
335
      // reset the apt_get_running time-slice field because its not
 
336
      // important anymore (it finished running)
288
337
      //
289
338
      // This may leave a 5s race condition when a apt-get install finished
290
339
      // and something new (apt-get) was started
291
 
      un->apt_get_runing = FALSE;
 
340
      un->apt_get_running = FALSE;
292
341
      un->last_apt_action = 0;
293
342
   }
294
343
 
295
 
   // apt-get update/install or dpkg is runing (and updates files in 
296
 
   // it's list/cache dir) or in /var/lib/dpkg/status
297
 
   if(un->apt_get_runing) 
 
344
   // show pending hooks
 
345
   if(un->hook_pending) {
 
346
      //g_print("checking hooks now\n");
 
347
      check_update_hooks(un->hook);
 
348
      un->hook_pending = FALSE;
 
349
   }
 
350
 
 
351
   // apt-get update/install or dpkg is running (and updates files in
 
352
   // its list/cache dir) or in /var/lib/dpkg/status
 
353
   if(un->apt_get_running)
298
354
      update_apt_is_running(un->update, TRUE);
299
355
 
300
356
   // update time information for apt/dpkg
301
357
   time_t now = time(NULL);
302
 
   if(un->apt_get_runing) 
 
358
   if(un->apt_get_running)
303
359
      un->last_apt_action = now;
304
360
 
305
361
   // no apt operation for a long time
311
367
   }
312
368
 
313
369
   if(un->crashreport_pending) {
314
 
      g_print("checking for valid crashreport now\n");
 
370
      g_debug("checking for valid crashreport now");
315
371
      crashreport_check (un->crashreport);
316
372
      un->crashreport_pending = FALSE;
317
373
   }
318
374
 
319
375
   if(un->unicast_local_avahi_pending) {
320
 
      g_print("checking for disabled avahi due to unicast .local domain now\n");
321
 
      avahi_disabled_check ();
 
376
      g_debug("checking for disabled avahi due to unicast .local domain now");
 
377
      avahi_disabled ();
322
378
      un->unicast_local_avahi_pending = FALSE;
323
379
   }
324
380
 
 
381
  if(un->livepatch_pending) {
 
382
      g_debug("checking for livepatch status now");
 
383
      livepatch_check ();
 
384
      un->livepatch_pending = FALSE;
 
385
   } 
 
386
 
325
387
   // reset the bitfields (for the next "time-slice")
326
388
   un->dpkg_was_run = FALSE;
327
 
   un->apt_get_runing = FALSE;
 
389
   un->apt_get_running = FALSE;
328
390
 
329
391
   return TRUE;
330
392
}
332
394
 
333
395
 
334
396
 
335
 
/* u_abort seems like an internal error notification.
336
 
 * End user might not understand the message at all */
337
 
void u_abort(gchar *msg)
338
 
{
339
 
   const char *fmt = "<span weight=\"bold\" size=\"larger\">%s</span>\n\n%s\n";
340
 
   gtk_dialog_run(GTK_DIALOG(gtk_message_dialog_new_with_markup(NULL, 0,
341
 
                                                     GTK_MESSAGE_ERROR,
342
 
                                                     GTK_BUTTONS_CLOSE,
343
 
                                                     fmt,
344
 
                                                     _("Internal error"),
345
 
                                                     msg)));
346
 
   g_free(msg);
347
 
   exit(1);
348
 
}
349
 
 
350
397
// FIXME: get the apt directories with apt-config or something
351
 
gboolean 
 
398
static gboolean
352
399
monitor_init(UpgradeNotifier *un)
353
400
{
354
401
   int i;
355
402
   GFileMonitor *monitor_handle;
356
403
 
357
 
   // monitor thise dirs
358
 
   static const char *monitor_dirs[] = { 
359
 
      "/var/lib/apt/lists/", "/var/lib/apt/lists/partial/", 
360
 
      "/var/cache/apt/archives/", "/var/cache/apt/archives/partial/", 
361
 
      HOOKS_DIR, 
 
404
   // monitor these dirs
 
405
   static const char *monitor_dirs[] = {
 
406
      "/var/lib/apt/lists/", "/var/lib/apt/lists/partial/",
 
407
      "/var/cache/apt/archives/", "/var/cache/apt/archives/partial/",
 
408
      HOOKS_DIR,
362
409
      CRASHREPORT_DIR,
363
410
      NULL};
364
411
   for(i=0;monitor_dirs[i] != NULL;i++) {
 
412
      if (getenv("UPSTART_SESSION") && monitor_dirs[i] == CRASHREPORT_DIR) {
 
413
         continue;
 
414
      }
365
415
      GError *error = NULL;
366
416
      GFile *gf = g_file_new_for_path(monitor_dirs[i]);
367
417
      monitor_handle = g_file_monitor_directory(gf, 0, NULL, &error);
368
418
      if(monitor_handle)
369
419
         g_signal_connect(monitor_handle, "changed", (GCallback)monitor_cb, un);
370
420
      else
371
 
         g_warning("can not add '%s'\n", monitor_dirs[i]);
 
421
         g_warning("can not add '%s'", monitor_dirs[i]);
372
422
   }
373
423
 
374
424
   // and those files
375
 
   static const char *monitor_files[] = { 
376
 
      "/var/lib/dpkg/status", 
377
 
      "/var/lib/update-notifier/dpkg-run-stamp", 
 
425
   static const char *monitor_files[] = {
 
426
      "/var/lib/dpkg/status",
 
427
      "/var/lib/update-notifier/dpkg-run-stamp",
378
428
      "/var/lib/apt/periodic/update-success-stamp",
379
 
      REBOOT_FILE,
380
429
      UNICAST_LOCAL_AVAHI_FILE,
 
430
      LIVEPATCH_FILE,
381
431
      NULL};
382
432
   for(i=0;monitor_files[i] != NULL;i++) {
 
433
      if (getenv("UPSTART_SESSION") && monitor_files[i] == UNICAST_LOCAL_AVAHI_FILE) {
 
434
         continue;
 
435
      }
383
436
      GError *error = NULL;
384
437
      GFile *gf = g_file_new_for_path(monitor_files[i]);
385
438
      monitor_handle = g_file_monitor_file(gf, 0, NULL, &error);
386
439
      if(monitor_handle)
387
440
         g_signal_connect(monitor_handle, "changed", (GCallback)monitor_cb, un);
388
441
      else
389
 
         g_warning("can not add '%s'\n", monitor_dirs[i]);
 
442
         g_warning("can not add '%s'", monitor_dirs[i]);
390
443
   }
391
 
 
392
 
   g_timeout_add (TIMEOUT_FAM, (GSourceFunc)file_monitor_periodic_check, un);
 
444
   g_timeout_add_seconds (TIMEOUT_FAM,
 
445
                          (GSourceFunc)file_monitor_periodic_check, un);
393
446
 
394
447
 
395
448
   return TRUE;
403
456
{
404
457
   //g_debug_inotify("tray_icons_init");
405
458
 
406
 
   /* new upates tray icon */
 
459
   /* new updates tray icon */
407
460
   un->update = g_new0 (TrayApplet, 1);
408
461
 
409
462
   // check if the updates icon should be displayed
410
463
   if (in_admin_group() || FORCE_START) {
411
 
      trayapplet_create(un->update, "software-update-available");
 
464
      trayapplet_create(un->update, un, "software-update-available");
412
465
      update_tray_icon_init(un->update);
413
 
   } else 
 
466
   } else
414
467
      un->update = NULL;
415
468
 
416
469
   /* update hook icon*/
417
470
   un->hook = g_new0 (TrayApplet, 1);
418
 
   trayapplet_create(un->hook, "hook-notifier");
 
471
   trayapplet_create(un->hook, un, "hook-notifier");
419
472
   hook_tray_icon_init(un->hook);
420
473
 
421
 
   /* reboot required icon */
422
 
   un->reboot = g_new0 (TrayApplet, 1);
423
 
   trayapplet_create(un->reboot, "reboot-notifier");
424
 
   reboot_tray_icon_init(un->reboot);
425
 
 
426
474
   /* crashreport detected icon */
427
475
   un->crashreport = g_new0 (TrayApplet, 1);
428
 
   trayapplet_create(un->crashreport, "apport");
 
476
   trayapplet_create(un->crashreport, un, "apport");
429
477
   crashreport_tray_icon_init(un->crashreport);
430
478
 
 
479
   /* livepatch icon */
 
480
   un->livepatch = g_new0(TrayApplet, 1);
 
481
   trayapplet_create(un->livepatch, un, "livepatch");
 
482
   livepatch_tray_icon_init(un->livepatch);
 
483
 
431
484
   return FALSE; // for the tray_destroyed_cb
432
485
}
433
486
 
434
 
gboolean
435
 
system_user()
 
487
static gboolean
 
488
system_user(UpgradeNotifier *un)
436
489
{
437
 
   /* do not start for system users, e.g. the guest session 
 
490
   /* do not start for system users, e.g. the guest session
438
491
    * (see /usr/share/gdm/guest-session/guest-session-setup.sh)
439
492
    */
440
493
   int end_system_uid = 500;
441
 
   GConfClient *gconf = gconf_client_get_default();
442
 
   if (gconf) {
443
 
      int i = gconf_client_get_int(gconf, GCONF_KEY_END_SYSTEM_UIDS, NULL);
444
 
      if (i>0)
445
 
         end_system_uid = i;
446
 
   }
 
494
   int i = g_settings_get_int(un->settings, SETTINGS_KEY_END_SYSTEM_UIDS);
 
495
   if (i>0)
 
496
      end_system_uid = i;
447
497
 
448
498
   uid_t uid = getuid();
449
499
   if (uid < end_system_uid)
451
501
   return FALSE;
452
502
}
453
503
 
454
 
// this function checks if the user is in the admin group
455
 
// if there is no admin group, we return true becuase there
456
 
// is no way to figure if the user is a admin or not
457
 
gboolean
458
 
in_admin_group()
 
504
// this function checks if the user is in the given group; return 1 if user is
 
505
// a member, 0 if not; return 2 if group does not exist.
 
506
static int
 
507
user_in_group(const char* grpname)
459
508
{
460
509
   int i, ng = 0;
461
510
   gid_t *groups = NULL;
462
511
 
463
 
   struct group *grp = getgrnam("admin");
 
512
   struct group *grp = getgrnam(grpname);
464
513
   if(grp == NULL) 
465
 
      return TRUE;
 
514
      return 2;
466
515
 
467
516
   ng = getgroups (0, NULL);
468
517
   groups = (gid_t *) malloc (ng * sizeof (gid_t));
470
519
   i = getgroups (ng, groups);
471
520
   if (i != ng) {
472
521
     free (groups);
473
 
     return TRUE;
 
522
     return 1;
474
523
   }
475
 
   
 
524
 
476
525
   for(i=0;i<ng;i++) {
477
526
      if(groups[i] == grp->gr_gid) {
478
527
        free(groups);
479
 
        return TRUE;
 
528
        return 1;
480
529
      }
481
530
   }
482
 
   
 
531
 
483
532
   if(groups != NULL)
484
533
      free(groups);
485
534
 
486
 
   return FALSE;
487
 
}
488
 
 
489
 
static GOptionEntry entries[] = 
 
535
   return 0;
 
536
}
 
537
 
 
538
gboolean
 
539
in_admin_group(void)
 
540
{
 
541
   int is_admin, is_sudo;
 
542
 
 
543
   // we consider the user an admin if the user is in the "sudo" or "admin"
 
544
   // group or neither of these groups exist
 
545
   is_admin = user_in_group("admin");
 
546
   is_sudo = user_in_group("sudo");
 
547
   return is_admin == 1 || is_sudo == 1 || (is_admin + is_sudo == 4);
 
548
}
 
549
 
 
550
 
 
551
static gboolean
 
552
sigint_cb (gpointer user_data __attribute__ ((__unused__)))
 
553
{
 
554
        gtk_main_quit ();
 
555
        return FALSE;
 
556
}
 
557
 
 
558
 
 
559
static GOptionEntry entries[] =
490
560
{
491
561
   { "debug-hooks", 0, 0, G_OPTION_ARG_NONE, &HOOK_DEBUG, "Enable hooks debugging"},
492
562
   { "debug-updates", 0, 0, G_OPTION_ARG_NONE, &UPDATE_DEBUG, "Enable updates/autolaunch debugging"},
493
563
   { "debug-inotify", 0, 0, G_OPTION_ARG_NONE, &INOTIFY_DEBUG, "Enable inotify debugging"},
494
 
   { "debug-firmware", 0, 0, G_OPTION_ARG_NONE, &FIRMWARE_DEBUG, "Enable firmware debugging"},
 
564
   { "debug-uevent", 0, 0, G_OPTION_ARG_NONE, &UEVENT_DEBUG, "Enable uevent debugging"},
495
565
   { "debug-new-release-check", 0, 0, G_OPTION_ARG_NONE, &RELEASE_DEBUG, "Enable new release check debugging"},
 
566
   { "debug-misc", 0, 0, G_OPTION_ARG_NONE, &MISC_DEBUG, "Enable uncategorized debug prints"},
496
567
   { "force", 0, 0, G_OPTION_ARG_NONE, &FORCE_START, "Force start even if the user is not in the admin group"},
497
 
   { "force-use-gksu", 0, 0, G_OPTION_ARG_NONE, &FORCE_GKSU, "Force running all commands (update-manager, synaptic) with gksu" },
 
568
   { "force-use-pkexec", 0, 0, G_OPTION_ARG_NONE, &FORCE_PKEXEC, "Force running all commands (update-manager, synaptic) with pkexec" },
498
569
   { "startup-delay", 0, 0, G_OPTION_ARG_INT, &STARTUP_DELAY, "Delay startup by given amount of seconds" },
499
570
   { "devel-release", 0, 0, G_OPTION_ARG_NONE, &DEVEL_RELEASE, "Make the release checker check for a new development release" },
500
571
   { "force-release-check", 0, 0, G_OPTION_ARG_NONE, &FORCE_RELEASE_CHECK, "Force release check" },
501
572
   { NULL }
502
573
};
503
574
 
504
 
int 
 
575
int
505
576
main (int argc, char **argv)
506
577
{
507
578
        UpgradeNotifier *un;
508
579
        GError *error = NULL;
 
580
        int pid_file, rc;
 
581
        gchar *lockfn;
509
582
 
510
583
        // init
511
 
        if(!gtk_init_with_args (&argc, &argv, 
512
 
                                _("- inform about updates"), entries, 
 
584
        if(!gtk_init_with_args (&argc, &argv,
 
585
                                _("- inform about updates"), entries,
513
586
                                "update-notifier", &error) ) {
514
 
           fprintf(stderr, _("Failed to init the UI: %s\n"), 
 
587
           fprintf(stderr, _("Failed to init the UI: %s\n"),
515
588
                   error ? error->message : _("unknown error"));
516
589
           exit(1);
517
590
        }
518
591
 
519
592
        notify_init("update-notifier");
520
 
        bindtextdomain(PACKAGE, PACKAGE_LOCALE_DIR);
521
 
        bind_textdomain_codeset(PACKAGE, "UTF-8");
522
 
        textdomain(PACKAGE);
 
593
        bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
 
594
        bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
 
595
        textdomain(GETTEXT_PACKAGE);
 
596
 
 
597
        if (HOOK_DEBUG || UPDATE_DEBUG || INOTIFY_DEBUG ||
 
598
            UEVENT_DEBUG || RELEASE_DEBUG || MISC_DEBUG)
 
599
                g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
523
600
 
524
601
        // setup a custom debug log handler
525
602
        g_log_set_handler ("inotify", G_LOG_LEVEL_DEBUG,
528
605
                           debug_log_handler, NULL);
529
606
        g_log_set_handler ("update", G_LOG_LEVEL_DEBUG,
530
607
                           debug_log_handler, NULL);
531
 
        g_log_set_handler ("firmware", G_LOG_LEVEL_DEBUG,
 
608
        g_log_set_handler ("uevent", G_LOG_LEVEL_DEBUG,
532
609
                           debug_log_handler, NULL);
533
610
        g_log_set_handler ("release", G_LOG_LEVEL_DEBUG,
 
611
                           debug_log_handler, NULL);
 
612
        g_log_set_handler (NULL, G_LOG_LEVEL_DEBUG,
534
613
                           debug_log_handler, NULL);
535
614
 
536
615
        g_set_application_name (_("update-notifier"));
538
617
 
539
618
        //g_print("starting update-notifier\n");
540
619
 
 
620
        /* Create the UpgradeNotifier object */
 
621
        un = g_new0 (UpgradeNotifier, 1);
 
622
        un->settings = g_settings_new(SETTINGS_SCHEMA);
 
623
 
541
624
        // do not run as system user (e.g. guest user)
542
 
        if (system_user() && !FORCE_START) {
543
 
           g_warning("not starting for system user\n");
 
625
        if (system_user(un) && !FORCE_START) {
 
626
           g_warning("not starting for system user");
544
627
           exit(0);
545
628
        }
546
629
 
547
630
        // do not run as system user (e.g. guest user)
548
 
        if (FORCE_RELEASE_CHECK) {
549
 
           GConfClient *gconf = gconf_client_get_default();
550
 
           gconf_client_unset(gconf, GCONF_KEY_LAST_RELEASE_CHECK, NULL);
551
 
        }
 
631
        if (FORCE_RELEASE_CHECK)
 
632
           g_settings_reset(un->settings, SETTINGS_KEY_LAST_RELEASE_CHECK);
552
633
 
553
634
        // check if it is running already
554
 
        if (!up_get_clipboard ()) {
555
 
           g_warning ("already running?\n");
 
635
        lockfn = g_build_filename (g_get_user_runtime_dir (), "update-notifier.pid", NULL);
 
636
        pid_file = open (lockfn, O_CREAT | O_RDWR, 0600);
 
637
        g_free (lockfn);
 
638
        rc = flock(pid_file, LOCK_EX | LOCK_NB);
 
639
        if (rc) {
 
640
           g_warning ("already running?");
556
641
           return 1;
557
642
        }
558
643
 
559
 
        /* Create the UpgradeNotifier object */
560
 
        un = g_new0 (UpgradeNotifier, 1);
561
 
 
562
 
        // check for .update-notifier dir and create if needed
563
 
        gchar *dirname = g_strdup_printf("%s/.update-notifier",
564
 
                                         g_get_home_dir());
 
644
        // check for update-notifier dir and create if needed
 
645
        gchar *dirname = g_strdup_printf("%s/update-notifier",
 
646
                                         g_get_user_config_dir());
565
647
        if(!g_file_test(dirname, G_FILE_TEST_IS_DIR))
566
648
           g_mkdir(dirname, 0700);
567
649
        g_free(dirname);
568
650
 
569
 
        // delay icon creation for 30s so that the desktop 
 
651
        // delay icon creation for 30s so that the desktop
570
652
        // login is not slowed down by update-notifier
571
 
        g_timeout_add_seconds(STARTUP_DELAY, 
 
653
        g_timeout_add_seconds(STARTUP_DELAY,
572
654
                              (GSourceFunc)(tray_icons_init), un);
573
655
 
574
 
        // initial check for avahi
575
 
        avahi_disabled_check();
576
 
        
577
 
        /* setup hal so that inserted cdroms can be checked */
578
 
        if(!up_do_hal_init(un)) {
579
 
           g_warning("initializing gdu failed");
580
 
        }
581
 
 
582
656
        // init release checker
583
 
        release_checker_init();
584
 
 
585
 
        // init missing firmware monitoring
586
 
        missing_firmware_init();
 
657
        release_checker_init(un);
 
658
 
 
659
        // init uevent monitoring (printer support, etc.)
 
660
#ifdef ENABLE_SCP
 
661
        uevent_init();
 
662
#endif
 
663
 
 
664
        /* check if livepatch patches has been applied during boot or before
 
665
           update-notifier has started (see LP: #1800862) */
 
666
        livepatch_check ();
587
667
 
588
668
        // init gio file monitoring
589
669
        monitor_init (un);
590
 
        
 
670
 
591
671
        /* Start the main gtk loop */
 
672
        g_unix_signal_add_full (G_PRIORITY_DEFAULT, SIGINT, sigint_cb,
 
673
                                NULL, NULL);
592
674
        gtk_main ();
593
675
 
594
676
        return 0;