~ubuntu-branches/ubuntu/oneiric/indicator-session/oneiric-proposed

« back to all changes in this revision

Viewing changes to src/udev-mgr.c

  • Committer: Bazaar Package Importer
  • Author(s): Ken VanDine
  • Date: 2011-08-10 16:23:33 UTC
  • mfrom: (1.1.32 upstream)
  • Revision ID: james.westby@ubuntu.com-20110810162333-e1elpqez16qr18ya
Tags: 0.3.1-0ubuntu1
* New upstream release.
  - restart is missing from SessionMenu (LP: #815077)
  - Don't allow starting programs via the greeter indicators (LP: #811853)
  - Printer menu item should launch system-config-printer (LP: #818602)
  - gudev integration
  - apt restart required awareness
* debian/control
  - Added build depends on libgudev-1.0-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
with this program.  If not, see <http://www.gnu.org/licenses/>.
18
18
*/
19
19
 
 
20
#include <gudev/gudev.h>
 
21
 
 
22
// TEMP
 
23
#include <stdio.h>
 
24
#include <string.h>
 
25
#include <stdlib.h>
 
26
#include <stdarg.h>
 
27
 
20
28
#include "udev-mgr.h"
 
29
#include "sane-rules.h"
 
30
 
 
31
static void udevice_mgr_device_list_iterator (gpointer data,
 
32
                                              gpointer userdata);
 
33
static void udev_mgr_uevent_cb  (GUdevClient *client,
 
34
                                 gchar       *action,
 
35
                                 GUdevDevice *device,
 
36
                                 gpointer     user_data);   
 
37
static void udev_mgr_update_menuitems (UdevMgr* self);
 
38
static void udev_mgr_check_if_usb_device_is_supported (UdevMgr* self, 
 
39
                                                        GUdevDevice *device,
 
40
                                                        UdevMgrDeviceAction action);                                                                                                                                               
 
41
static void udev_mgr_handle_webcam (UdevMgr* self,
 
42
                                    GUdevDevice* device,
 
43
                                    UdevMgrDeviceAction action);                                                      
 
44
static void udev_mgr_handle_scsi_device (UdevMgr* self,
 
45
                                         GUdevDevice* device,
 
46
                                         UdevMgrDeviceAction action);
 
47
 
 
48
static void udev_mgr_cleanup_lists(gpointer data, gpointer self);
 
49
static void udev_mgr_cleanup_entries(gpointer data, gpointer self);
 
50
 
 
51
 
 
52
static void debug_device (UdevMgr* self,
 
53
                          GUdevDevice* device,
 
54
                          UdevMgrDeviceAction action);
 
55
                          
 
56
 
 
57
struct _UdevMgr
 
58
{
 
59
        GObject parent_instance;
 
60
  DbusmenuMenuitem* scanner_item;
 
61
  DbusmenuMenuitem* webcam_item;  
 
62
  GUdevClient* client;  
 
63
  GHashTable* supported_usb_scanners;
 
64
  GHashTable* supported_scsi_scanners;
 
65
  GHashTable* scanners_present;
 
66
  GHashTable* webcams_present;
 
67
};
 
68
 
 
69
const char *subsystems[3] = {"usb", "scsi", "video4linux"};
 
70
const gchar* usb_subsystem = "usb";
 
71
const gchar* scsi_subsystem = "scsi";
 
72
const gchar* video4linux_subsystem = "video4linux";
21
73
 
22
74
 
23
75
G_DEFINE_TYPE (UdevMgr, udev_mgr, G_TYPE_OBJECT);
24
76
 
25
77
static void
26
 
udev_mgr_init (UdevMgr *object)
27
 
{
28
 
        /* TODO: Add initialization code here */
 
78
udev_mgr_init (UdevMgr* self)
 
79
{
 
80
  self->client = NULL;
 
81
  self->supported_usb_scanners = NULL;
 
82
  self->scanners_present = NULL;
 
83
  self->webcams_present = NULL;
 
84
  self->client = g_udev_client_new (subsystems);  
 
85
  self->supported_usb_scanners = g_hash_table_new_full (g_str_hash,
 
86
                                                        g_str_equal,
 
87
                                                        g_free,
 
88
                                                        (GDestroyNotify)udev_mgr_cleanup_lists);
 
89
  self->supported_scsi_scanners = g_hash_table_new_full (g_str_hash,
 
90
                                                         g_str_equal,
 
91
                                                         g_free,
 
92
                                                         (GDestroyNotify)udev_mgr_cleanup_lists);
 
93
  self->scanners_present = g_hash_table_new_full (g_str_hash,
 
94
                                                  g_str_equal,
 
95
                                                  g_free,
 
96
                                                  g_free);
 
97
  self->webcams_present = g_hash_table_new_full (g_str_hash,
 
98
                                                 g_str_equal,
 
99
                                                 g_free,
 
100
                                                 g_free);
 
101
  
 
102
  // load into memory all supported scanners ...
 
103
  populate_usb_scanners (self->supported_usb_scanners);
 
104
  populate_scsi_scanners (self->supported_scsi_scanners);
 
105
  g_signal_connect (G_OBJECT (self->client),
 
106
                   "uevent",
 
107
                    G_CALLBACK (udev_mgr_uevent_cb),
 
108
                    self);
 
109
}
 
110
 
 
111
static void
 
112
udev_mgr_cleanup_lists(gpointer data, gpointer self)
 
113
{
 
114
  GList* scanners = (GList*)data;
 
115
  g_list_foreach (scanners, udev_mgr_cleanup_entries, NULL);  
 
116
  g_list_free(scanners);
 
117
}
 
118
 
 
119
static void
 
120
udev_mgr_cleanup_entries(gpointer data, gpointer self)
 
121
{
 
122
  gchar* entry = (gchar*)data;
 
123
  g_free(entry);
29
124
}
30
125
 
31
126
static void
32
127
udev_mgr_finalize (GObject *object)
33
128
{
34
 
        /* TODO: Add deinitalization code here */
35
 
 
 
129
  UdevMgr* self = UDEV_MGR (object);
 
130
  g_hash_table_destroy (self->supported_scsi_scanners);  
 
131
  g_hash_table_destroy (self->supported_usb_scanners);  
 
132
  g_hash_table_destroy (self->scanners_present);  
 
133
  g_hash_table_destroy (self->webcams_present);  
36
134
        G_OBJECT_CLASS (udev_mgr_parent_class)->finalize (object);
37
135
}
38
136
 
40
138
udev_mgr_class_init (UdevMgrClass *klass)
41
139
{
42
140
        GObjectClass* object_class = G_OBJECT_CLASS (klass);
43
 
 
44
141
        object_class->finalize = udev_mgr_finalize;
45
142
}
46
143
 
 
144
static void
 
145
udevice_mgr_device_list_iterator (gpointer data, gpointer userdata)
 
146
{
 
147
  g_return_if_fail (G_UDEV_IS_DEVICE (data));
 
148
  g_return_if_fail (UDEV_IS_MGR (userdata));
 
149
  
 
150
  UdevMgr* self = UDEV_MGR (userdata);
 
151
  
 
152
  GUdevDevice* device = G_UDEV_DEVICE (data);
 
153
 
 
154
  const gchar* subsystem = NULL; 
 
155
  subsystem = g_udev_device_get_subsystem (device);
 
156
 
 
157
  if (g_strcmp0 (subsystem, "usb") == 0){
 
158
    udev_mgr_check_if_usb_device_is_supported (self, device, ADD);
 
159
  }
 
160
  else if (g_strcmp0 (subsystem, "video4linux") == 0){
 
161
    udev_mgr_handle_webcam (self, device, ADD);    
 
162
  }
 
163
  else if (g_strcmp0 (subsystem, "scsi") == 0){
 
164
    udev_mgr_handle_scsi_device (self, device, ADD);    
 
165
  }
 
166
  
 
167
  g_object_unref (device);
 
168
}
 
169
 
 
170
 
 
171
static void udev_mgr_update_menuitems (UdevMgr* self)
 
172
{
 
173
  dbusmenu_menuitem_property_set_bool (self->scanner_item,
 
174
                                       DBUSMENU_MENUITEM_PROP_VISIBLE,
 
175
                                       g_hash_table_size (self->scanners_present) > 0);
 
176
 
 
177
  dbusmenu_menuitem_property_set_bool (self->webcam_item,
 
178
                                       DBUSMENU_MENUITEM_PROP_VISIBLE,
 
179
                                       g_hash_table_size (self->webcams_present) > 0);
 
180
 
 
181
}
 
182
 
 
183
static void udev_mgr_uevent_cb (GUdevClient *client,
 
184
                                gchar       *action,
 
185
                                GUdevDevice *device,
 
186
                                gpointer     user_data)   
 
187
{
 
188
  g_return_if_fail (UDEV_IS_MGR (user_data));
 
189
  UdevMgr* self = UDEV_MGR (user_data);
 
190
  g_return_if_fail (device != NULL);
 
191
  
 
192
  g_debug ("just received a UEVENT with an action :  %s", action);
 
193
 
 
194
  UdevMgrDeviceAction udev_mgr_action = ADD;
 
195
 
 
196
  if (g_strcmp0 (action, "remove") == 0){
 
197
    udev_mgr_action = REMOVE;
 
198
  }
 
199
  
 
200
  const gchar* subsystem = NULL;  
 
201
  subsystem = g_udev_device_get_subsystem (device);
 
202
 
 
203
  if (g_strcmp0 (subsystem, "usb") == 0){
 
204
    udev_mgr_check_if_usb_device_is_supported (self,
 
205
                                               device,
 
206
                                               udev_mgr_action);
 
207
  }
 
208
  else if (g_strcmp0 (subsystem, "video4linux") == 0){
 
209
    udev_mgr_handle_webcam (self, device, udev_mgr_action);
 
210
  }
 
211
  else if (g_strcmp0 (subsystem, "scsi") == 0){
 
212
    udev_mgr_handle_scsi_device (self, device, udev_mgr_action);    
 
213
  }
 
214
}
 
215
 
 
216
 
 
217
static void
 
218
udev_mgr_handle_webcam (UdevMgr* self,
 
219
                        GUdevDevice* device,
 
220
                        UdevMgrDeviceAction action)
 
221
{
 
222
  if (FALSE)
 
223
    debug_device (self, device, action);    
 
224
  
 
225
  const gchar* vendor;
 
226
  const gchar* product;
 
227
  
 
228
  vendor = g_udev_device_get_property (device, "ID_VENDOR_ID");
 
229
  product = g_udev_device_get_property (device, "ID_MODEL_ID");
 
230
  
 
231
  if (action == REMOVE){
 
232
    if (g_hash_table_lookup (self->webcams_present, product) == NULL){
 
233
      g_warning ("Got a remove event on a webcam device but we don't have that device in our webcam cache");
 
234
      return;                     
 
235
    }
 
236
    g_hash_table_remove (self->webcams_present,
 
237
                         product);
 
238
    
 
239
  }
 
240
  else {
 
241
    if (g_hash_table_lookup (self->webcams_present, product) != NULL){
 
242
      g_warning ("Got an ADD event on a webcam device but we already have that device in our webcam cache");
 
243
      return;                     
 
244
    }
 
245
    g_hash_table_insert (self->webcams_present,
 
246
                         g_strdup (product),
 
247
                         g_strdup (vendor));                               
 
248
  }
 
249
  udev_mgr_update_menuitems (self);  
 
250
}                        
 
251
 
 
252
static void
 
253
debug_device (UdevMgr* self,
 
254
              GUdevDevice* device,
 
255
              UdevMgrDeviceAction action)
 
256
{
 
257
  const gchar* vendor;
 
258
  const gchar* product;
 
259
  const gchar* number;
 
260
  const gchar* name;
 
261
  
 
262
        vendor = g_udev_device_get_property (device, "ID_VENDOR_ID");
 
263
        product = g_udev_device_get_property (device, "ID_MODEL_ID");
 
264
  number = g_udev_device_get_number (device);
 
265
  name = g_udev_device_get_name (device);
 
266
  
 
267
  g_debug ("device vendor id %s , product id of %s , number of %s and name of %s",
 
268
           g_strdup(vendor),
 
269
           g_strdup(product),
 
270
           g_strdup(number),
 
271
           g_strdup(name));
 
272
           
 
273
  const gchar *const *list;
 
274
  const gchar *const *iter;  
 
275
  char propstr[500];
 
276
  guint32 namelen = 0, i;  
 
277
  
 
278
  list = g_udev_device_get_property_keys(device);
 
279
  
 
280
  for (iter = list; iter && *iter; iter++) {
 
281
    if (strlen(*iter) > namelen)
 
282
      namelen = strlen(*iter);
 
283
  }
 
284
  namelen++;
 
285
 
 
286
  for (iter = list; iter && *iter; iter++) {
 
287
    strcpy(propstr, *iter);
 
288
    strcat(propstr, ":");
 
289
    for (i = 0; i < namelen - strlen(*iter); i++)
 
290
           strcat(propstr, " ");
 
291
    strcat(propstr, g_udev_device_get_property(device, *iter));
 
292
    g_debug("%s", propstr);
 
293
  }   
 
294
}
 
295
 
 
296
static void udev_mgr_handle_scsi_device (UdevMgr* self,
 
297
                                         GUdevDevice* device,
 
298
                                         UdevMgrDeviceAction action)
 
299
{
 
300
  const gchar* type = NULL;
 
301
        type = g_udev_device_get_property (device, "TYPE");
 
302
  // apparently anything thats type 3 and SCSI is a Scanner
 
303
  if (g_strcmp0 (type, "6") == 0){
 
304
    gchar* random_scanner_name =        g_strdup_printf("%p--scanner", self);
 
305
    g_hash_table_insert (self->scanners_present,
 
306
                         random_scanner_name,
 
307
                         g_strdup("Scanner")); 
 
308
    udev_mgr_update_menuitems (self);    
 
309
    return;                         
 
310
  }
 
311
 
 
312
  // We only care about type 3 for the special cases below
 
313
  if (g_strcmp0 (type, "3") != 0){
 
314
    return;
 
315
  }
 
316
 
 
317
  const gchar* vendor = NULL;
 
318
        vendor = g_udev_device_get_property (device, "VENDOR");
 
319
  
 
320
  if (vendor == NULL)
 
321
    return;
 
322
 
 
323
  GList* vendor_list = NULL;
 
324
  vendor_list = g_hash_table_lookup (self->supported_scsi_scanners,
 
325
                                     (gpointer)vendor);
 
326
  if (vendor_list == NULL)
 
327
    return;
 
328
 
 
329
  const gchar* model_id = NULL;
 
330
        model_id = g_udev_device_get_property (device, "MODEL");
 
331
  
 
332
  if (model_id == NULL)
 
333
    return;
 
334
 
 
335
  GList* model_entry = NULL;
 
336
  model_entry = g_list_find_custom (vendor_list,
 
337
                                    model_id,
 
338
                                    (GCompareFunc)g_strcmp0);
 
339
    
 
340
  if (model_entry != NULL){
 
341
    if (action == REMOVE){
 
342
      if (g_hash_table_lookup (self->scanners_present, g_strdup(vendor)) == NULL){
 
343
        g_warning ("Got an REMOVE event on a scanner device but we dont have that device in our scanners cache");
 
344
      }
 
345
      else{
 
346
        g_hash_table_remove (self->scanners_present, vendor);
 
347
      }
 
348
    }
 
349
    else{      
 
350
      if (g_hash_table_lookup (self->scanners_present, g_strdup(vendor)) != NULL){
 
351
        g_warning ("Got an ADD event on a scanner device but we already have that device in our scanners cache");
 
352
      }
 
353
      else{
 
354
        g_hash_table_insert (self->scanners_present,
 
355
                             g_strdup(vendor),
 
356
                             g_strdup(model_id)); 
 
357
      }
 
358
    }
 
359
    udev_mgr_update_menuitems (self);
 
360
  }
 
361
}                                         
 
362
 
 
363
static void
 
364
udev_mgr_check_if_usb_device_is_supported (UdevMgr* self, 
 
365
                                           GUdevDevice *device,
 
366
                                           UdevMgrDeviceAction action)
 
367
{
 
368
  const gchar* vendor = NULL;
 
369
  debug_device (self, device, action);    
 
370
  
 
371
        vendor = g_udev_device_get_property (device, "ID_VENDOR_ID");
 
372
  
 
373
  if (vendor == NULL)
 
374
    return;
 
375
 
 
376
  //g_debug ("vendor = %s", vendor);
 
377
  
 
378
  GList* vendor_list = NULL;
 
379
  vendor_list = g_hash_table_lookup (self->supported_usb_scanners,
 
380
                                     (gpointer)vendor);
 
381
  if (vendor_list == NULL)
 
382
    return;
 
383
 
 
384
  const gchar* model_id = NULL;
 
385
        model_id = g_udev_device_get_property (device, "ID_MODEL_ID");
 
386
  
 
387
  if (model_id == NULL)
 
388
    return;
 
389
  
 
390
  GList* model_entry = NULL;
 
391
  model_entry = g_list_find_custom(vendor_list, model_id, (GCompareFunc)g_strcmp0);
 
392
    
 
393
  if (model_entry != NULL){
 
394
    if (action == REMOVE){
 
395
      if (g_hash_table_lookup (self->scanners_present, g_strdup(vendor)) == NULL){
 
396
        g_warning ("Got an REMOVE event on a scanner device but we dont have that device in our scanners cache");
 
397
      }
 
398
      else{
 
399
        g_hash_table_remove (self->scanners_present, vendor);
 
400
      }
 
401
    }
 
402
    else{      
 
403
      if (g_hash_table_lookup (self->scanners_present, g_strdup(vendor)) != NULL){
 
404
        g_warning ("Got an ADD event on a scanner device but we already have that device in our scanners cache");
 
405
      }
 
406
      else{
 
407
        g_hash_table_insert (self->scanners_present,
 
408
                             g_strdup(vendor),
 
409
                             g_strdup(model_id)); 
 
410
      }
 
411
    }
 
412
    udev_mgr_update_menuitems (self);
 
413
  }
 
414
}
 
415
 
 
416
UdevMgr* udev_mgr_new (DbusmenuMenuitem* scanner, 
 
417
                       DbusmenuMenuitem* webcam)
 
418
{
 
419
  UdevMgr* mgr = g_object_new (UDEV_TYPE_MGR, NULL);
 
420
  mgr->scanner_item = scanner;
 
421
  mgr->webcam_item = webcam;
 
422
  
 
423
  // Check for USB devices
 
424
  GList* usb_devices_available = NULL;
 
425
  usb_devices_available  = g_udev_client_query_by_subsystem (mgr->client,
 
426
                                                             usb_subsystem);
 
427
  if (usb_devices_available != NULL){
 
428
    g_list_foreach (usb_devices_available,
 
429
                    udevice_mgr_device_list_iterator,
 
430
                    mgr);
 
431
                    
 
432
    g_list_free (usb_devices_available);
 
433
  }  
 
434
  // Check for webcams
 
435
  GList* video_devices_available  = NULL;
 
436
  video_devices_available  = g_udev_client_query_by_subsystem (mgr->client,
 
437
                                                               video4linux_subsystem);
 
438
  if (video_devices_available != NULL){
 
439
    g_list_foreach (video_devices_available,
 
440
                    udevice_mgr_device_list_iterator,
 
441
                    mgr);
 
442
    
 
443
    g_list_free (video_devices_available);
 
444
  }  
 
445
  // Check for SCSI devices
 
446
  GList* scsi_devices_available = NULL;
 
447
  scsi_devices_available  = g_udev_client_query_by_subsystem (mgr->client,
 
448
                                                              scsi_subsystem);
 
449
  if (scsi_devices_available != NULL){
 
450
    g_list_foreach (scsi_devices_available,
 
451
                    udevice_mgr_device_list_iterator,
 
452
                    mgr);                    
 
453
    g_list_free (scsi_devices_available);
 
454
  }
 
455
  return mgr;
 
456
}