~ubuntu-branches/ubuntu/trusty/systemd/trusty

« back to all changes in this revision

Viewing changes to src/udev/udev-builtin-usb_id.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl, Michael Biebl, Michael Stapelberg, Daniel Schaal, Ondrej Balaz
  • Date: 2013-09-12 00:13:11 UTC
  • mfrom: (1.1.11) (9.1.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 53.
  • Revision ID: package-import@ubuntu.com-20130912001311-dz35it34wr2lbday
Tags: 204-3
[ Michael Biebl ]
* Upload to unstable.
* Use /bin/bash in debug-shell.service as Debian doesn't have /sbin/sushell.
* Only import net.ifaces cmdline property for network devices.
* Generate strict dependencies between the binary packages using a
  shlibs.local file and add an explicit versioned dependency on
  libsystemd-login0 to systemd to ensure packages are upgraded in sync.
  Closes: #719444
* Drop obsolete Replaces: libudev0 from udev package.
* Use correct paths for various binaries, like /sbin/quotaon, which are
  installed in / and not /usr in Debian.  Closes: #721347
* Don't install kernel-install(8) man page since we don't install the
  corresponding binary either.  Closes: #722180
* Cherry-pick upstream fixes to make switching runlevels and starting
  reboot via ctrl-alt-del more robust.
* Cherry-pick upstream fix to properly apply ACLs to Journal files.

[ Michael Stapelberg ]
* Make systemctl enable|disable call update-rc.d for SysV init scripts.
  Closes: #709780
* Don't mount /tmp as tmpfs by default and make it possible to enable this
  feature via "systemctl enable tmp.mount".

[ Daniel Schaal ]
* Add bug-script to systemd and udev.  Closes: #711245

[ Ondrej Balaz ]
* Recognize discard option in /etc/crypttab.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * USB device properties and persistent device path
 
3
 *
 
4
 * Copyright (c) 2005 SUSE Linux Products GmbH, Germany
 
5
 *   Author: Hannes Reinecke <hare@suse.de>
 
6
 *
 
7
 * Copyright (C) 2005-2011 Kay Sievers <kay@vrfy.org>
 
8
 *
 
9
 * This program is free software: you can redistribute it and/or modify
 
10
 * it under the terms of the GNU General Public License as published by
 
11
 * the Free Software Foundation, either version 2 of the License, or
 
12
 * (at your option) any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 * GNU General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License
 
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
 */
 
22
 
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <stdarg.h>
 
26
#include <unistd.h>
 
27
#include <string.h>
 
28
#include <ctype.h>
 
29
#include <fcntl.h>
 
30
#include <errno.h>
 
31
 
 
32
#include "udev.h"
 
33
 
 
34
static void set_usb_iftype(char *to, int if_class_num, size_t len)
 
35
{
 
36
        const char *type = "generic";
 
37
 
 
38
        switch (if_class_num) {
 
39
        case 1:
 
40
                type = "audio";
 
41
                break;
 
42
        case 2: /* CDC-Control */
 
43
                break;
 
44
        case 3:
 
45
                type = "hid";
 
46
                break;
 
47
        case 5: /* Physical */
 
48
                break;
 
49
        case 6:
 
50
                type = "media";
 
51
                break;
 
52
        case 7:
 
53
                type = "printer";
 
54
                break;
 
55
        case 8:
 
56
                type = "storage";
 
57
                break;
 
58
        case 9:
 
59
                type = "hub";
 
60
                break;
 
61
        case 0x0a: /* CDC-Data */
 
62
                break;
 
63
        case 0x0b: /* Chip/Smart Card */
 
64
                break;
 
65
        case 0x0d: /* Content Security */
 
66
                break;
 
67
        case 0x0e:
 
68
                type = "video";
 
69
                break;
 
70
        case 0xdc: /* Diagnostic Device */
 
71
                break;
 
72
        case 0xe0: /* Wireless Controller */
 
73
                break;
 
74
        case 0xfe: /* Application-specific */
 
75
                break;
 
76
        case 0xff: /* Vendor-specific */
 
77
                break;
 
78
        default:
 
79
                break;
 
80
        }
 
81
        strncpy(to, type, len);
 
82
        to[len-1] = '\0';
 
83
}
 
84
 
 
85
static int set_usb_mass_storage_ifsubtype(char *to, const char *from, size_t len)
 
86
{
 
87
        int type_num = 0;
 
88
        char *eptr;
 
89
        const char *type = "generic";
 
90
 
 
91
        type_num = strtoul(from, &eptr, 0);
 
92
        if (eptr != from) {
 
93
                switch (type_num) {
 
94
                case 2:
 
95
                        type = "atapi";
 
96
                        break;
 
97
                case 3:
 
98
                        type = "tape";
 
99
                        break;
 
100
                case 4: /* UFI */
 
101
                case 5: /* SFF-8070i */
 
102
                        type = "floppy";
 
103
                        break;
 
104
                case 1: /* RBC devices */
 
105
                        type = "rbc";
 
106
                        break;
 
107
                case 6: /* Transparent SPC-2 devices */
 
108
                        type = "scsi";
 
109
                        break;
 
110
                default:
 
111
                        break;
 
112
                }
 
113
        }
 
114
        strscpy(to, len, type);
 
115
        return type_num;
 
116
}
 
117
 
 
118
static void set_scsi_type(char *to, const char *from, size_t len)
 
119
{
 
120
        int type_num;
 
121
        char *eptr;
 
122
        const char *type = "generic";
 
123
 
 
124
        type_num = strtoul(from, &eptr, 0);
 
125
        if (eptr != from) {
 
126
                switch (type_num) {
 
127
                case 0:
 
128
                case 0xe:
 
129
                        type = "disk";
 
130
                        break;
 
131
                case 1:
 
132
                        type = "tape";
 
133
                        break;
 
134
                case 4:
 
135
                case 7:
 
136
                case 0xf:
 
137
                        type = "optical";
 
138
                        break;
 
139
                case 5:
 
140
                        type = "cd";
 
141
                        break;
 
142
                default:
 
143
                        break;
 
144
                }
 
145
        }
 
146
        strscpy(to, len, type);
 
147
}
 
148
 
 
149
#define USB_DT_DEVICE                        0x01
 
150
#define USB_DT_INTERFACE                0x04
 
151
 
 
152
static int dev_if_packed_info(struct udev_device *dev, char *ifs_str, size_t len)
 
153
{
 
154
        _cleanup_free_ char *filename = NULL;
 
155
        _cleanup_close_ int fd = -1;
 
156
        ssize_t size;
 
157
        unsigned char buf[18 + 65535];
 
158
        int pos = 0;
 
159
        unsigned strpos = 0;
 
160
        struct usb_interface_descriptor {
 
161
                u_int8_t        bLength;
 
162
                u_int8_t        bDescriptorType;
 
163
                u_int8_t        bInterfaceNumber;
 
164
                u_int8_t        bAlternateSetting;
 
165
                u_int8_t        bNumEndpoints;
 
166
                u_int8_t        bInterfaceClass;
 
167
                u_int8_t        bInterfaceSubClass;
 
168
                u_int8_t        bInterfaceProtocol;
 
169
                u_int8_t        iInterface;
 
170
        } __attribute__((packed));
 
171
 
 
172
        if (asprintf(&filename, "%s/descriptors", udev_device_get_syspath(dev)) < 0)
 
173
                return log_oom();
 
174
 
 
175
        fd = open(filename, O_RDONLY|O_CLOEXEC);
 
176
        if (fd < 0) {
 
177
                fprintf(stderr, "error opening USB device 'descriptors' file\n");
 
178
                return -errno;
 
179
        }
 
180
 
 
181
        size = read(fd, buf, sizeof(buf));
 
182
        if (size < 18 || size == sizeof(buf))
 
183
                return -EIO;
 
184
 
 
185
        ifs_str[0] = '\0';
 
186
        while (pos < size && strpos+7 < len-2) {
 
187
                struct usb_interface_descriptor *desc;
 
188
                char if_str[8];
 
189
 
 
190
                desc = (struct usb_interface_descriptor *) &buf[pos];
 
191
                if (desc->bLength < 3)
 
192
                        break;
 
193
                pos += desc->bLength;
 
194
 
 
195
                if (desc->bDescriptorType != USB_DT_INTERFACE)
 
196
                        continue;
 
197
 
 
198
                if (snprintf(if_str, 8, ":%02x%02x%02x",
 
199
                             desc->bInterfaceClass,
 
200
                             desc->bInterfaceSubClass,
 
201
                             desc->bInterfaceProtocol) != 7)
 
202
                        continue;
 
203
 
 
204
                if (strstr(ifs_str, if_str) != NULL)
 
205
                        continue;
 
206
 
 
207
                memcpy(&ifs_str[strpos], if_str, 8),
 
208
                strpos += 7;
 
209
        }
 
210
 
 
211
        if (strpos > 0) {
 
212
                ifs_str[strpos++] = ':';
 
213
                ifs_str[strpos++] = '\0';
 
214
        }
 
215
 
 
216
        return 0;
 
217
}
 
218
 
 
219
/*
 
220
 * A unique USB identification is generated like this:
 
221
 *
 
222
 * 1.) Get the USB device type from InterfaceClass and InterfaceSubClass
 
223
 * 2.) If the device type is 'Mass-Storage/SPC-2' or 'Mass-Storage/RBC'
 
224
 *     use the SCSI vendor and model as USB-Vendor and USB-model.
 
225
 * 3.) Otherwise use the USB manufacturer and product as
 
226
 *     USB-Vendor and USB-model. Any non-printable characters
 
227
 *     in those strings will be skipped; a slash '/' will be converted
 
228
 *     into a full stop '.'.
 
229
 * 4.) If that fails, too, we will use idVendor and idProduct
 
230
 *     as USB-Vendor and USB-model.
 
231
 * 5.) The USB identification is the USB-vendor and USB-model
 
232
 *     string concatenated with an underscore '_'.
 
233
 * 6.) If the device supplies a serial number, this number
 
234
 *     is concatenated with the identification with an underscore '_'.
 
235
 */
 
236
static int builtin_usb_id(struct udev_device *dev, int argc, char *argv[], bool test)
 
237
{
 
238
        char vendor_str[64];
 
239
        char vendor_str_enc[256];
 
240
        const char *vendor_id;
 
241
        char model_str[64];
 
242
        char model_str_enc[256];
 
243
        const char *product_id;
 
244
        char serial_str[UTIL_NAME_SIZE];
 
245
        char packed_if_str[UTIL_NAME_SIZE];
 
246
        char revision_str[64];
 
247
        char type_str[64];
 
248
        char instance_str[64];
 
249
        const char *ifnum = NULL;
 
250
        const char *driver = NULL;
 
251
        char serial[256];
 
252
 
 
253
        struct udev_device *dev_interface = NULL;
 
254
        struct udev_device *dev_usb = NULL;
 
255
        const char *if_class, *if_subclass;
 
256
        int if_class_num;
 
257
        int protocol = 0;
 
258
        size_t l;
 
259
        char *s;
 
260
 
 
261
        vendor_str[0] = '\0';
 
262
        model_str[0] = '\0';
 
263
        serial_str[0] = '\0';
 
264
        packed_if_str[0] = '\0';
 
265
        revision_str[0] = '\0';
 
266
        type_str[0] = '\0';
 
267
        instance_str[0] = '\0';
 
268
 
 
269
        /* shortcut, if we are called directly for a "usb_device" type */
 
270
        if (udev_device_get_devtype(dev) != NULL && streq(udev_device_get_devtype(dev), "usb_device")) {
 
271
                dev_if_packed_info(dev, packed_if_str, sizeof(packed_if_str));
 
272
                dev_usb = dev;
 
273
                goto fallback;
 
274
        }
 
275
 
 
276
        /* usb interface directory */
 
277
        dev_interface = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
 
278
        if (dev_interface == NULL) {
 
279
                log_debug("unable to access usb_interface device of '%s'\n",
 
280
                     udev_device_get_syspath(dev));
 
281
                return EXIT_FAILURE;
 
282
        }
 
283
 
 
284
        ifnum = udev_device_get_sysattr_value(dev_interface, "bInterfaceNumber");
 
285
        driver = udev_device_get_sysattr_value(dev_interface, "driver");
 
286
 
 
287
        if_class = udev_device_get_sysattr_value(dev_interface, "bInterfaceClass");
 
288
        if (!if_class) {
 
289
                log_debug("%s: cannot get bInterfaceClass attribute\n",
 
290
                     udev_device_get_sysname(dev));
 
291
                return EXIT_FAILURE;
 
292
        }
 
293
 
 
294
        if_class_num = strtoul(if_class, NULL, 16);
 
295
        if (if_class_num == 8) {
 
296
                /* mass storage */
 
297
                if_subclass = udev_device_get_sysattr_value(dev_interface, "bInterfaceSubClass");
 
298
                if (if_subclass != NULL)
 
299
                        protocol = set_usb_mass_storage_ifsubtype(type_str, if_subclass, sizeof(type_str)-1);
 
300
        } else {
 
301
                set_usb_iftype(type_str, if_class_num, sizeof(type_str)-1);
 
302
        }
 
303
 
 
304
        log_debug("%s: if_class %d protocol %d\n",
 
305
             udev_device_get_syspath(dev_interface), if_class_num, protocol);
 
306
 
 
307
        /* usb device directory */
 
308
        dev_usb = udev_device_get_parent_with_subsystem_devtype(dev_interface, "usb", "usb_device");
 
309
        if (!dev_usb) {
 
310
                log_debug("unable to find parent 'usb' device of '%s'\n",
 
311
                     udev_device_get_syspath(dev));
 
312
                return EXIT_FAILURE;
 
313
        }
 
314
 
 
315
        /* all interfaces of the device in a single string */
 
316
        dev_if_packed_info(dev_usb, packed_if_str, sizeof(packed_if_str));
 
317
 
 
318
        /* mass storage : SCSI or ATAPI */
 
319
        if ((protocol == 6 || protocol == 2)) {
 
320
                struct udev_device *dev_scsi;
 
321
                const char *scsi_model, *scsi_vendor, *scsi_type, *scsi_rev;
 
322
                int host, bus, target, lun;
 
323
 
 
324
                /* get scsi device */
 
325
                dev_scsi = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device");
 
326
                if (dev_scsi == NULL) {
 
327
                        log_debug("unable to find parent 'scsi' device of '%s'\n",
 
328
                             udev_device_get_syspath(dev));
 
329
                        goto fallback;
 
330
                }
 
331
                if (sscanf(udev_device_get_sysname(dev_scsi), "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4) {
 
332
                        log_debug("invalid scsi device '%s'\n", udev_device_get_sysname(dev_scsi));
 
333
                        goto fallback;
 
334
                }
 
335
 
 
336
                /* Generic SPC-2 device */
 
337
                scsi_vendor = udev_device_get_sysattr_value(dev_scsi, "vendor");
 
338
                if (!scsi_vendor) {
 
339
                        log_debug("%s: cannot get SCSI vendor attribute\n",
 
340
                             udev_device_get_sysname(dev_scsi));
 
341
                        goto fallback;
 
342
                }
 
343
                udev_util_encode_string(scsi_vendor, vendor_str_enc, sizeof(vendor_str_enc));
 
344
                util_replace_whitespace(scsi_vendor, vendor_str, sizeof(vendor_str)-1);
 
345
                util_replace_chars(vendor_str, NULL);
 
346
 
 
347
                scsi_model = udev_device_get_sysattr_value(dev_scsi, "model");
 
348
                if (!scsi_model) {
 
349
                        log_debug("%s: cannot get SCSI model attribute\n",
 
350
                             udev_device_get_sysname(dev_scsi));
 
351
                        goto fallback;
 
352
                }
 
353
                udev_util_encode_string(scsi_model, model_str_enc, sizeof(model_str_enc));
 
354
                util_replace_whitespace(scsi_model, model_str, sizeof(model_str)-1);
 
355
                util_replace_chars(model_str, NULL);
 
356
 
 
357
                scsi_type = udev_device_get_sysattr_value(dev_scsi, "type");
 
358
                if (!scsi_type) {
 
359
                        log_debug("%s: cannot get SCSI type attribute\n",
 
360
                             udev_device_get_sysname(dev_scsi));
 
361
                        goto fallback;
 
362
                }
 
363
                set_scsi_type(type_str, scsi_type, sizeof(type_str)-1);
 
364
 
 
365
                scsi_rev = udev_device_get_sysattr_value(dev_scsi, "rev");
 
366
                if (!scsi_rev) {
 
367
                        log_debug("%s: cannot get SCSI revision attribute\n",
 
368
                             udev_device_get_sysname(dev_scsi));
 
369
                        goto fallback;
 
370
                }
 
371
                util_replace_whitespace(scsi_rev, revision_str, sizeof(revision_str)-1);
 
372
                util_replace_chars(revision_str, NULL);
 
373
 
 
374
                /*
 
375
                 * some broken devices have the same identifiers
 
376
                 * for all luns, export the target:lun number
 
377
                 */
 
378
                sprintf(instance_str, "%d:%d", target, lun);
 
379
        }
 
380
 
 
381
fallback:
 
382
        vendor_id = udev_device_get_sysattr_value(dev_usb, "idVendor");
 
383
        product_id = udev_device_get_sysattr_value(dev_usb, "idProduct");
 
384
 
 
385
        /* fallback to USB vendor & device */
 
386
        if (vendor_str[0] == '\0') {
 
387
                const char *usb_vendor = NULL;
 
388
 
 
389
                usb_vendor = udev_device_get_sysattr_value(dev_usb, "manufacturer");
 
390
                if (!usb_vendor)
 
391
                        usb_vendor = vendor_id;
 
392
                if (!usb_vendor) {
 
393
                        log_debug("No USB vendor information available\n");
 
394
                        return EXIT_FAILURE;
 
395
                }
 
396
                udev_util_encode_string(usb_vendor, vendor_str_enc, sizeof(vendor_str_enc));
 
397
                util_replace_whitespace(usb_vendor, vendor_str, sizeof(vendor_str)-1);
 
398
                util_replace_chars(vendor_str, NULL);
 
399
        }
 
400
 
 
401
        if (model_str[0] == '\0') {
 
402
                const char *usb_model = NULL;
 
403
 
 
404
                usb_model = udev_device_get_sysattr_value(dev_usb, "product");
 
405
                if (!usb_model)
 
406
                        usb_model = product_id;
 
407
                if (!usb_model)
 
408
                        return EXIT_FAILURE;
 
409
                udev_util_encode_string(usb_model, model_str_enc, sizeof(model_str_enc));
 
410
                util_replace_whitespace(usb_model, model_str, sizeof(model_str)-1);
 
411
                util_replace_chars(model_str, NULL);
 
412
        }
 
413
 
 
414
        if (revision_str[0] == '\0') {
 
415
                const char *usb_rev;
 
416
 
 
417
                usb_rev = udev_device_get_sysattr_value(dev_usb, "bcdDevice");
 
418
                if (usb_rev) {
 
419
                        util_replace_whitespace(usb_rev, revision_str, sizeof(revision_str)-1);
 
420
                        util_replace_chars(revision_str, NULL);
 
421
                }
 
422
        }
 
423
 
 
424
        if (serial_str[0] == '\0') {
 
425
                const char *usb_serial;
 
426
 
 
427
                usb_serial = udev_device_get_sysattr_value(dev_usb, "serial");
 
428
                if (usb_serial) {
 
429
                        const unsigned char *p;
 
430
 
 
431
                        /* http://msdn.microsoft.com/en-us/library/windows/hardware/gg487321.aspx */
 
432
                        for (p = (unsigned char *)usb_serial; *p != '\0'; p++)
 
433
                                if (*p < 0x20 || *p > 0x7f || *p == ',') {
 
434
                                        usb_serial = NULL;
 
435
                                        break;
 
436
                                }
 
437
                }
 
438
 
 
439
                if (usb_serial) {
 
440
                        util_replace_whitespace(usb_serial, serial_str, sizeof(serial_str)-1);
 
441
                        util_replace_chars(serial_str, NULL);
 
442
                }
 
443
        }
 
444
 
 
445
        s = serial;
 
446
        l = strpcpyl(&s, sizeof(serial), vendor_str, "_", model_str, NULL);
 
447
        if (serial_str[0] != '\0')
 
448
                l = strpcpyl(&s, l, "_", serial_str, NULL);
 
449
 
 
450
        if (instance_str[0] != '\0')
 
451
                strpcpyl(&s, l, "-", instance_str, NULL);
 
452
 
 
453
        udev_builtin_add_property(dev, test, "ID_VENDOR", vendor_str);
 
454
        udev_builtin_add_property(dev, test, "ID_VENDOR_ENC", vendor_str_enc);
 
455
        udev_builtin_add_property(dev, test, "ID_VENDOR_ID", vendor_id);
 
456
        udev_builtin_add_property(dev, test, "ID_MODEL", model_str);
 
457
        udev_builtin_add_property(dev, test, "ID_MODEL_ENC", model_str_enc);
 
458
        udev_builtin_add_property(dev, test, "ID_MODEL_ID", product_id);
 
459
        udev_builtin_add_property(dev, test, "ID_REVISION", revision_str);
 
460
        udev_builtin_add_property(dev, test, "ID_SERIAL", serial);
 
461
        if (serial_str[0] != '\0')
 
462
                udev_builtin_add_property(dev, test, "ID_SERIAL_SHORT", serial_str);
 
463
        if (type_str[0] != '\0')
 
464
                udev_builtin_add_property(dev, test, "ID_TYPE", type_str);
 
465
        if (instance_str[0] != '\0')
 
466
                udev_builtin_add_property(dev, test, "ID_INSTANCE", instance_str);
 
467
        udev_builtin_add_property(dev, test, "ID_BUS", "usb");
 
468
        if (packed_if_str[0] != '\0')
 
469
                udev_builtin_add_property(dev, test, "ID_USB_INTERFACES", packed_if_str);
 
470
        if (ifnum != NULL)
 
471
                udev_builtin_add_property(dev, test, "ID_USB_INTERFACE_NUM", ifnum);
 
472
        if (driver != NULL)
 
473
                udev_builtin_add_property(dev, test, "ID_USB_DRIVER", driver);
 
474
        return EXIT_SUCCESS;
 
475
}
 
476
 
 
477
const struct udev_builtin udev_builtin_usb_id = {
 
478
        .name = "usb_id",
 
479
        .cmd = builtin_usb_id,
 
480
        .help = "usb device properties",
 
481
        .run_once = true,
 
482
};