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

541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
1
#ifdef HAVE_CONFIG_H
2
#include "config.h"
3
#endif
573 by Michael Vogt
merged from debian
4
#ifdef HAVE_GUDEV
558 by Michael Vogt
src/firmware.c: fixes to the firmware plugin stuff, thanks to tkampetter
5
#include <sys/wait.h>
6
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
7
#define G_UDEV_API_IS_SUBJECT_TO_CHANGE
8
#include <gudev/gudev.h>
9
#include <sys/utsname.h>
10
11
/* search path for firmare; second and fourth element are dynamically constructed
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
12
 * in uevent_init(). */
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
13
const gchar* firmware_search_path[] = {
14
    "/lib/firmware", NULL,
15
    "/lib/firmware/updates", NULL,
16
    NULL };
17
557 by Michael Vogt
* src/firmware.c:
18
gchar *hplip_helper[] = { "/usr/bin/hp-plugin-ubuntu", NULL };
19
567 by Michael Vogt
silence debug messages by default (unless one of the
20
static inline void
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
21
g_debug_uevent(const char *msg, ...)
567 by Michael Vogt
silence debug messages by default (unless one of the
22
{
23
   va_list va;
24
   va_start(va, msg);
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
25
   g_logv("uevent",G_LOG_LEVEL_DEBUG, msg, va);
567 by Michael Vogt
silence debug messages by default (unless one of the
26
   va_end(va);
27
}
28
557 by Michael Vogt
* src/firmware.c:
29
static gboolean
30
deal_with_hplip_firmware(GUdevDevice *device)
31
{
32
    const gchar *id_vendor, *id_product, *id_model;
33
    GError *error = NULL;
34
    gint ret = 0;
35
36
    id_vendor = g_udev_device_get_sysfs_attr (device, "idVendor");
37
    id_product = g_udev_device_get_sysfs_attr (device, "idProduct");
38
    id_model = g_udev_device_get_property (device, "ID_MODEL");
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
39
    g_debug_uevent ("uevent.c id_vendor=%s, id_product=%s", id_vendor, id_product);
559 by Michael Vogt
src/firmware.c: add cold-plug support
40
626 by Michael Vogt
* src/uevent.c:
41
    // only idVendor=03f0, idProduct="??{17,2a}" requires firmware
42
    if (g_strcmp0 (id_vendor, "03f0") != 0 || 
43
        id_product == NULL || 
44
        g_utf8_strlen(id_product, -1) != 4)
557 by Michael Vogt
* src/firmware.c:
45
       return FALSE;
626 by Michael Vogt
* src/uevent.c:
46
    if (! ( ((id_product[2] == '1') && (id_product[3] == '7')) ||
47
            ((id_product[2] == '2') && (tolower(id_product[3]) == 'a')) ))
557 by Michael Vogt
* src/firmware.c:
48
       return FALSE;
559 by Michael Vogt
src/firmware.c: add cold-plug support
49
50
    // firmware is only required if "hp-mkuri -c" returns 2 or 5
557 by Michael Vogt
* src/firmware.c:
51
    const gchar *cmd = "/usr/bin/hp-mkuri -c";
52
    g_setenv("hp_model", id_model, TRUE);
53
    if (!g_spawn_command_line_sync (cmd, NULL, NULL, &ret, &error))
54
    {
55
       g_warning("error calling hp-mkuri");
56
       return FALSE;
57
    }
58
558 by Michael Vogt
src/firmware.c: fixes to the firmware plugin stuff, thanks to tkampetter
59
    // check return codes, 2 & 5 indicate that it has the firmware already
60
    if (WEXITSTATUS(ret) != 2 && WEXITSTATUS(ret) != 5) 
61
    {
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
62
       g_debug_uevent ("hp-mkuri indicates no firmware needed");
558 by Michael Vogt
src/firmware.c: fixes to the firmware plugin stuff, thanks to tkampetter
63
       return TRUE;
64
    }
65
557 by Michael Vogt
* src/firmware.c:
66
    if (!g_spawn_async("/", hplip_helper, NULL, 0, NULL, NULL, NULL, NULL))
67
    {
68
       g_warning("error calling hplip_helper");
69
       return FALSE;
70
    }
71
    return TRUE;
72
}
73
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
74
static gboolean
75
deal_with_missing_firmware(GUdevDevice *device)
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
76
{
77
    gchar *path;
557 by Michael Vogt
* src/firmware.c:
78
    const gchar **i;
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
79
    gboolean found = FALSE;
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
80
    const gchar* firmware_file;
557 by Michael Vogt
* src/firmware.c:
81
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
82
    firmware_file = g_udev_device_get_property (device, "FIRMWARE");
83
84
    if (!firmware_file) {
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
85
        g_debug_uevent ("deal_with_missing_firmware: discarding, no FIRMWARE property");
86
        return FALSE;
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
87
    }
88
89
    for (i = firmware_search_path; *i && !found; ++i) {
90
	path = g_build_path("/", *i, firmware_file, NULL);
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
91
	g_debug_uevent ("deal_with_missing_firmware: searching for %s", path);
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
92
	if (g_file_test (path, G_FILE_TEST_EXISTS)) {
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
93
	    g_debug_uevent ("deal_with_missing_firmware: found");
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
94
	    found = TRUE;
95
	}
96
	g_free (path);
97
    }
98
99
    if (found)
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
100
	return TRUE;
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
101
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
102
    g_debug_uevent ("calling jockey");
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
103
    gchar* argv[] = {"jockey-gtk", "-c", NULL };
104
    GError* error = NULL;
105
    if (!g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error)) {
106
	g_warning("jockey could not be called: %s", error->message);
107
	g_error_free (error);
108
    }
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
109
    return TRUE;
110
}
111
580 by Martin Pitt
src/uevent.c: Add new function deal_with_scp() to launch
112
#ifdef ENABLE_SCP
113
static gboolean scp_checked = FALSE;
114
115
static gboolean
116
deal_with_scp(GUdevDevice *device)
117
{
118
    GError *error = NULL;
119
120
    /* only do this once */
121
    if (scp_checked)
122
	return FALSE;
123
124
    /* check if we just added a printer */
125
    if ((g_strcmp0(g_udev_device_get_sysfs_attr(device, "bInterfaceClass"), "07") != 0 ||
126
		g_strcmp0(g_udev_device_get_sysfs_attr(device, "bInterfaceSubClass"), "01") != 0) &&
127
	    !g_str_has_prefix(g_udev_device_get_name (device), "lp")) {
128
	g_debug_uevent ("deal_with_scp: devpath=%s: not a printer", g_udev_device_get_sysfs_path(device));
129
	return FALSE;
130
    }
131
132
    g_debug_uevent ("deal_with_scp: devpath=%s: printer identified", g_udev_device_get_sysfs_path(device));
133
134
    scp_checked = TRUE;
135
136
    gchar* ps_argv[] = {"ps", "h", "-ocommand", "-Cpython", NULL};
137
    gchar* ps_out;
138
    if (!g_spawn_sync (NULL, ps_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
139
		&ps_out, NULL, NULL, &error)) {
140
	g_warning ("deal_with_scp: error calling ps: %s", error->message);
141
	g_error_free (error);
142
	return TRUE;
143
    }
144
    g_debug_uevent ("deal_with_scp: running python processes:\n%s", ps_out);
145
    if (strstr (ps_out, "system-config-printer") != NULL) {
146
	g_debug_uevent ("deal_with_scp: system-config-printer already running");
147
	return TRUE;
148
    }
149
150
    g_debug_uevent ("deal_with_scp: launching system-config-printer");
151
    gchar* scp_argv[] = {"system-config-printer-applet", NULL};
152
    error = NULL;
153
    if (!g_spawn_async(NULL, scp_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error)) {
154
	g_warning("%s could not be called: %s", scp_argv[0], error->message);
155
	g_error_free (error);
156
    }
157
    return TRUE;
158
}
159
#endif
160
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
161
static void
162
on_uevent (GUdevClient *client,
163
           gchar *action,
164
           GUdevDevice *device,
165
           gpointer user_data)
166
{
167
    g_debug_uevent ("uevent.c on_uevent: action=%s, devpath=%s", action, g_udev_device_get_sysfs_path(device));
168
169
    if (g_strcmp0 (action, "add") != 0 && g_strcmp0 (action, "change") != 0)
170
	return;
171
172
    /* handle firmware */
173
    if (deal_with_hplip_firmware(device))
174
       return;
175
176
    if (deal_with_missing_firmware(device))
177
	return;
580 by Martin Pitt
src/uevent.c: Add new function deal_with_scp() to launch
178
179
#ifdef ENABLE_SCP
180
    if (deal_with_scp(device))
181
	return;
182
#endif
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
183
}
184
185
void
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
186
uevent_init()
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
187
{
557 by Michael Vogt
* src/firmware.c:
188
    const gchar* subsytems[] = {"firmware", "usb", NULL};
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
189
    
190
    /* build firmware search path */
191
    struct utsname u;
192
    if (uname (&u) != 0) {
193
	g_warning("uname() failed, not monitoring firmware");
194
	return;
195
    }
196
    firmware_search_path[1] = g_strdup_printf("/lib/firmware/%s", u.release);
197
    firmware_search_path[3] = g_strdup_printf("/lib/firmware/updates/%s", u.release);
198
199
    GUdevClient* gudev = g_udev_client_new (subsytems);
200
    g_signal_connect (gudev, "uevent", G_CALLBACK (on_uevent), NULL);
559 by Michael Vogt
src/firmware.c: add cold-plug support
201
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
202
    /* cold plug HPLIP firmware */
559 by Michael Vogt
src/firmware.c: add cold-plug support
203
    GList *usb_devices, *elem;
204
    usb_devices = g_udev_client_query_by_subsystem (gudev, "usb");
580 by Martin Pitt
src/uevent.c: Add new function deal_with_scp() to launch
205
    for (elem = usb_devices; elem != NULL; elem = g_list_next(elem)) {
559 by Michael Vogt
src/firmware.c: add cold-plug support
206
       deal_with_hplip_firmware(elem->data);
580 by Martin Pitt
src/uevent.c: Add new function deal_with_scp() to launch
207
#ifdef ENABLE_SCP
208
       deal_with_scp(elem->data);
209
#endif
581 by Martin Pitt
src/uevent.c: Fix a memory leak, properly free the list items and list
210
       g_object_unref(elem->data);
580 by Martin Pitt
src/uevent.c: Add new function deal_with_scp() to launch
211
    }
581 by Martin Pitt
src/uevent.c: Fix a memory leak, properly free the list items and list
212
    g_list_free(usb_devices);
541 by Martin Pitt
Add src/firmware.{h,c}: Listen to "firmware" subsystem events, check if
213
}
573 by Michael Vogt
merged from debian
214
#else
215
#include <glib.h>
216
void
579 by Martin Pitt
* Generalize firmware backend to be more easily extensible for other types
217
uevent_init()
573 by Michael Vogt
merged from debian
218
{
219
    g_warning("Installation of firmware disabled.");
220
}
221
#endif // HAVE_GUDEV