summaryrefslogtreecommitdiff
path: root/src/udev
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2016-12-17 03:04:41 -0500
committerLuke Shumaker <lukeshu@sbcglobal.net>2016-12-17 03:04:41 -0500
commitfd6ea8a3f4999133f8ac036a23584c3e5f9e9b3f (patch)
tree6cdd53846655b04b178b4b8057c915c61a9cb525 /src/udev
parent1841fdb0b10cb37b55d1af644a7e6edc4ab66cbd (diff)
./tools/notsd-move
Diffstat (limited to 'src/udev')
-rw-r--r--src/udev/.gitignore4
-rw-r--r--src/udev/.vimrc4
l---------src/udev/Makefile1
l---------src/udev/ata_id/Makefile1
-rw-r--r--src/udev/ata_id/ata_id.c674
l---------src/udev/cdrom_id/Makefile1
-rw-r--r--src/udev/cdrom_id/cdrom_id.c1085
l---------src/udev/collect/Makefile1
-rw-r--r--src/udev/collect/collect.c491
l---------src/udev/mtd_probe/Makefile1
-rw-r--r--src/udev/mtd_probe/mtd_probe.c56
-rw-r--r--src/udev/mtd_probe/mtd_probe.h51
-rw-r--r--src/udev/mtd_probe/probe_smartmedia.c96
-rw-r--r--src/udev/net/.gitignore1
l---------src/udev/net/Makefile1
-rw-r--r--src/udev/net/ethtool-util.c325
-rw-r--r--src/udev/net/ethtool-util.h65
-rw-r--r--src/udev/net/link-config-gperf.gperf42
-rw-r--r--src/udev/net/link-config.c517
-rw-r--r--src/udev/net/link-config.h99
-rw-r--r--src/udev/scsi_id/.gitignore1
l---------src/udev/scsi_id/Makefile1
-rw-r--r--src/udev/scsi_id/README4
-rw-r--r--src/udev/scsi_id/scsi.h99
-rw-r--r--src/udev/scsi_id/scsi_id.c625
-rw-r--r--src/udev/scsi_id/scsi_id.h75
-rw-r--r--src/udev/scsi_id/scsi_serial.c964
-rw-r--r--src/udev/udev-builtin-blkid.c337
-rw-r--r--src/udev/udev-builtin-btrfs.c58
-rw-r--r--src/udev/udev-builtin-hwdb.c223
-rw-r--r--src/udev/udev-builtin-input_id.c340
-rw-r--r--src/udev/udev-builtin-keyboard.c277
-rw-r--r--src/udev/udev-builtin-kmod.c123
-rw-r--r--src/udev/udev-builtin-net_id.c638
-rw-r--r--src/udev/udev-builtin-net_setup_link.c107
-rw-r--r--src/udev/udev-builtin-path_id.c770
-rw-r--r--src/udev/udev-builtin-uaccess.c88
-rw-r--r--src/udev/udev-builtin-usb_id.c473
-rw-r--r--src/udev/udev-builtin.c142
-rw-r--r--src/udev/udev-ctrl.c461
-rw-r--r--src/udev/udev-event.c943
-rw-r--r--src/udev/udev-node.c375
-rw-r--r--src/udev/udev-rules.c2582
-rw-r--r--src/udev/udev-watch.c152
-rw-r--r--src/udev/udev.conf3
-rw-r--r--src/udev/udev.h216
-rw-r--r--src/udev/udev.pc.in5
-rw-r--r--src/udev/udevadm-control.c172
-rw-r--r--src/udev/udevadm-hwdb.c698
-rw-r--r--src/udev/udevadm-info.c480
-rw-r--r--src/udev/udevadm-monitor.c281
-rw-r--r--src/udev/udevadm-settle.c162
-rw-r--r--src/udev/udevadm-test-builtin.c112
-rw-r--r--src/udev/udevadm-test.c160
-rw-r--r--src/udev/udevadm-trigger.c286
-rw-r--r--src/udev/udevadm-util.c50
-rw-r--r--src/udev/udevadm-util.h24
-rw-r--r--src/udev/udevadm.c137
-rw-r--r--src/udev/udevd.c1757
l---------src/udev/v4l_id/Makefile1
-rw-r--r--src/udev/v4l_id/v4l_id.c86
61 files changed, 0 insertions, 18004 deletions
diff --git a/src/udev/.gitignore b/src/udev/.gitignore
deleted file mode 100644
index f5d8be3dc1..0000000000
--- a/src/udev/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-/udev.pc
-/keyboard-keys-from-name.gperf
-/keyboard-keys-from-name.h
-/keyboard-keys-list.txt
diff --git a/src/udev/.vimrc b/src/udev/.vimrc
deleted file mode 100644
index 366fbdca4b..0000000000
--- a/src/udev/.vimrc
+++ /dev/null
@@ -1,4 +0,0 @@
-" 'set exrc' in ~/.vimrc will read .vimrc from the current directory
-set tabstop=8
-set shiftwidth=8
-set expandtab
diff --git a/src/udev/Makefile b/src/udev/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/ata_id/Makefile b/src/udev/ata_id/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/ata_id/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c
deleted file mode 100644
index 1e414664ce..0000000000
--- a/src/udev/ata_id/ata_id.c
+++ /dev/null
@@ -1,674 +0,0 @@
-/*
- * ata_id - reads product/serial number from ATA drives
- *
- * Copyright (C) 2005-2008 Kay Sievers <kay@vrfy.org>
- * Copyright (C) 2009 Lennart Poettering <lennart@poettering.net>
- * Copyright (C) 2009-2010 David Zeuthen <zeuthen@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <linux/bsg.h>
-#include <linux/hdreg.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_ioctl.h>
-#include <scsi/sg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "libudev.h"
-
-#include "fd-util.h"
-#include "libudev-private.h"
-#include "log.h"
-#include "udev-util.h"
-
-#define COMMAND_TIMEOUT_MSEC (30 * 1000)
-
-static int disk_scsi_inquiry_command(int fd,
- void *buf,
- size_t buf_len)
-{
- uint8_t cdb[6] = {
- /*
- * INQUIRY, see SPC-4 section 6.4
- */
- [0] = 0x12, /* OPERATION CODE: INQUIRY */
- [3] = (buf_len >> 8), /* ALLOCATION LENGTH */
- [4] = (buf_len & 0xff),
- };
- uint8_t sense[32] = {};
- struct sg_io_v4 io_v4 = {
- .guard = 'Q',
- .protocol = BSG_PROTOCOL_SCSI,
- .subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD,
- .request_len = sizeof(cdb),
- .request = (uintptr_t) cdb,
- .max_response_len = sizeof(sense),
- .response = (uintptr_t) sense,
- .din_xfer_len = buf_len,
- .din_xferp = (uintptr_t) buf,
- .timeout = COMMAND_TIMEOUT_MSEC,
- };
- int ret;
-
- ret = ioctl(fd, SG_IO, &io_v4);
- if (ret != 0) {
- /* could be that the driver doesn't do version 4, try version 3 */
- if (errno == EINVAL) {
- struct sg_io_hdr io_hdr = {
- .interface_id = 'S',
- .cmdp = (unsigned char*) cdb,
- .cmd_len = sizeof (cdb),
- .dxferp = buf,
- .dxfer_len = buf_len,
- .sbp = sense,
- .mx_sb_len = sizeof(sense),
- .dxfer_direction = SG_DXFER_FROM_DEV,
- .timeout = COMMAND_TIMEOUT_MSEC,
- };
-
- ret = ioctl(fd, SG_IO, &io_hdr);
- if (ret != 0)
- return ret;
-
- /* even if the ioctl succeeds, we need to check the return value */
- if (!(io_hdr.status == 0 &&
- io_hdr.host_status == 0 &&
- io_hdr.driver_status == 0)) {
- errno = EIO;
- return -1;
- }
- } else
- return ret;
- }
-
- /* even if the ioctl succeeds, we need to check the return value */
- if (!(io_v4.device_status == 0 &&
- io_v4.transport_status == 0 &&
- io_v4.driver_status == 0)) {
- errno = EIO;
- return -1;
- }
-
- return 0;
-}
-
-static int disk_identify_command(int fd,
- void *buf,
- size_t buf_len)
-{
- uint8_t cdb[12] = {
- /*
- * ATA Pass-Through 12 byte command, as described in
- *
- * T10 04-262r8 ATA Command Pass-Through
- *
- * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf
- */
- [0] = 0xa1, /* OPERATION CODE: 12 byte pass through */
- [1] = 4 << 1, /* PROTOCOL: PIO Data-in */
- [2] = 0x2e, /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */
- [3] = 0, /* FEATURES */
- [4] = 1, /* SECTORS */
- [5] = 0, /* LBA LOW */
- [6] = 0, /* LBA MID */
- [7] = 0, /* LBA HIGH */
- [8] = 0 & 0x4F, /* SELECT */
- [9] = 0xEC, /* Command: ATA IDENTIFY DEVICE */
- };
- uint8_t sense[32] = {};
- uint8_t *desc = sense + 8;
- struct sg_io_v4 io_v4 = {
- .guard = 'Q',
- .protocol = BSG_PROTOCOL_SCSI,
- .subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD,
- .request_len = sizeof(cdb),
- .request = (uintptr_t) cdb,
- .max_response_len = sizeof(sense),
- .response = (uintptr_t) sense,
- .din_xfer_len = buf_len,
- .din_xferp = (uintptr_t) buf,
- .timeout = COMMAND_TIMEOUT_MSEC,
- };
- int ret;
-
- ret = ioctl(fd, SG_IO, &io_v4);
- if (ret != 0) {
- /* could be that the driver doesn't do version 4, try version 3 */
- if (errno == EINVAL) {
- struct sg_io_hdr io_hdr = {
- .interface_id = 'S',
- .cmdp = (unsigned char*) cdb,
- .cmd_len = sizeof (cdb),
- .dxferp = buf,
- .dxfer_len = buf_len,
- .sbp = sense,
- .mx_sb_len = sizeof (sense),
- .dxfer_direction = SG_DXFER_FROM_DEV,
- .timeout = COMMAND_TIMEOUT_MSEC,
- };
-
- ret = ioctl(fd, SG_IO, &io_hdr);
- if (ret != 0)
- return ret;
- } else
- return ret;
- }
-
- if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) {
- errno = EIO;
- return -1;
- }
-
- return 0;
-}
-
-static int disk_identify_packet_device_command(int fd,
- void *buf,
- size_t buf_len)
-{
- uint8_t cdb[16] = {
- /*
- * ATA Pass-Through 16 byte command, as described in
- *
- * T10 04-262r8 ATA Command Pass-Through
- *
- * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf
- */
- [0] = 0x85, /* OPERATION CODE: 16 byte pass through */
- [1] = 4 << 1, /* PROTOCOL: PIO Data-in */
- [2] = 0x2e, /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */
- [3] = 0, /* FEATURES */
- [4] = 0, /* FEATURES */
- [5] = 0, /* SECTORS */
- [6] = 1, /* SECTORS */
- [7] = 0, /* LBA LOW */
- [8] = 0, /* LBA LOW */
- [9] = 0, /* LBA MID */
- [10] = 0, /* LBA MID */
- [11] = 0, /* LBA HIGH */
- [12] = 0, /* LBA HIGH */
- [13] = 0, /* DEVICE */
- [14] = 0xA1, /* Command: ATA IDENTIFY PACKET DEVICE */
- [15] = 0, /* CONTROL */
- };
- uint8_t sense[32] = {};
- uint8_t *desc = sense + 8;
- struct sg_io_v4 io_v4 = {
- .guard = 'Q',
- .protocol = BSG_PROTOCOL_SCSI,
- .subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD,
- .request_len = sizeof (cdb),
- .request = (uintptr_t) cdb,
- .max_response_len = sizeof (sense),
- .response = (uintptr_t) sense,
- .din_xfer_len = buf_len,
- .din_xferp = (uintptr_t) buf,
- .timeout = COMMAND_TIMEOUT_MSEC,
- };
- int ret;
-
- ret = ioctl(fd, SG_IO, &io_v4);
- if (ret != 0) {
- /* could be that the driver doesn't do version 4, try version 3 */
- if (errno == EINVAL) {
- struct sg_io_hdr io_hdr = {
- .interface_id = 'S',
- .cmdp = (unsigned char*) cdb,
- .cmd_len = sizeof (cdb),
- .dxferp = buf,
- .dxfer_len = buf_len,
- .sbp = sense,
- .mx_sb_len = sizeof (sense),
- .dxfer_direction = SG_DXFER_FROM_DEV,
- .timeout = COMMAND_TIMEOUT_MSEC,
- };
-
- ret = ioctl(fd, SG_IO, &io_hdr);
- if (ret != 0)
- return ret;
- } else
- return ret;
- }
-
- if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) {
- errno = EIO;
- return -1;
- }
-
- return 0;
-}
-
-/**
- * disk_identify_get_string:
- * @identify: A block of IDENTIFY data
- * @offset_words: Offset of the string to get, in words.
- * @dest: Destination buffer for the string.
- * @dest_len: Length of destination buffer, in bytes.
- *
- * Copies the ATA string from @identify located at @offset_words into @dest.
- */
-static void disk_identify_get_string(uint8_t identify[512],
- unsigned int offset_words,
- char *dest,
- size_t dest_len)
-{
- unsigned int c1;
- unsigned int c2;
-
- while (dest_len > 0) {
- c1 = identify[offset_words * 2 + 1];
- c2 = identify[offset_words * 2];
- *dest = c1;
- dest++;
- *dest = c2;
- dest++;
- offset_words++;
- dest_len -= 2;
- }
-}
-
-static void disk_identify_fixup_string(uint8_t identify[512],
- unsigned int offset_words,
- size_t len)
-{
- disk_identify_get_string(identify, offset_words,
- (char *) identify + offset_words * 2, len);
-}
-
-static void disk_identify_fixup_uint16 (uint8_t identify[512], unsigned int offset_words)
-{
- uint16_t *p;
-
- p = (uint16_t *) identify;
- p[offset_words] = le16toh (p[offset_words]);
-}
-
-/**
- * disk_identify:
- * @udev: The libudev context.
- * @fd: File descriptor for the block device.
- * @out_identify: Return location for IDENTIFY data.
- * @out_is_packet_device: Return location for whether returned data is from a IDENTIFY PACKET DEVICE.
- *
- * Sends the IDENTIFY DEVICE or IDENTIFY PACKET DEVICE command to the
- * device represented by @fd. If successful, then the result will be
- * copied into @out_identify and @out_is_packet_device.
- *
- * This routine is based on code from libatasmart, Copyright 2008
- * Lennart Poettering, LGPL v2.1.
- *
- * Returns: 0 if the data was successfully obtained, otherwise
- * non-zero with errno set.
- */
-static int disk_identify(struct udev *udev,
- int fd,
- uint8_t out_identify[512],
- int *out_is_packet_device)
-{
- int ret;
- uint8_t inquiry_buf[36];
- int peripheral_device_type;
- int all_nul_bytes;
- int n;
- int is_packet_device = 0;
-
- /* init results */
- memzero(out_identify, 512);
-
- /* If we were to use ATA PASS_THROUGH (12) on an ATAPI device
- * we could accidentally blank media. This is because MMC's BLANK
- * command has the same op-code (0x61).
- *
- * To prevent this from happening we bail out if the device
- * isn't a Direct Access Block Device, e.g. SCSI type 0x00
- * (CD/DVD devices are type 0x05). So we send a SCSI INQUIRY
- * command first... libata is handling this via its SCSI
- * emulation layer.
- *
- * This also ensures that we're actually dealing with a device
- * that understands SCSI commands.
- *
- * (Yes, it is a bit perverse that we're tunneling the ATA
- * command through SCSI and relying on the ATA driver
- * emulating SCSI well-enough...)
- *
- * (See commit 160b069c25690bfb0c785994c7c3710289179107 for
- * the original bug-fix and see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=556635
- * for the original bug-report.)
- */
- ret = disk_scsi_inquiry_command (fd, inquiry_buf, sizeof (inquiry_buf));
- if (ret != 0)
- goto out;
-
- /* SPC-4, section 6.4.2: Standard INQUIRY data */
- peripheral_device_type = inquiry_buf[0] & 0x1f;
- if (peripheral_device_type == 0x05)
- {
- is_packet_device = 1;
- ret = disk_identify_packet_device_command(fd, out_identify, 512);
- goto check_nul_bytes;
- }
- if (peripheral_device_type != 0x00) {
- ret = -1;
- errno = EIO;
- goto out;
- }
-
- /* OK, now issue the IDENTIFY DEVICE command */
- ret = disk_identify_command(fd, out_identify, 512);
- if (ret != 0)
- goto out;
-
- check_nul_bytes:
- /* Check if IDENTIFY data is all NUL bytes - if so, bail */
- all_nul_bytes = 1;
- for (n = 0; n < 512; n++) {
- if (out_identify[n] != '\0') {
- all_nul_bytes = 0;
- break;
- }
- }
-
- if (all_nul_bytes) {
- ret = -1;
- errno = EIO;
- goto out;
- }
-
-out:
- if (out_is_packet_device != NULL)
- *out_is_packet_device = is_packet_device;
- return ret;
-}
-
-int main(int argc, char *argv[])
-{
- _cleanup_udev_unref_ struct udev *udev = NULL;
- struct hd_driveid id;
- union {
- uint8_t byte[512];
- uint16_t wyde[256];
- } identify;
- char model[41];
- char model_enc[256];
- char serial[21];
- char revision[9];
- const char *node = NULL;
- int export = 0;
- _cleanup_close_ int fd = -1;
- uint16_t word;
- int is_packet_device = 0;
- static const struct option options[] = {
- { "export", no_argument, NULL, 'x' },
- { "help", no_argument, NULL, 'h' },
- {}
- };
-
- log_parse_environment();
- log_open();
-
- udev = udev_new();
- if (udev == NULL)
- return 0;
-
- for (;;) {
- int option;
-
- option = getopt_long(argc, argv, "xh", options, NULL);
- if (option == -1)
- break;
-
- switch (option) {
- case 'x':
- export = 1;
- break;
- case 'h':
- printf("Usage: ata_id [--export] [--help] <device>\n"
- " -x,--export print values as environment keys\n"
- " -h,--help print this help text\n\n");
- return 0;
- }
- }
-
- node = argv[optind];
- if (node == NULL) {
- log_error("no node specified");
- return 1;
- }
-
- fd = open(node, O_RDONLY|O_NONBLOCK|O_CLOEXEC);
- if (fd < 0) {
- log_error("unable to open '%s'", node);
- return 1;
- }
-
- if (disk_identify(udev, fd, identify.byte, &is_packet_device) == 0) {
- /*
- * fix up only the fields from the IDENTIFY data that we are going to
- * use and copy it into the hd_driveid struct for convenience
- */
- disk_identify_fixup_string(identify.byte, 10, 20); /* serial */
- disk_identify_fixup_string(identify.byte, 23, 8); /* fwrev */
- disk_identify_fixup_string(identify.byte, 27, 40); /* model */
- disk_identify_fixup_uint16(identify.byte, 0); /* configuration */
- disk_identify_fixup_uint16(identify.byte, 75); /* queue depth */
- disk_identify_fixup_uint16(identify.byte, 76); /* SATA capabilities */
- disk_identify_fixup_uint16(identify.byte, 82); /* command set supported */
- disk_identify_fixup_uint16(identify.byte, 83); /* command set supported */
- disk_identify_fixup_uint16(identify.byte, 84); /* command set supported */
- disk_identify_fixup_uint16(identify.byte, 85); /* command set supported */
- disk_identify_fixup_uint16(identify.byte, 86); /* command set supported */
- disk_identify_fixup_uint16(identify.byte, 87); /* command set supported */
- disk_identify_fixup_uint16(identify.byte, 89); /* time required for SECURITY ERASE UNIT */
- disk_identify_fixup_uint16(identify.byte, 90); /* time required for enhanced SECURITY ERASE UNIT */
- disk_identify_fixup_uint16(identify.byte, 91); /* current APM values */
- disk_identify_fixup_uint16(identify.byte, 94); /* current AAM value */
- disk_identify_fixup_uint16(identify.byte, 108); /* WWN */
- disk_identify_fixup_uint16(identify.byte, 109); /* WWN */
- disk_identify_fixup_uint16(identify.byte, 110); /* WWN */
- disk_identify_fixup_uint16(identify.byte, 111); /* WWN */
- disk_identify_fixup_uint16(identify.byte, 128); /* device lock function */
- disk_identify_fixup_uint16(identify.byte, 217); /* nominal media rotation rate */
- memcpy(&id, identify.byte, sizeof id);
- } else {
- /* If this fails, then try HDIO_GET_IDENTITY */
- if (ioctl(fd, HDIO_GET_IDENTITY, &id) != 0) {
- log_debug_errno(errno, "HDIO_GET_IDENTITY failed for '%s': %m", node);
- return 2;
- }
- }
-
- memcpy(model, id.model, 40);
- model[40] = '\0';
- udev_util_encode_string(model, model_enc, sizeof(model_enc));
- util_replace_whitespace((char *) id.model, model, 40);
- util_replace_chars(model, NULL);
- util_replace_whitespace((char *) id.serial_no, serial, 20);
- util_replace_chars(serial, NULL);
- util_replace_whitespace((char *) id.fw_rev, revision, 8);
- util_replace_chars(revision, NULL);
-
- if (export) {
- /* Set this to convey the disk speaks the ATA protocol */
- printf("ID_ATA=1\n");
-
- if ((id.config >> 8) & 0x80) {
- /* This is an ATAPI device */
- switch ((id.config >> 8) & 0x1f) {
- case 0:
- printf("ID_TYPE=cd\n");
- break;
- case 1:
- printf("ID_TYPE=tape\n");
- break;
- case 5:
- printf("ID_TYPE=cd\n");
- break;
- case 7:
- printf("ID_TYPE=optical\n");
- break;
- default:
- printf("ID_TYPE=generic\n");
- break;
- }
- } else {
- printf("ID_TYPE=disk\n");
- }
- printf("ID_BUS=ata\n");
- printf("ID_MODEL=%s\n", model);
- printf("ID_MODEL_ENC=%s\n", model_enc);
- printf("ID_REVISION=%s\n", revision);
- if (serial[0] != '\0') {
- printf("ID_SERIAL=%s_%s\n", model, serial);
- printf("ID_SERIAL_SHORT=%s\n", serial);
- } else {
- printf("ID_SERIAL=%s\n", model);
- }
-
- if (id.command_set_1 & (1<<5)) {
- printf("ID_ATA_WRITE_CACHE=1\n");
- printf("ID_ATA_WRITE_CACHE_ENABLED=%d\n", (id.cfs_enable_1 & (1<<5)) ? 1 : 0);
- }
- if (id.command_set_1 & (1<<10)) {
- printf("ID_ATA_FEATURE_SET_HPA=1\n");
- printf("ID_ATA_FEATURE_SET_HPA_ENABLED=%d\n", (id.cfs_enable_1 & (1<<10)) ? 1 : 0);
-
- /*
- * TODO: use the READ NATIVE MAX ADDRESS command to get the native max address
- * so it is easy to check whether the protected area is in use.
- */
- }
- if (id.command_set_1 & (1<<3)) {
- printf("ID_ATA_FEATURE_SET_PM=1\n");
- printf("ID_ATA_FEATURE_SET_PM_ENABLED=%d\n", (id.cfs_enable_1 & (1<<3)) ? 1 : 0);
- }
- if (id.command_set_1 & (1<<1)) {
- printf("ID_ATA_FEATURE_SET_SECURITY=1\n");
- printf("ID_ATA_FEATURE_SET_SECURITY_ENABLED=%d\n", (id.cfs_enable_1 & (1<<1)) ? 1 : 0);
- printf("ID_ATA_FEATURE_SET_SECURITY_ERASE_UNIT_MIN=%d\n", id.trseuc * 2);
- if ((id.cfs_enable_1 & (1<<1))) /* enabled */ {
- if (id.dlf & (1<<8))
- printf("ID_ATA_FEATURE_SET_SECURITY_LEVEL=maximum\n");
- else
- printf("ID_ATA_FEATURE_SET_SECURITY_LEVEL=high\n");
- }
- if (id.dlf & (1<<5))
- printf("ID_ATA_FEATURE_SET_SECURITY_ENHANCED_ERASE_UNIT_MIN=%d\n", id.trsEuc * 2);
- if (id.dlf & (1<<4))
- printf("ID_ATA_FEATURE_SET_SECURITY_EXPIRE=1\n");
- if (id.dlf & (1<<3))
- printf("ID_ATA_FEATURE_SET_SECURITY_FROZEN=1\n");
- if (id.dlf & (1<<2))
- printf("ID_ATA_FEATURE_SET_SECURITY_LOCKED=1\n");
- }
- if (id.command_set_1 & (1<<0)) {
- printf("ID_ATA_FEATURE_SET_SMART=1\n");
- printf("ID_ATA_FEATURE_SET_SMART_ENABLED=%d\n", (id.cfs_enable_1 & (1<<0)) ? 1 : 0);
- }
- if (id.command_set_2 & (1<<9)) {
- printf("ID_ATA_FEATURE_SET_AAM=1\n");
- printf("ID_ATA_FEATURE_SET_AAM_ENABLED=%d\n", (id.cfs_enable_2 & (1<<9)) ? 1 : 0);
- printf("ID_ATA_FEATURE_SET_AAM_VENDOR_RECOMMENDED_VALUE=%d\n", id.acoustic >> 8);
- printf("ID_ATA_FEATURE_SET_AAM_CURRENT_VALUE=%d\n", id.acoustic & 0xff);
- }
- if (id.command_set_2 & (1<<5)) {
- printf("ID_ATA_FEATURE_SET_PUIS=1\n");
- printf("ID_ATA_FEATURE_SET_PUIS_ENABLED=%d\n", (id.cfs_enable_2 & (1<<5)) ? 1 : 0);
- }
- if (id.command_set_2 & (1<<3)) {
- printf("ID_ATA_FEATURE_SET_APM=1\n");
- printf("ID_ATA_FEATURE_SET_APM_ENABLED=%d\n", (id.cfs_enable_2 & (1<<3)) ? 1 : 0);
- if ((id.cfs_enable_2 & (1<<3)))
- printf("ID_ATA_FEATURE_SET_APM_CURRENT_VALUE=%d\n", id.CurAPMvalues & 0xff);
- }
- if (id.command_set_2 & (1<<0))
- printf("ID_ATA_DOWNLOAD_MICROCODE=1\n");
-
- /*
- * Word 76 indicates the capabilities of a SATA device. A PATA device shall set
- * word 76 to 0000h or FFFFh. If word 76 is set to 0000h or FFFFh, then
- * the device does not claim compliance with the Serial ATA specification and words
- * 76 through 79 are not valid and shall be ignored.
- */
-
- word = identify.wyde[76];
- if (word != 0x0000 && word != 0xffff) {
- printf("ID_ATA_SATA=1\n");
- /*
- * If bit 2 of word 76 is set to one, then the device supports the Gen2
- * signaling rate of 3.0 Gb/s (see SATA 2.6).
- *
- * If bit 1 of word 76 is set to one, then the device supports the Gen1
- * signaling rate of 1.5 Gb/s (see SATA 2.6).
- */
- if (word & (1<<2))
- printf("ID_ATA_SATA_SIGNAL_RATE_GEN2=1\n");
- if (word & (1<<1))
- printf("ID_ATA_SATA_SIGNAL_RATE_GEN1=1\n");
- }
-
- /* Word 217 indicates the nominal media rotation rate of the device */
- word = identify.wyde[217];
- if (word == 0x0001)
- printf ("ID_ATA_ROTATION_RATE_RPM=0\n"); /* non-rotating e.g. SSD */
- else if (word >= 0x0401 && word <= 0xfffe)
- printf ("ID_ATA_ROTATION_RATE_RPM=%d\n", word);
-
- /*
- * Words 108-111 contain a mandatory World Wide Name (WWN) in the NAA IEEE Registered identifier
- * format. Word 108 bits (15:12) shall contain 5h, indicating that the naming authority is IEEE.
- * All other values are reserved.
- */
- word = identify.wyde[108];
- if ((word & 0xf000) == 0x5000) {
- uint64_t wwwn;
-
- wwwn = identify.wyde[108];
- wwwn <<= 16;
- wwwn |= identify.wyde[109];
- wwwn <<= 16;
- wwwn |= identify.wyde[110];
- wwwn <<= 16;
- wwwn |= identify.wyde[111];
- printf("ID_WWN=0x%1$" PRIx64 "\n"
- "ID_WWN_WITH_EXTENSION=0x%1$" PRIx64 "\n",
- wwwn);
- }
-
- /* from Linux's include/linux/ata.h */
- if (identify.wyde[0] == 0x848a ||
- identify.wyde[0] == 0x844a ||
- (identify.wyde[83] & 0xc004) == 0x4004)
- printf("ID_ATA_CFA=1\n");
- } else {
- if (serial[0] != '\0')
- printf("%s_%s\n", model, serial);
- else
- printf("%s\n", model);
- }
-
- return 0;
-}
diff --git a/src/udev/cdrom_id/Makefile b/src/udev/cdrom_id/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/cdrom_id/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c
deleted file mode 100644
index 72f284f710..0000000000
--- a/src/udev/cdrom_id/cdrom_id.c
+++ /dev/null
@@ -1,1085 +0,0 @@
-/*
- * cdrom_id - optical drive and media information prober
- *
- * Copyright (C) 2008-2010 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <limits.h>
-#include <linux/cdrom.h>
-#include <scsi/sg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "libudev.h"
-
-#include "libudev-private.h"
-#include "random-util.h"
-
-/* device info */
-static unsigned int cd_cd_rom;
-static unsigned int cd_cd_r;
-static unsigned int cd_cd_rw;
-static unsigned int cd_dvd_rom;
-static unsigned int cd_dvd_r;
-static unsigned int cd_dvd_rw;
-static unsigned int cd_dvd_ram;
-static unsigned int cd_dvd_plus_r;
-static unsigned int cd_dvd_plus_rw;
-static unsigned int cd_dvd_plus_r_dl;
-static unsigned int cd_dvd_plus_rw_dl;
-static unsigned int cd_bd;
-static unsigned int cd_bd_r;
-static unsigned int cd_bd_re;
-static unsigned int cd_hddvd;
-static unsigned int cd_hddvd_r;
-static unsigned int cd_hddvd_rw;
-static unsigned int cd_mo;
-static unsigned int cd_mrw;
-static unsigned int cd_mrw_w;
-
-/* media info */
-static unsigned int cd_media;
-static unsigned int cd_media_cd_rom;
-static unsigned int cd_media_cd_r;
-static unsigned int cd_media_cd_rw;
-static unsigned int cd_media_dvd_rom;
-static unsigned int cd_media_dvd_r;
-static unsigned int cd_media_dvd_rw;
-static unsigned int cd_media_dvd_rw_ro; /* restricted overwrite mode */
-static unsigned int cd_media_dvd_rw_seq; /* sequential mode */
-static unsigned int cd_media_dvd_ram;
-static unsigned int cd_media_dvd_plus_r;
-static unsigned int cd_media_dvd_plus_rw;
-static unsigned int cd_media_dvd_plus_r_dl;
-static unsigned int cd_media_dvd_plus_rw_dl;
-static unsigned int cd_media_bd;
-static unsigned int cd_media_bd_r;
-static unsigned int cd_media_bd_re;
-static unsigned int cd_media_hddvd;
-static unsigned int cd_media_hddvd_r;
-static unsigned int cd_media_hddvd_rw;
-static unsigned int cd_media_mo;
-static unsigned int cd_media_mrw;
-static unsigned int cd_media_mrw_w;
-
-static const char *cd_media_state = NULL;
-static unsigned int cd_media_session_next;
-static unsigned int cd_media_session_count;
-static unsigned int cd_media_track_count;
-static unsigned int cd_media_track_count_data;
-static unsigned int cd_media_track_count_audio;
-static unsigned long long int cd_media_session_last_offset;
-
-#define ERRCODE(s) ((((s)[2] & 0x0F) << 16) | ((s)[12] << 8) | ((s)[13]))
-#define SK(errcode) (((errcode) >> 16) & 0xF)
-#define ASC(errcode) (((errcode) >> 8) & 0xFF)
-#define ASCQ(errcode) ((errcode) & 0xFF)
-
-static bool is_mounted(const char *device)
-{
- struct stat statbuf;
- FILE *fp;
- int maj, min;
- bool mounted = false;
-
- if (stat(device, &statbuf) < 0)
- return false;
-
- fp = fopen("/proc/self/mountinfo", "re");
- if (fp == NULL)
- return false;
- while (fscanf(fp, "%*s %*s %i:%i %*[^\n]", &maj, &min) == 2) {
- if (makedev(maj, min) == statbuf.st_rdev) {
- mounted = true;
- break;
- }
- }
- fclose(fp);
- return mounted;
-}
-
-static void info_scsi_cmd_err(struct udev *udev, const char *cmd, int err)
-{
- if (err == -1) {
- log_debug("%s failed", cmd);
- return;
- }
- log_debug("%s failed with SK=%Xh/ASC=%02Xh/ACQ=%02Xh", cmd, SK(err), ASC(err), ASCQ(err));
-}
-
-struct scsi_cmd {
- struct cdrom_generic_command cgc;
- union {
- struct request_sense s;
- unsigned char u[18];
- } _sense;
- struct sg_io_hdr sg_io;
-};
-
-static void scsi_cmd_init(struct udev *udev, struct scsi_cmd *cmd)
-{
- memzero(cmd, sizeof(struct scsi_cmd));
- cmd->cgc.quiet = 1;
- cmd->cgc.sense = &cmd->_sense.s;
- cmd->sg_io.interface_id = 'S';
- cmd->sg_io.mx_sb_len = sizeof(cmd->_sense);
- cmd->sg_io.cmdp = cmd->cgc.cmd;
- cmd->sg_io.sbp = cmd->_sense.u;
- cmd->sg_io.flags = SG_FLAG_LUN_INHIBIT | SG_FLAG_DIRECT_IO;
-}
-
-static void scsi_cmd_set(struct udev *udev, struct scsi_cmd *cmd, size_t i, unsigned char arg)
-{
- cmd->sg_io.cmd_len = i + 1;
- cmd->cgc.cmd[i] = arg;
-}
-
-#define CHECK_CONDITION 0x01
-
-static int scsi_cmd_run(struct udev *udev, struct scsi_cmd *cmd, int fd, unsigned char *buf, size_t bufsize)
-{
- int ret = 0;
-
- if (bufsize > 0) {
- cmd->sg_io.dxferp = buf;
- cmd->sg_io.dxfer_len = bufsize;
- cmd->sg_io.dxfer_direction = SG_DXFER_FROM_DEV;
- } else {
- cmd->sg_io.dxfer_direction = SG_DXFER_NONE;
- }
- if (ioctl(fd, SG_IO, &cmd->sg_io))
- return -1;
-
- if ((cmd->sg_io.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
- errno = EIO;
- ret = -1;
- if (cmd->sg_io.masked_status & CHECK_CONDITION) {
- ret = ERRCODE(cmd->_sense.u);
- if (ret == 0)
- ret = -1;
- }
- }
- return ret;
-}
-
-static int media_lock(struct udev *udev, int fd, bool lock)
-{
- int err;
-
- /* disable the kernel's lock logic */
- err = ioctl(fd, CDROM_CLEAR_OPTIONS, CDO_LOCK);
- if (err < 0)
- log_debug("CDROM_CLEAR_OPTIONS, CDO_LOCK failed");
-
- err = ioctl(fd, CDROM_LOCKDOOR, lock ? 1 : 0);
- if (err < 0)
- log_debug("CDROM_LOCKDOOR failed");
-
- return err;
-}
-
-static int media_eject(struct udev *udev, int fd)
-{
- struct scsi_cmd sc;
- int err;
-
- scsi_cmd_init(udev, &sc);
- scsi_cmd_set(udev, &sc, 0, 0x1b);
- scsi_cmd_set(udev, &sc, 4, 0x02);
- scsi_cmd_set(udev, &sc, 5, 0);
- err = scsi_cmd_run(udev, &sc, fd, NULL, 0);
- if ((err != 0)) {
- info_scsi_cmd_err(udev, "START_STOP_UNIT", err);
- return -1;
- }
- return 0;
-}
-
-static int cd_capability_compat(struct udev *udev, int fd)
-{
- int capability;
-
- capability = ioctl(fd, CDROM_GET_CAPABILITY, NULL);
- if (capability < 0) {
- log_debug("CDROM_GET_CAPABILITY failed");
- return -1;
- }
-
- if (capability & CDC_CD_R)
- cd_cd_r = 1;
- if (capability & CDC_CD_RW)
- cd_cd_rw = 1;
- if (capability & CDC_DVD)
- cd_dvd_rom = 1;
- if (capability & CDC_DVD_R)
- cd_dvd_r = 1;
- if (capability & CDC_DVD_RAM)
- cd_dvd_ram = 1;
- if (capability & CDC_MRW)
- cd_mrw = 1;
- if (capability & CDC_MRW_W)
- cd_mrw_w = 1;
- return 0;
-}
-
-static int cd_media_compat(struct udev *udev, int fd)
-{
- if (ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) != CDS_DISC_OK) {
- log_debug("CDROM_DRIVE_STATUS != CDS_DISC_OK");
- return -1;
- }
- cd_media = 1;
- return 0;
-}
-
-static int cd_inquiry(struct udev *udev, int fd)
-{
- struct scsi_cmd sc;
- unsigned char inq[128];
- int err;
-
- scsi_cmd_init(udev, &sc);
- scsi_cmd_set(udev, &sc, 0, 0x12);
- scsi_cmd_set(udev, &sc, 4, 36);
- scsi_cmd_set(udev, &sc, 5, 0);
- err = scsi_cmd_run(udev, &sc, fd, inq, 36);
- if ((err != 0)) {
- info_scsi_cmd_err(udev, "INQUIRY", err);
- return -1;
- }
-
- if ((inq[0] & 0x1F) != 5) {
- log_debug("not an MMC unit");
- return -1;
- }
-
- log_debug("INQUIRY: [%.8s][%.16s][%.4s]", inq + 8, inq + 16, inq + 32);
- return 0;
-}
-
-static void feature_profile_media(struct udev *udev, int cur_profile)
-{
- switch (cur_profile) {
- case 0x03:
- case 0x04:
- case 0x05:
- log_debug("profile 0x%02x ", cur_profile);
- cd_media = 1;
- cd_media_mo = 1;
- break;
- case 0x08:
- log_debug("profile 0x%02x media_cd_rom", cur_profile);
- cd_media = 1;
- cd_media_cd_rom = 1;
- break;
- case 0x09:
- log_debug("profile 0x%02x media_cd_r", cur_profile);
- cd_media = 1;
- cd_media_cd_r = 1;
- break;
- case 0x0a:
- log_debug("profile 0x%02x media_cd_rw", cur_profile);
- cd_media = 1;
- cd_media_cd_rw = 1;
- break;
- case 0x10:
- log_debug("profile 0x%02x media_dvd_ro", cur_profile);
- cd_media = 1;
- cd_media_dvd_rom = 1;
- break;
- case 0x11:
- log_debug("profile 0x%02x media_dvd_r", cur_profile);
- cd_media = 1;
- cd_media_dvd_r = 1;
- break;
- case 0x12:
- log_debug("profile 0x%02x media_dvd_ram", cur_profile);
- cd_media = 1;
- cd_media_dvd_ram = 1;
- break;
- case 0x13:
- log_debug("profile 0x%02x media_dvd_rw_ro", cur_profile);
- cd_media = 1;
- cd_media_dvd_rw = 1;
- cd_media_dvd_rw_ro = 1;
- break;
- case 0x14:
- log_debug("profile 0x%02x media_dvd_rw_seq", cur_profile);
- cd_media = 1;
- cd_media_dvd_rw = 1;
- cd_media_dvd_rw_seq = 1;
- break;
- case 0x1B:
- log_debug("profile 0x%02x media_dvd_plus_r", cur_profile);
- cd_media = 1;
- cd_media_dvd_plus_r = 1;
- break;
- case 0x1A:
- log_debug("profile 0x%02x media_dvd_plus_rw", cur_profile);
- cd_media = 1;
- cd_media_dvd_plus_rw = 1;
- break;
- case 0x2A:
- log_debug("profile 0x%02x media_dvd_plus_rw_dl", cur_profile);
- cd_media = 1;
- cd_media_dvd_plus_rw_dl = 1;
- break;
- case 0x2B:
- log_debug("profile 0x%02x media_dvd_plus_r_dl", cur_profile);
- cd_media = 1;
- cd_media_dvd_plus_r_dl = 1;
- break;
- case 0x40:
- log_debug("profile 0x%02x media_bd", cur_profile);
- cd_media = 1;
- cd_media_bd = 1;
- break;
- case 0x41:
- case 0x42:
- log_debug("profile 0x%02x media_bd_r", cur_profile);
- cd_media = 1;
- cd_media_bd_r = 1;
- break;
- case 0x43:
- log_debug("profile 0x%02x media_bd_re", cur_profile);
- cd_media = 1;
- cd_media_bd_re = 1;
- break;
- case 0x50:
- log_debug("profile 0x%02x media_hddvd", cur_profile);
- cd_media = 1;
- cd_media_hddvd = 1;
- break;
- case 0x51:
- log_debug("profile 0x%02x media_hddvd_r", cur_profile);
- cd_media = 1;
- cd_media_hddvd_r = 1;
- break;
- case 0x52:
- log_debug("profile 0x%02x media_hddvd_rw", cur_profile);
- cd_media = 1;
- cd_media_hddvd_rw = 1;
- break;
- default:
- log_debug("profile 0x%02x <ignored>", cur_profile);
- break;
- }
-}
-
-static int feature_profiles(struct udev *udev, const unsigned char *profiles, size_t size)
-{
- unsigned int i;
-
- for (i = 0; i+4 <= size; i += 4) {
- int profile;
-
- profile = profiles[i] << 8 | profiles[i+1];
- switch (profile) {
- case 0x03:
- case 0x04:
- case 0x05:
- log_debug("profile 0x%02x mo", profile);
- cd_mo = 1;
- break;
- case 0x08:
- log_debug("profile 0x%02x cd_rom", profile);
- cd_cd_rom = 1;
- break;
- case 0x09:
- log_debug("profile 0x%02x cd_r", profile);
- cd_cd_r = 1;
- break;
- case 0x0A:
- log_debug("profile 0x%02x cd_rw", profile);
- cd_cd_rw = 1;
- break;
- case 0x10:
- log_debug("profile 0x%02x dvd_rom", profile);
- cd_dvd_rom = 1;
- break;
- case 0x12:
- log_debug("profile 0x%02x dvd_ram", profile);
- cd_dvd_ram = 1;
- break;
- case 0x13:
- case 0x14:
- log_debug("profile 0x%02x dvd_rw", profile);
- cd_dvd_rw = 1;
- break;
- case 0x1B:
- log_debug("profile 0x%02x dvd_plus_r", profile);
- cd_dvd_plus_r = 1;
- break;
- case 0x1A:
- log_debug("profile 0x%02x dvd_plus_rw", profile);
- cd_dvd_plus_rw = 1;
- break;
- case 0x2A:
- log_debug("profile 0x%02x dvd_plus_rw_dl", profile);
- cd_dvd_plus_rw_dl = 1;
- break;
- case 0x2B:
- log_debug("profile 0x%02x dvd_plus_r_dl", profile);
- cd_dvd_plus_r_dl = 1;
- break;
- case 0x40:
- cd_bd = 1;
- log_debug("profile 0x%02x bd", profile);
- break;
- case 0x41:
- case 0x42:
- cd_bd_r = 1;
- log_debug("profile 0x%02x bd_r", profile);
- break;
- case 0x43:
- cd_bd_re = 1;
- log_debug("profile 0x%02x bd_re", profile);
- break;
- case 0x50:
- cd_hddvd = 1;
- log_debug("profile 0x%02x hddvd", profile);
- break;
- case 0x51:
- cd_hddvd_r = 1;
- log_debug("profile 0x%02x hddvd_r", profile);
- break;
- case 0x52:
- cd_hddvd_rw = 1;
- log_debug("profile 0x%02x hddvd_rw", profile);
- break;
- default:
- log_debug("profile 0x%02x <ignored>", profile);
- break;
- }
- }
- return 0;
-}
-
-/* returns 0 if media was detected */
-static int cd_profiles_old_mmc(struct udev *udev, int fd)
-{
- struct scsi_cmd sc;
- int err;
-
- unsigned char header[32];
-
- scsi_cmd_init(udev, &sc);
- scsi_cmd_set(udev, &sc, 0, 0x51);
- scsi_cmd_set(udev, &sc, 8, sizeof(header));
- scsi_cmd_set(udev, &sc, 9, 0);
- err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
- if ((err != 0)) {
- info_scsi_cmd_err(udev, "READ DISC INFORMATION", err);
- if (cd_media == 1) {
- log_debug("no current profile, but disc is present; assuming CD-ROM");
- cd_media_cd_rom = 1;
- cd_media_track_count = 1;
- cd_media_track_count_data = 1;
- return 0;
- } else {
- log_debug("no current profile, assuming no media");
- return -1;
- }
- };
-
- cd_media = 1;
-
- if (header[2] & 16) {
- cd_media_cd_rw = 1;
- log_debug("profile 0x0a media_cd_rw");
- } else if ((header[2] & 3) < 2 && cd_cd_r) {
- cd_media_cd_r = 1;
- log_debug("profile 0x09 media_cd_r");
- } else {
- cd_media_cd_rom = 1;
- log_debug("profile 0x08 media_cd_rom");
- }
- return 0;
-}
-
-/* returns 0 if media was detected */
-static int cd_profiles(struct udev *udev, int fd)
-{
- struct scsi_cmd sc;
- unsigned char features[65530];
- unsigned int cur_profile = 0;
- unsigned int len;
- unsigned int i;
- int err;
- int ret;
-
- ret = -1;
-
- /* First query the current profile */
- scsi_cmd_init(udev, &sc);
- scsi_cmd_set(udev, &sc, 0, 0x46);
- scsi_cmd_set(udev, &sc, 8, 8);
- scsi_cmd_set(udev, &sc, 9, 0);
- err = scsi_cmd_run(udev, &sc, fd, features, 8);
- if ((err != 0)) {
- info_scsi_cmd_err(udev, "GET CONFIGURATION", err);
- /* handle pre-MMC2 drives which do not support GET CONFIGURATION */
- if (SK(err) == 0x5 && (ASC(err) == 0x20 || ASC(err) == 0x24)) {
- log_debug("drive is pre-MMC2 and does not support 46h get configuration command");
- log_debug("trying to work around the problem");
- ret = cd_profiles_old_mmc(udev, fd);
- }
- goto out;
- }
-
- cur_profile = features[6] << 8 | features[7];
- if (cur_profile > 0) {
- log_debug("current profile 0x%02x", cur_profile);
- feature_profile_media (udev, cur_profile);
- ret = 0; /* we have media */
- } else {
- log_debug("no current profile, assuming no media");
- }
-
- len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3];
- log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len);
-
- if (len > sizeof(features)) {
- log_debug("can not get features in a single query, truncating");
- len = sizeof(features);
- } else if (len <= 8)
- len = sizeof(features);
-
- /* Now get the full feature buffer */
- scsi_cmd_init(udev, &sc);
- scsi_cmd_set(udev, &sc, 0, 0x46);
- scsi_cmd_set(udev, &sc, 7, ( len >> 8 ) & 0xff);
- scsi_cmd_set(udev, &sc, 8, len & 0xff);
- scsi_cmd_set(udev, &sc, 9, 0);
- err = scsi_cmd_run(udev, &sc, fd, features, len);
- if ((err != 0)) {
- info_scsi_cmd_err(udev, "GET CONFIGURATION", err);
- return -1;
- }
-
- /* parse the length once more, in case the drive decided to have other features suddenly :) */
- len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3];
- log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len);
-
- if (len > sizeof(features)) {
- log_debug("can not get features in a single query, truncating");
- len = sizeof(features);
- }
-
- /* device features */
- for (i = 8; i+4 < len; i += (4 + features[i+3])) {
- unsigned int feature;
-
- feature = features[i] << 8 | features[i+1];
-
- switch (feature) {
- case 0x00:
- log_debug("GET CONFIGURATION: feature 'profiles', with %i entries", features[i+3] / 4);
- feature_profiles(udev, &features[i]+4, MIN(features[i+3], len - i - 4));
- break;
- default:
- log_debug("GET CONFIGURATION: feature 0x%04x <ignored>, with 0x%02x bytes", feature, features[i+3]);
- break;
- }
- }
-out:
- return ret;
-}
-
-static int cd_media_info(struct udev *udev, int fd)
-{
- struct scsi_cmd sc;
- unsigned char header[32];
- static const char *media_status[] = {
- "blank",
- "appendable",
- "complete",
- "other"
- };
- int err;
-
- scsi_cmd_init(udev, &sc);
- scsi_cmd_set(udev, &sc, 0, 0x51);
- scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff);
- scsi_cmd_set(udev, &sc, 9, 0);
- err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
- if ((err != 0)) {
- info_scsi_cmd_err(udev, "READ DISC INFORMATION", err);
- return -1;
- };
-
- cd_media = 1;
- log_debug("disk type %02x", header[8]);
- log_debug("hardware reported media status: %s", media_status[header[2] & 3]);
-
- /* exclude plain CDROM, some fake cdroms return 0 for "blank" media here */
- if (!cd_media_cd_rom)
- cd_media_state = media_status[header[2] & 3];
-
- /* fresh DVD-RW in restricted overwite mode reports itself as
- * "appendable"; change it to "blank" to make it consistent with what
- * gets reported after blanking, and what userspace expects */
- if (cd_media_dvd_rw_ro && (header[2] & 3) == 1)
- cd_media_state = media_status[0];
-
- /* DVD+RW discs (and DVD-RW in restricted mode) once formatted are
- * always "complete", DVD-RAM are "other" or "complete" if the disc is
- * write protected; we need to check the contents if it is blank */
- if ((cd_media_dvd_rw_ro || cd_media_dvd_plus_rw || cd_media_dvd_plus_rw_dl || cd_media_dvd_ram) && (header[2] & 3) > 1) {
- unsigned char buffer[32 * 2048];
- unsigned char len;
- int offset;
-
- if (cd_media_dvd_ram) {
- /* a write protected dvd-ram may report "complete" status */
-
- unsigned char dvdstruct[8];
- unsigned char format[12];
-
- scsi_cmd_init(udev, &sc);
- scsi_cmd_set(udev, &sc, 0, 0xAD);
- scsi_cmd_set(udev, &sc, 7, 0xC0);
- scsi_cmd_set(udev, &sc, 9, sizeof(dvdstruct));
- scsi_cmd_set(udev, &sc, 11, 0);
- err = scsi_cmd_run(udev, &sc, fd, dvdstruct, sizeof(dvdstruct));
- if ((err != 0)) {
- info_scsi_cmd_err(udev, "READ DVD STRUCTURE", err);
- return -1;
- }
- if (dvdstruct[4] & 0x02) {
- cd_media_state = media_status[2];
- log_debug("write-protected DVD-RAM media inserted");
- goto determined;
- }
-
- /* let's make sure we don't try to read unformatted media */
- scsi_cmd_init(udev, &sc);
- scsi_cmd_set(udev, &sc, 0, 0x23);
- scsi_cmd_set(udev, &sc, 8, sizeof(format));
- scsi_cmd_set(udev, &sc, 9, 0);
- err = scsi_cmd_run(udev, &sc, fd, format, sizeof(format));
- if ((err != 0)) {
- info_scsi_cmd_err(udev, "READ DVD FORMAT CAPACITIES", err);
- return -1;
- }
-
- len = format[3];
- if (len & 7 || len < 16) {
- log_debug("invalid format capacities length");
- return -1;
- }
-
- switch(format[8] & 3) {
- case 1:
- log_debug("unformatted DVD-RAM media inserted");
- /* This means that last format was interrupted
- * or failed, blank dvd-ram discs are factory
- * formatted. Take no action here as it takes
- * quite a while to reformat a dvd-ram and it's
- * not automatically started */
- goto determined;
-
- case 2:
- log_debug("formatted DVD-RAM media inserted");
- break;
-
- case 3:
- cd_media = 0; //return no media
- log_debug("format capacities returned no media");
- return -1;
- }
- }
-
- /* Take a closer look at formatted media (unformatted DVD+RW
- * has "blank" status", DVD-RAM was examined earlier) and check
- * for ISO and UDF PVDs or a fs superblock presence and do it
- * in one ioctl (we need just sectors 0 and 16) */
- scsi_cmd_init(udev, &sc);
- scsi_cmd_set(udev, &sc, 0, 0x28);
- scsi_cmd_set(udev, &sc, 5, 0);
- scsi_cmd_set(udev, &sc, 8, 32);
- scsi_cmd_set(udev, &sc, 9, 0);
- err = scsi_cmd_run(udev, &sc, fd, buffer, sizeof(buffer));
- if ((err != 0)) {
- cd_media = 0;
- info_scsi_cmd_err(udev, "READ FIRST 32 BLOCKS", err);
- return -1;
- }
-
- /* if any non-zero data is found in sector 16 (iso and udf) or
- * eventually 0 (fat32 boot sector, ext2 superblock, etc), disc
- * is assumed non-blank */
-
- for (offset = 32768; offset < (32768 + 2048); offset++) {
- if (buffer [offset]) {
- log_debug("data in block 16, assuming complete");
- goto determined;
- }
- }
-
- for (offset = 0; offset < 2048; offset++) {
- if (buffer [offset]) {
- log_debug("data in block 0, assuming complete");
- goto determined;
- }
- }
-
- cd_media_state = media_status[0];
- log_debug("no data in blocks 0 or 16, assuming blank");
- }
-
-determined:
- /* "other" is e. g. DVD-RAM, can't append sessions there; DVDs in
- * restricted overwrite mode can never append, only in sequential mode */
- if ((header[2] & 3) < 2 && !cd_media_dvd_rw_ro)
- cd_media_session_next = header[10] << 8 | header[5];
- cd_media_session_count = header[9] << 8 | header[4];
- cd_media_track_count = header[11] << 8 | header[6];
-
- return 0;
-}
-
-static int cd_media_toc(struct udev *udev, int fd)
-{
- struct scsi_cmd sc;
- unsigned char header[12];
- unsigned char toc[65536];
- unsigned int len, i, num_tracks;
- unsigned char *p;
- int err;
-
- scsi_cmd_init(udev, &sc);
- scsi_cmd_set(udev, &sc, 0, 0x43);
- scsi_cmd_set(udev, &sc, 6, 1);
- scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff);
- scsi_cmd_set(udev, &sc, 9, 0);
- err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
- if ((err != 0)) {
- info_scsi_cmd_err(udev, "READ TOC", err);
- return -1;
- }
-
- len = (header[0] << 8 | header[1]) + 2;
- log_debug("READ TOC: len: %d, start track: %d, end track: %d", len, header[2], header[3]);
- if (len > sizeof(toc))
- return -1;
- if (len < 2)
- return -1;
- /* 2: first track, 3: last track */
- num_tracks = header[3] - header[2] + 1;
-
- /* empty media has no tracks */
- if (len < 8)
- return 0;
-
- scsi_cmd_init(udev, &sc);
- scsi_cmd_set(udev, &sc, 0, 0x43);
- scsi_cmd_set(udev, &sc, 6, header[2]); /* First Track/Session Number */
- scsi_cmd_set(udev, &sc, 7, (len >> 8) & 0xff);
- scsi_cmd_set(udev, &sc, 8, len & 0xff);
- scsi_cmd_set(udev, &sc, 9, 0);
- err = scsi_cmd_run(udev, &sc, fd, toc, len);
- if ((err != 0)) {
- info_scsi_cmd_err(udev, "READ TOC (tracks)", err);
- return -1;
- }
-
- /* Take care to not iterate beyond the last valid track as specified in
- * the TOC, but also avoid going beyond the TOC length, just in case
- * the last track number is invalidly large */
- for (p = toc+4, i = 4; i < len-8 && num_tracks > 0; i += 8, p += 8, --num_tracks) {
- unsigned int block;
- unsigned int is_data_track;
-
- is_data_track = (p[1] & 0x04) != 0;
-
- block = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7];
- log_debug("track=%u info=0x%x(%s) start_block=%u",
- p[2], p[1] & 0x0f, is_data_track ? "data":"audio", block);
-
- if (is_data_track)
- cd_media_track_count_data++;
- else
- cd_media_track_count_audio++;
- }
-
- scsi_cmd_init(udev, &sc);
- scsi_cmd_set(udev, &sc, 0, 0x43);
- scsi_cmd_set(udev, &sc, 2, 1); /* Session Info */
- scsi_cmd_set(udev, &sc, 8, sizeof(header));
- scsi_cmd_set(udev, &sc, 9, 0);
- err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
- if ((err != 0)) {
- info_scsi_cmd_err(udev, "READ TOC (multi session)", err);
- return -1;
- }
- len = header[4+4] << 24 | header[4+5] << 16 | header[4+6] << 8 | header[4+7];
- log_debug("last track %u starts at block %u", header[4+2], len);
- cd_media_session_last_offset = (unsigned long long int)len * 2048;
- return 0;
-}
-
-int main(int argc, char *argv[])
-{
- struct udev *udev;
- static const struct option options[] = {
- { "lock-media", no_argument, NULL, 'l' },
- { "unlock-media", no_argument, NULL, 'u' },
- { "eject-media", no_argument, NULL, 'e' },
- { "debug", no_argument, NULL, 'd' },
- { "help", no_argument, NULL, 'h' },
- {}
- };
- bool eject = false;
- bool lock = false;
- bool unlock = false;
- const char *node = NULL;
- int fd = -1;
- int cnt;
- int rc = 0;
-
- log_parse_environment();
- log_open();
-
- udev = udev_new();
- if (udev == NULL)
- goto exit;
-
- for (;;) {
- int option;
-
- option = getopt_long(argc, argv, "deluh", options, NULL);
- if (option == -1)
- break;
-
- switch (option) {
- case 'l':
- lock = true;
- break;
- case 'u':
- unlock = true;
- break;
- case 'e':
- eject = true;
- break;
- case 'd':
- log_set_target(LOG_TARGET_CONSOLE);
- log_set_max_level(LOG_DEBUG);
- log_open();
- break;
- case 'h':
- printf("Usage: cdrom_id [options] <device>\n"
- " -l,--lock-media lock the media (to enable eject request events)\n"
- " -u,--unlock-media unlock the media\n"
- " -e,--eject-media eject the media\n"
- " -d,--debug debug to stderr\n"
- " -h,--help print this help text\n\n");
- goto exit;
- default:
- rc = 1;
- goto exit;
- }
- }
-
- node = argv[optind];
- if (!node) {
- log_error("no device");
- fprintf(stderr, "no device\n");
- rc = 1;
- goto exit;
- }
-
- initialize_srand();
- for (cnt = 20; cnt > 0; cnt--) {
- struct timespec duration;
-
- fd = open(node, O_RDONLY|O_NONBLOCK|O_CLOEXEC|(is_mounted(node) ? 0 : O_EXCL));
- if (fd >= 0 || errno != EBUSY)
- break;
- duration.tv_sec = 0;
- duration.tv_nsec = (100 * 1000 * 1000) + (rand() % 100 * 1000 * 1000);
- nanosleep(&duration, NULL);
- }
- if (fd < 0) {
- log_debug("unable to open '%s'", node);
- fprintf(stderr, "unable to open '%s'\n", node);
- rc = 1;
- goto exit;
- }
- log_debug("probing: '%s'", node);
-
- /* same data as original cdrom_id */
- if (cd_capability_compat(udev, fd) < 0) {
- rc = 1;
- goto exit;
- }
-
- /* check for media - don't bail if there's no media as we still need to
- * to read profiles */
- cd_media_compat(udev, fd);
-
- /* check if drive talks MMC */
- if (cd_inquiry(udev, fd) < 0)
- goto work;
-
- /* read drive and possibly current profile */
- if (cd_profiles(udev, fd) != 0)
- goto work;
-
- /* at this point we are guaranteed to have media in the drive - find out more about it */
-
- /* get session/track info */
- cd_media_toc(udev, fd);
-
- /* get writable media state */
- cd_media_info(udev, fd);
-
-work:
- /* lock the media, so we enable eject button events */
- if (lock && cd_media) {
- log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (lock)");
- media_lock(udev, fd, true);
- }
-
- if (unlock && cd_media) {
- log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)");
- media_lock(udev, fd, false);
- }
-
- if (eject) {
- log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)");
- media_lock(udev, fd, false);
- log_debug("START_STOP_UNIT (eject)");
- media_eject(udev, fd);
- }
-
- printf("ID_CDROM=1\n");
- if (cd_cd_rom)
- printf("ID_CDROM_CD=1\n");
- if (cd_cd_r)
- printf("ID_CDROM_CD_R=1\n");
- if (cd_cd_rw)
- printf("ID_CDROM_CD_RW=1\n");
- if (cd_dvd_rom)
- printf("ID_CDROM_DVD=1\n");
- if (cd_dvd_r)
- printf("ID_CDROM_DVD_R=1\n");
- if (cd_dvd_rw)
- printf("ID_CDROM_DVD_RW=1\n");
- if (cd_dvd_ram)
- printf("ID_CDROM_DVD_RAM=1\n");
- if (cd_dvd_plus_r)
- printf("ID_CDROM_DVD_PLUS_R=1\n");
- if (cd_dvd_plus_rw)
- printf("ID_CDROM_DVD_PLUS_RW=1\n");
- if (cd_dvd_plus_r_dl)
- printf("ID_CDROM_DVD_PLUS_R_DL=1\n");
- if (cd_dvd_plus_rw_dl)
- printf("ID_CDROM_DVD_PLUS_RW_DL=1\n");
- if (cd_bd)
- printf("ID_CDROM_BD=1\n");
- if (cd_bd_r)
- printf("ID_CDROM_BD_R=1\n");
- if (cd_bd_re)
- printf("ID_CDROM_BD_RE=1\n");
- if (cd_hddvd)
- printf("ID_CDROM_HDDVD=1\n");
- if (cd_hddvd_r)
- printf("ID_CDROM_HDDVD_R=1\n");
- if (cd_hddvd_rw)
- printf("ID_CDROM_HDDVD_RW=1\n");
- if (cd_mo)
- printf("ID_CDROM_MO=1\n");
- if (cd_mrw)
- printf("ID_CDROM_MRW=1\n");
- if (cd_mrw_w)
- printf("ID_CDROM_MRW_W=1\n");
-
- if (cd_media)
- printf("ID_CDROM_MEDIA=1\n");
- if (cd_media_mo)
- printf("ID_CDROM_MEDIA_MO=1\n");
- if (cd_media_mrw)
- printf("ID_CDROM_MEDIA_MRW=1\n");
- if (cd_media_mrw_w)
- printf("ID_CDROM_MEDIA_MRW_W=1\n");
- if (cd_media_cd_rom)
- printf("ID_CDROM_MEDIA_CD=1\n");
- if (cd_media_cd_r)
- printf("ID_CDROM_MEDIA_CD_R=1\n");
- if (cd_media_cd_rw)
- printf("ID_CDROM_MEDIA_CD_RW=1\n");
- if (cd_media_dvd_rom)
- printf("ID_CDROM_MEDIA_DVD=1\n");
- if (cd_media_dvd_r)
- printf("ID_CDROM_MEDIA_DVD_R=1\n");
- if (cd_media_dvd_ram)
- printf("ID_CDROM_MEDIA_DVD_RAM=1\n");
- if (cd_media_dvd_rw)
- printf("ID_CDROM_MEDIA_DVD_RW=1\n");
- if (cd_media_dvd_plus_r)
- printf("ID_CDROM_MEDIA_DVD_PLUS_R=1\n");
- if (cd_media_dvd_plus_rw)
- printf("ID_CDROM_MEDIA_DVD_PLUS_RW=1\n");
- if (cd_media_dvd_plus_rw_dl)
- printf("ID_CDROM_MEDIA_DVD_PLUS_RW_DL=1\n");
- if (cd_media_dvd_plus_r_dl)
- printf("ID_CDROM_MEDIA_DVD_PLUS_R_DL=1\n");
- if (cd_media_bd)
- printf("ID_CDROM_MEDIA_BD=1\n");
- if (cd_media_bd_r)
- printf("ID_CDROM_MEDIA_BD_R=1\n");
- if (cd_media_bd_re)
- printf("ID_CDROM_MEDIA_BD_RE=1\n");
- if (cd_media_hddvd)
- printf("ID_CDROM_MEDIA_HDDVD=1\n");
- if (cd_media_hddvd_r)
- printf("ID_CDROM_MEDIA_HDDVD_R=1\n");
- if (cd_media_hddvd_rw)
- printf("ID_CDROM_MEDIA_HDDVD_RW=1\n");
-
- if (cd_media_state != NULL)
- printf("ID_CDROM_MEDIA_STATE=%s\n", cd_media_state);
- if (cd_media_session_next > 0)
- printf("ID_CDROM_MEDIA_SESSION_NEXT=%u\n", cd_media_session_next);
- if (cd_media_session_count > 0)
- printf("ID_CDROM_MEDIA_SESSION_COUNT=%u\n", cd_media_session_count);
- if (cd_media_session_count > 1 && cd_media_session_last_offset > 0)
- printf("ID_CDROM_MEDIA_SESSION_LAST_OFFSET=%llu\n", cd_media_session_last_offset);
- if (cd_media_track_count > 0)
- printf("ID_CDROM_MEDIA_TRACK_COUNT=%u\n", cd_media_track_count);
- if (cd_media_track_count_audio > 0)
- printf("ID_CDROM_MEDIA_TRACK_COUNT_AUDIO=%u\n", cd_media_track_count_audio);
- if (cd_media_track_count_data > 0)
- printf("ID_CDROM_MEDIA_TRACK_COUNT_DATA=%u\n", cd_media_track_count_data);
-exit:
- if (fd >= 0)
- close(fd);
- udev_unref(udev);
- log_close();
- return rc;
-}
diff --git a/src/udev/collect/Makefile b/src/udev/collect/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/collect/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/collect/collect.c b/src/udev/collect/collect.c
deleted file mode 100644
index 0e973cd521..0000000000
--- a/src/udev/collect/collect.c
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- * Collect variables across events.
- *
- * usage: collect [--add|--remove] <checkpoint> <id> <idlist>
- *
- * Adds ID <id> to the list governed by <checkpoint>.
- * <id> must be part of the ID list <idlist>.
- * If all IDs given by <idlist> are listed (ie collect has been
- * invoked for each ID in <idlist>) collect returns 0, the
- * number of missing IDs otherwise.
- * A negative number is returned on error.
- *
- * Copyright(C) 2007, Hannes Reinecke <hare@suse.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <stddef.h>
-#include <stdio.h>
-
-#include "alloc-util.h"
-#include "libudev-private.h"
-#include "macro.h"
-#include "stdio-util.h"
-#include "string-util.h"
-
-#define BUFSIZE 16
-#define UDEV_ALARM_TIMEOUT 180
-
-enum collect_state {
- STATE_NONE,
- STATE_OLD,
- STATE_CONFIRMED,
-};
-
-struct _mate {
- struct udev_list_node node;
- char *name;
- enum collect_state state;
-};
-
-static struct udev_list_node bunch;
-static int debug;
-
-/* This can increase dynamically */
-static size_t bufsize = BUFSIZE;
-
-static inline struct _mate *node_to_mate(struct udev_list_node *node)
-{
- return container_of(node, struct _mate, node);
-}
-
-noreturn static void sig_alrm(int signo)
-{
- exit(4);
-}
-
-static void usage(void)
-{
- printf("%s [options] <checkpoint> <id> <idlist>\n\n"
- "Collect variables across events.\n\n"
- " -h --help Print this message\n"
- " -a --add Add ID <id> to the list <idlist>\n"
- " -r --remove Remove ID <id> from the list <idlist>\n"
- " -d --debug Debug to stderr\n\n"
- " Adds ID <id> to the list governed by <checkpoint>.\n"
- " <id> must be part of the list <idlist>.\n"
- " If all IDs given by <idlist> are listed (ie collect has been\n"
- " invoked for each ID in <idlist>) collect returns 0, the\n"
- " number of missing IDs otherwise.\n"
- " On error a negative number is returned.\n\n"
- , program_invocation_short_name);
-}
-
-/*
- * prepare
- *
- * Prepares the database file
- */
-static int prepare(char *dir, char *filename)
-{
- char buf[PATH_MAX];
- int r, fd;
-
- r = mkdir(dir, 0700);
- if (r < 0 && errno != EEXIST)
- return -errno;
-
- snprintf(buf, sizeof buf, "%s/%s", dir, filename);
-
- fd = open(buf, O_RDWR|O_CREAT|O_CLOEXEC, S_IRUSR|S_IWUSR);
- if (fd < 0)
- fprintf(stderr, "Cannot open %s: %m\n", buf);
-
- if (lockf(fd,F_TLOCK,0) < 0) {
- if (debug)
- fprintf(stderr, "Lock taken, wait for %d seconds\n", UDEV_ALARM_TIMEOUT);
- if (errno == EAGAIN || errno == EACCES) {
- alarm(UDEV_ALARM_TIMEOUT);
- lockf(fd, F_LOCK, 0);
- if (debug)
- fprintf(stderr, "Acquired lock on %s\n", buf);
- } else {
- if (debug)
- fprintf(stderr, "Could not get lock on %s: %m\n", buf);
- }
- }
-
- return fd;
-}
-
-/*
- * Read checkpoint file
- *
- * Tricky reading this. We allocate a buffer twice as large
- * as we're going to read. Then we read into the upper half
- * of that buffer and start parsing.
- * Once we do _not_ find end-of-work terminator (whitespace
- * character) we move the upper half to the lower half,
- * adjust the read pointer and read the next bit.
- * Quite clever methinks :-)
- * I should become a programmer ...
- *
- * Yes, one could have used fgets() for this. But then we'd
- * have to use freopen etc which I found quite tedious.
- */
-static int checkout(int fd)
-{
- int len;
- char *buf, *ptr, *word = NULL;
- struct _mate *him;
-
- restart:
- len = bufsize >> 1;
- buf = malloc(bufsize + 1);
- if (!buf)
- return log_oom();
- memset(buf, ' ', bufsize);
- buf[bufsize] = '\0';
-
- ptr = buf + len;
- while ((read(fd, buf + len, len)) > 0) {
- while (ptr && *ptr) {
- word = ptr;
- ptr = strpbrk(word," \n\t\r");
- if (!ptr && word < (buf + len)) {
- bufsize = bufsize << 1;
- if (debug)
- fprintf(stderr, "ID overflow, restarting with size %zu\n", bufsize);
- free(buf);
- lseek(fd, 0, SEEK_SET);
- goto restart;
- }
- if (ptr) {
- *ptr = '\0';
- ptr++;
- if (!strlen(word))
- continue;
-
- if (debug)
- fprintf(stderr, "Found word %s\n", word);
- him = malloc(sizeof (struct _mate));
- if (!him) {
- free(buf);
- return log_oom();
- }
- him->name = strdup(word);
- if (!him->name) {
- free(buf);
- free(him);
- return log_oom();
- }
- him->state = STATE_OLD;
- udev_list_node_append(&him->node, &bunch);
- word = NULL;
- }
- }
- memcpy(buf, buf + len, len);
- memset(buf + len, ' ', len);
-
- if (!ptr)
- ptr = word;
- if (!ptr)
- break;
- ptr -= len;
- }
-
- free(buf);
- return 0;
-}
-
-/*
- * invite
- *
- * Adds a new ID 'us' to the internal list,
- * marks it as confirmed.
- */
-static void invite(char *us)
-{
- struct udev_list_node *him_node;
- struct _mate *who = NULL;
-
- if (debug)
- fprintf(stderr, "Adding ID '%s'\n", us);
-
- udev_list_node_foreach(him_node, &bunch) {
- struct _mate *him = node_to_mate(him_node);
-
- if (streq(him->name, us)) {
- him->state = STATE_CONFIRMED;
- who = him;
- }
- }
- if (debug && !who)
- fprintf(stderr, "ID '%s' not in database\n", us);
-
-}
-
-/*
- * reject
- *
- * Marks the ID 'us' as invalid,
- * causing it to be removed when the
- * list is written out.
- */
-static void reject(char *us)
-{
- struct udev_list_node *him_node;
- struct _mate *who = NULL;
-
- if (debug)
- fprintf(stderr, "Removing ID '%s'\n", us);
-
- udev_list_node_foreach(him_node, &bunch) {
- struct _mate *him = node_to_mate(him_node);
-
- if (streq(him->name, us)) {
- him->state = STATE_NONE;
- who = him;
- }
- }
- if (debug && !who)
- fprintf(stderr, "ID '%s' not in database\n", us);
-}
-
-/*
- * kickout
- *
- * Remove all IDs in the internal list which are not part
- * of the list passed via the command line.
- */
-static void kickout(void)
-{
- struct udev_list_node *him_node;
- struct udev_list_node *tmp;
-
- udev_list_node_foreach_safe(him_node, tmp, &bunch) {
- struct _mate *him = node_to_mate(him_node);
-
- if (him->state == STATE_OLD) {
- udev_list_node_remove(&him->node);
- free(him->name);
- free(him);
- }
- }
-}
-
-/*
- * missing
- *
- * Counts all missing IDs in the internal list.
- */
-static int missing(int fd)
-{
- char *buf;
- int ret = 0;
- struct udev_list_node *him_node;
-
- buf = malloc(bufsize);
- if (!buf)
- return log_oom();
-
- udev_list_node_foreach(him_node, &bunch) {
- struct _mate *him = node_to_mate(him_node);
-
- if (him->state == STATE_NONE) {
- ret++;
- } else {
- while (strlen(him->name)+1 >= bufsize) {
- char *tmpbuf;
-
- bufsize = bufsize << 1;
- tmpbuf = realloc(buf, bufsize);
- if (!tmpbuf) {
- free(buf);
- return log_oom();
- }
- buf = tmpbuf;
- }
- snprintf(buf, strlen(him->name)+2, "%s ", him->name);
- if (write(fd, buf, strlen(buf)) < 0) {
- free(buf);
- return -1;
- }
- }
- }
-
- free(buf);
- return ret;
-}
-
-/*
- * everybody
- *
- * Prints out the status of the internal list.
- */
-static void everybody(void)
-{
- struct udev_list_node *him_node;
- const char *state = "";
-
- udev_list_node_foreach(him_node, &bunch) {
- struct _mate *him = node_to_mate(him_node);
-
- switch (him->state) {
- case STATE_NONE:
- state = "none";
- break;
- case STATE_OLD:
- state = "old";
- break;
- case STATE_CONFIRMED:
- state = "confirmed";
- break;
- }
- fprintf(stderr, "ID: %s=%s\n", him->name, state);
- }
-}
-
-int main(int argc, char **argv)
-{
- struct udev *udev;
- static const struct option options[] = {
- { "add", no_argument, NULL, 'a' },
- { "remove", no_argument, NULL, 'r' },
- { "debug", no_argument, NULL, 'd' },
- { "help", no_argument, NULL, 'h' },
- {}
- };
- int argi;
- char *checkpoint, *us;
- int fd;
- int i;
- int ret = EXIT_SUCCESS;
- int prune = 0;
- char tmpdir[UTIL_PATH_SIZE];
-
- udev = udev_new();
- if (udev == NULL) {
- ret = EXIT_FAILURE;
- goto exit;
- }
-
- for (;;) {
- int option;
-
- option = getopt_long(argc, argv, "ardh", options, NULL);
- if (option == -1)
- break;
-
- switch (option) {
- case 'a':
- prune = 0;
- break;
- case 'r':
- prune = 1;
- break;
- case 'd':
- debug = 1;
- break;
- case 'h':
- usage();
- goto exit;
- default:
- ret = 1;
- goto exit;
- }
- }
-
- argi = optind;
- if (argi + 2 > argc) {
- printf("Missing parameter(s)\n");
- ret = 1;
- goto exit;
- }
- checkpoint = argv[argi++];
- us = argv[argi++];
-
- if (signal(SIGALRM, sig_alrm) == SIG_ERR) {
- fprintf(stderr, "Cannot set SIGALRM: %m\n");
- ret = 2;
- goto exit;
- }
-
- udev_list_node_init(&bunch);
-
- if (debug)
- fprintf(stderr, "Using checkpoint '%s'\n", checkpoint);
-
- strscpyl(tmpdir, sizeof(tmpdir), "/run/udev/collect", NULL);
- fd = prepare(tmpdir, checkpoint);
- if (fd < 0) {
- ret = 3;
- goto out;
- }
-
- if (checkout(fd) < 0) {
- ret = 2;
- goto out;
- }
-
- for (i = argi; i < argc; i++) {
- struct udev_list_node *him_node;
- struct _mate *who;
-
- who = NULL;
- udev_list_node_foreach(him_node, &bunch) {
- struct _mate *him = node_to_mate(him_node);
-
- if (streq(him->name, argv[i]))
- who = him;
- }
- if (!who) {
- struct _mate *him;
-
- if (debug)
- fprintf(stderr, "ID %s: not in database\n", argv[i]);
- him = new(struct _mate, 1);
- if (!him) {
- ret = ENOMEM;
- goto out;
- }
-
- him->name = strdup(argv[i]);
- if (!him->name) {
- free(him);
- ret = ENOMEM;
- goto out;
- }
-
- him->state = STATE_NONE;
- udev_list_node_append(&him->node, &bunch);
- } else {
- if (debug)
- fprintf(stderr, "ID %s: found in database\n", argv[i]);
- who->state = STATE_CONFIRMED;
- }
- }
-
- if (prune)
- reject(us);
- else
- invite(us);
-
- if (debug) {
- everybody();
- fprintf(stderr, "Prune lists\n");
- }
- kickout();
-
- lseek(fd, 0, SEEK_SET);
- ftruncate(fd, 0);
- ret = missing(fd);
-
- lockf(fd, F_ULOCK, 0);
- close(fd);
-out:
- if (debug)
- everybody();
- if (ret >= 0)
- printf("COLLECT_%s=%d\n", checkpoint, ret);
-exit:
- udev_unref(udev);
- return ret;
-}
diff --git a/src/udev/mtd_probe/Makefile b/src/udev/mtd_probe/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/mtd_probe/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/mtd_probe/mtd_probe.c b/src/udev/mtd_probe/mtd_probe.c
deleted file mode 100644
index 462fab7623..0000000000
--- a/src/udev/mtd_probe/mtd_probe.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2010 - Maxim Levitsky
- *
- * mtd_probe is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * mtd_probe is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with mtd_probe; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#include <fcntl.h>
-#include <mtd/mtd-user.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "mtd_probe.h"
-
-int main(int argc, char** argv)
-{
- int mtd_fd;
- int error;
- mtd_info_t mtd_info;
-
- if (argc != 2) {
- printf("usage: mtd_probe /dev/mtd[n]\n");
- return 1;
- }
-
- mtd_fd = open(argv[1], O_RDONLY|O_CLOEXEC);
- if (mtd_fd == -1) {
- perror("open");
- exit(-1);
- }
-
- error = ioctl(mtd_fd, MEMGETINFO, &mtd_info);
- if (error == -1) {
- perror("ioctl");
- exit(-1);
- }
-
- probe_smart_media(mtd_fd, &mtd_info);
- return -1;
-}
diff --git a/src/udev/mtd_probe/mtd_probe.h b/src/udev/mtd_probe/mtd_probe.h
deleted file mode 100644
index 68e4954537..0000000000
--- a/src/udev/mtd_probe/mtd_probe.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2010 - Maxim Levitsky
- *
- * mtd_probe is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * mtd_probe is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with mtd_probe; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#include <mtd/mtd-user.h>
-
-#include "macro.h"
-
-/* Full oob structure as written on the flash */
-struct sm_oob {
- uint32_t reserved;
- uint8_t data_status;
- uint8_t block_status;
- uint8_t lba_copy1[2];
- uint8_t ecc2[3];
- uint8_t lba_copy2[2];
- uint8_t ecc1[3];
-} _packed_;
-
-/* one sector is always 512 bytes, but it can consist of two nand pages */
-#define SM_SECTOR_SIZE 512
-
-/* oob area is also 16 bytes, but might be from two pages */
-#define SM_OOB_SIZE 16
-
-/* This is maximum zone size, and all devices that have more that one zone
- have this size */
-#define SM_MAX_ZONE_SIZE 1024
-
-/* support for small page nand */
-#define SM_SMALL_PAGE 256
-#define SM_SMALL_OOB_SIZE 8
-
-void probe_smart_media(int mtd_fd, mtd_info_t *info);
diff --git a/src/udev/mtd_probe/probe_smartmedia.c b/src/udev/mtd_probe/probe_smartmedia.c
deleted file mode 100644
index 2a7ba17637..0000000000
--- a/src/udev/mtd_probe/probe_smartmedia.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2010 - Maxim Levitsky
- *
- * mtd_probe is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * mtd_probe is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with mtd_probe; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-
-#include <fcntl.h>
-#include <mtd/mtd-user.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "mtd_probe.h"
-
-static const uint8_t cis_signature[] = {
- 0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20
-};
-
-
-void probe_smart_media(int mtd_fd, mtd_info_t* info)
-{
- int sector_size;
- int block_size;
- int size_in_megs;
- int spare_count;
- char* cis_buffer = malloc(SM_SECTOR_SIZE);
- int offset;
- int cis_found = 0;
-
- if (!cis_buffer)
- return;
-
- if (info->type != MTD_NANDFLASH)
- goto exit;
-
- sector_size = info->writesize;
- block_size = info->erasesize;
- size_in_megs = info->size / (1024 * 1024);
-
- if (sector_size != SM_SECTOR_SIZE && sector_size != SM_SMALL_PAGE)
- goto exit;
-
- switch(size_in_megs) {
- case 1:
- case 2:
- spare_count = 6;
- break;
- case 4:
- spare_count = 12;
- break;
- default:
- spare_count = 24;
- break;
- }
-
- for (offset = 0 ; offset < block_size * spare_count ;
- offset += sector_size) {
- lseek(mtd_fd, SEEK_SET, offset);
- if (read(mtd_fd, cis_buffer, SM_SECTOR_SIZE) == SM_SECTOR_SIZE) {
- cis_found = 1;
- break;
- }
- }
-
- if (!cis_found)
- goto exit;
-
- if (memcmp(cis_buffer, cis_signature, sizeof(cis_signature)) != 0 &&
- (memcmp(cis_buffer + SM_SMALL_PAGE, cis_signature,
- sizeof(cis_signature)) != 0))
- goto exit;
-
- printf("MTD_FTL=smartmedia\n");
- free(cis_buffer);
- exit(0);
-exit:
- free(cis_buffer);
- return;
-}
diff --git a/src/udev/net/.gitignore b/src/udev/net/.gitignore
deleted file mode 100644
index 9ca85bacc9..0000000000
--- a/src/udev/net/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/link-config-gperf.c
diff --git a/src/udev/net/Makefile b/src/udev/net/Makefile
deleted file mode 120000
index 94aaae2c4d..0000000000
--- a/src/udev/net/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../Makefile \ No newline at end of file
diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c
deleted file mode 100644
index 708a665576..0000000000
--- a/src/udev/net/ethtool-util.c
+++ /dev/null
@@ -1,325 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <linux/ethtool.h>
-#include <linux/sockios.h>
-
-#include "conf-parser.h"
-#include "ethtool-util.h"
-#include "log.h"
-#include "socket-util.h"
-#include "string-table.h"
-#include "strxcpyx.h"
-#include "util.h"
-
-static const char* const duplex_table[_DUP_MAX] = {
- [DUP_FULL] = "full",
- [DUP_HALF] = "half"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(duplex, Duplex);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_duplex, duplex, Duplex, "Failed to parse duplex setting");
-
-static const char* const wol_table[_WOL_MAX] = {
- [WOL_PHY] = "phy",
- [WOL_MAGIC] = "magic",
- [WOL_OFF] = "off"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_wol, wol, WakeOnLan, "Failed to parse WakeOnLan setting");
-
-static const char* const netdev_feature_table[_NET_DEV_FEAT_MAX] = {
- [NET_DEV_FEAT_GSO] = "tx-generic-segmentation",
- [NET_DEV_FEAT_GRO] = "rx-gro",
- [NET_DEV_FEAT_LRO] = "rx-lro",
- [NET_DEV_FEAT_TSO] = "tx-tcp-segmentation",
- [NET_DEV_FEAT_UFO] = "tx-udp-fragmentation",
-};
-
-int ethtool_connect(int *ret) {
- int fd;
-
- assert_return(ret, -EINVAL);
-
- fd = socket_ioctl_fd();
- if (fd < 0)
- return fd;
- *ret = fd;
-
- return 0;
-}
-
-int ethtool_get_driver(int *fd, const char *ifname, char **ret) {
- struct ethtool_drvinfo ecmd = {
- .cmd = ETHTOOL_GDRVINFO
- };
- struct ifreq ifr = {
- .ifr_data = (void*) &ecmd
- };
- char *d;
- int r;
-
- if (*fd < 0) {
- r = ethtool_connect(fd);
- if (r < 0)
- return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
- }
-
- strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
-
- r = ioctl(*fd, SIOCETHTOOL, &ifr);
- if (r < 0)
- return -errno;
-
- d = strdup(ecmd.driver);
- if (!d)
- return -ENOMEM;
-
- *ret = d;
- return 0;
-}
-
-int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex) {
- struct ethtool_cmd ecmd = {
- .cmd = ETHTOOL_GSET
- };
- struct ifreq ifr = {
- .ifr_data = (void*) &ecmd
- };
- bool need_update = false;
- int r;
-
- if (speed == 0 && duplex == _DUP_INVALID)
- return 0;
-
- if (*fd < 0) {
- r = ethtool_connect(fd);
- if (r < 0)
- return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
- }
-
- strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
-
- r = ioctl(*fd, SIOCETHTOOL, &ifr);
- if (r < 0)
- return -errno;
-
- if (ethtool_cmd_speed(&ecmd) != speed) {
- ethtool_cmd_speed_set(&ecmd, speed);
- need_update = true;
- }
-
- switch (duplex) {
- case DUP_HALF:
- if (ecmd.duplex != DUPLEX_HALF) {
- ecmd.duplex = DUPLEX_HALF;
- need_update = true;
- }
- break;
- case DUP_FULL:
- if (ecmd.duplex != DUPLEX_FULL) {
- ecmd.duplex = DUPLEX_FULL;
- need_update = true;
- }
- break;
- default:
- break;
- }
-
- if (need_update) {
- ecmd.cmd = ETHTOOL_SSET;
-
- r = ioctl(*fd, SIOCETHTOOL, &ifr);
- if (r < 0)
- return -errno;
- }
-
- return 0;
-}
-
-int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) {
- struct ethtool_wolinfo ecmd = {
- .cmd = ETHTOOL_GWOL
- };
- struct ifreq ifr = {
- .ifr_data = (void*) &ecmd
- };
- bool need_update = false;
- int r;
-
- if (wol == _WOL_INVALID)
- return 0;
-
- if (*fd < 0) {
- r = ethtool_connect(fd);
- if (r < 0)
- return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
- }
-
- strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
-
- r = ioctl(*fd, SIOCETHTOOL, &ifr);
- if (r < 0)
- return -errno;
-
- switch (wol) {
- case WOL_PHY:
- if (ecmd.wolopts != WAKE_PHY) {
- ecmd.wolopts = WAKE_PHY;
- need_update = true;
- }
- break;
- case WOL_MAGIC:
- if (ecmd.wolopts != WAKE_MAGIC) {
- ecmd.wolopts = WAKE_MAGIC;
- need_update = true;
- }
- break;
- case WOL_OFF:
- if (ecmd.wolopts != 0) {
- ecmd.wolopts = 0;
- need_update = true;
- }
- break;
- default:
- break;
- }
-
- if (need_update) {
- ecmd.cmd = ETHTOOL_SWOL;
-
- r = ioctl(*fd, SIOCETHTOOL, &ifr);
- if (r < 0)
- return -errno;
- }
-
- return 0;
-}
-
-static int ethtool_get_stringset(int *fd, struct ifreq *ifr, int stringset_id, struct ethtool_gstrings **gstrings) {
- _cleanup_free_ struct ethtool_gstrings *strings = NULL;
- struct {
- struct ethtool_sset_info info;
- uint32_t space;
- } buffer = {
- .info = {
- .cmd = ETHTOOL_GSSET_INFO,
- .sset_mask = UINT64_C(1) << stringset_id,
- },
- };
- unsigned len;
- int r;
-
- ifr->ifr_data = (void *) &buffer.info;
-
- r = ioctl(*fd, SIOCETHTOOL, ifr);
- if (r < 0)
- return -errno;
-
- if (!buffer.info.sset_mask)
- return -EINVAL;
-
- len = buffer.info.data[0];
-
- strings = malloc0(sizeof(struct ethtool_gstrings) + len * ETH_GSTRING_LEN);
- if (!strings)
- return -ENOMEM;
-
- strings->cmd = ETHTOOL_GSTRINGS;
- strings->string_set = stringset_id;
- strings->len = len;
-
- ifr->ifr_data = (void *) strings;
-
- r = ioctl(*fd, SIOCETHTOOL, ifr);
- if (r < 0)
- return -errno;
-
- *gstrings = strings;
- strings = NULL;
-
- return 0;
-}
-
-static int find_feature_index(struct ethtool_gstrings *strings, const char *feature) {
- unsigned i;
-
- for (i = 0; i < strings->len; i++) {
- if (streq((char *) &strings->data[i * ETH_GSTRING_LEN], feature))
- return i;
- }
-
- return -1;
-}
-
-int ethtool_set_features(int *fd, const char *ifname, NetDevFeature *features) {
- _cleanup_free_ struct ethtool_gstrings *strings = NULL;
- struct ethtool_sfeatures *sfeatures;
- int block, bit, i, r;
- struct ifreq ifr = {};
-
- if (*fd < 0) {
- r = ethtool_connect(fd);
- if (r < 0)
- return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
- }
-
- strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
-
- r = ethtool_get_stringset(fd, &ifr, ETH_SS_FEATURES, &strings);
- if (r < 0)
- return log_warning_errno(r, "link_config: could not get ethtool features for %s", ifname);
-
- sfeatures = alloca0(sizeof(struct ethtool_gstrings) + DIV_ROUND_UP(strings->len, 32U) * sizeof(sfeatures->features[0]));
- sfeatures->cmd = ETHTOOL_SFEATURES;
- sfeatures->size = DIV_ROUND_UP(strings->len, 32U);
-
- for (i = 0; i < _NET_DEV_FEAT_MAX; i++) {
-
- if (features[i] != -1) {
-
- r = find_feature_index(strings, netdev_feature_table[i]);
- if (r < 0) {
- log_warning_errno(r, "link_config: could not find feature: %s", netdev_feature_table[i]);
- continue;
- }
-
- block = r / 32;
- bit = r % 32;
-
- sfeatures->features[block].valid |= 1 << bit;
-
- if (features[i])
- sfeatures->features[block].requested |= 1 << bit;
- else
- sfeatures->features[block].requested &= ~(1 << bit);
- }
- }
-
- ifr.ifr_data = (void *) sfeatures;
-
- r = ioctl(*fd, SIOCETHTOOL, &ifr);
- if (r < 0)
- return log_warning_errno(r, "link_config: could not set ethtool features for %s", ifname);
-
- return 0;
-}
diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h
deleted file mode 100644
index 0744164653..0000000000
--- a/src/udev/net/ethtool-util.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <macro.h>
-
-/* we can't use DUPLEX_ prefix, as it
- * clashes with <linux/ethtool.h> */
-typedef enum Duplex {
- DUP_FULL,
- DUP_HALF,
- _DUP_MAX,
- _DUP_INVALID = -1
-} Duplex;
-
-typedef enum WakeOnLan {
- WOL_PHY,
- WOL_MAGIC,
- WOL_OFF,
- _WOL_MAX,
- _WOL_INVALID = -1
-} WakeOnLan;
-
-typedef enum NetDevFeature {
- NET_DEV_FEAT_GSO,
- NET_DEV_FEAT_GRO,
- NET_DEV_FEAT_LRO,
- NET_DEV_FEAT_TSO,
- NET_DEV_FEAT_UFO,
- _NET_DEV_FEAT_MAX,
- _NET_DEV_FEAT_INVALID = -1
-} NetDevFeature;
-
-int ethtool_connect(int *ret);
-
-int ethtool_get_driver(int *fd, const char *ifname, char **ret);
-int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex);
-int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol);
-int ethtool_set_features(int *fd, const char *ifname, NetDevFeature *features);
-
-const char *duplex_to_string(Duplex d) _const_;
-Duplex duplex_from_string(const char *d) _pure_;
-
-const char *wol_to_string(WakeOnLan wol) _const_;
-WakeOnLan wol_from_string(const char *wol) _pure_;
-
-int config_parse_duplex(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_wol(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
deleted file mode 100644
index f8b85cbd13..0000000000
--- a/src/udev/net/link-config-gperf.gperf
+++ /dev/null
@@ -1,42 +0,0 @@
-%{
-#include <stddef.h>
-#include "conf-parser.h"
-#include "network-internal.h"
-#include "link-config.h"
-#include "ethtool-util.h"
-%}
-struct ConfigPerfItem;
-%null_strings
-%language=ANSI-C
-%define slot-name section_and_lvalue
-%define hash-function-name link_config_gperf_hash
-%define lookup-function-name link_config_gperf_lookup
-%readonly-tables
-%omit-struct-type
-%struct-type
-%includes
-%%
-Match.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, match_mac)
-Match.OriginalName, config_parse_ifnames, 0, offsetof(link_config, match_name)
-Match.Path, config_parse_strv, 0, offsetof(link_config, match_path)
-Match.Driver, config_parse_strv, 0, offsetof(link_config, match_driver)
-Match.Type, config_parse_strv, 0, offsetof(link_config, match_type)
-Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(link_config, match_host)
-Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(link_config, match_virt)
-Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, match_kernel)
-Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(link_config, match_arch)
-Link.Description, config_parse_string, 0, offsetof(link_config, description)
-Link.MACAddressPolicy, config_parse_mac_policy, 0, offsetof(link_config, mac_policy)
-Link.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, mac)
-Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy)
-Link.Name, config_parse_ifname, 0, offsetof(link_config, name)
-Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias)
-Link.MTUBytes, config_parse_iec_size, 0, offsetof(link_config, mtu)
-Link.BitsPerSecond, config_parse_si_size, 0, offsetof(link_config, speed)
-Link.Duplex, config_parse_duplex, 0, offsetof(link_config, duplex)
-Link.WakeOnLan, config_parse_wol, 0, offsetof(link_config, wol)
-Link.GenericSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GSO])
-Link.TCPSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TSO])
-Link.UDPSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_UFO])
-Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GRO])
-Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_LRO])
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
deleted file mode 100644
index ece9248c2a..0000000000
--- a/src/udev/net/link-config.c
+++ /dev/null
@@ -1,517 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <netinet/ether.h>
-
-#include "sd-netlink.h"
-
-#include "alloc-util.h"
-#include "conf-files.h"
-#include "conf-parser.h"
-#include "ethtool-util.h"
-#include "fd-util.h"
-#include "libudev-private.h"
-#include "link-config.h"
-#include "log.h"
-#include "missing.h"
-#include "netlink-util.h"
-#include "network-internal.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "proc-cmdline.h"
-#include "random-util.h"
-#include "stat-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-#include "util.h"
-
-struct link_config_ctx {
- LIST_HEAD(link_config, links);
-
- int ethtool_fd;
-
- bool enable_name_policy;
-
- sd_netlink *rtnl;
-
- usec_t link_dirs_ts_usec;
-};
-
-static const char* const link_dirs[] = {
- "/etc/systemd/network",
- "/run/systemd/network",
- "/usr/lib/systemd/network",
-#ifdef HAVE_SPLIT_USR
- "/lib/systemd/network",
-#endif
- NULL};
-
-static void link_config_free(link_config *link) {
- if (!link)
- return;
-
- free(link->filename);
-
- free(link->match_mac);
- strv_free(link->match_path);
- strv_free(link->match_driver);
- strv_free(link->match_type);
- free(link->match_name);
- free(link->match_host);
- free(link->match_virt);
- free(link->match_kernel);
- free(link->match_arch);
-
- free(link->description);
- free(link->mac);
- free(link->name_policy);
- free(link->name);
- free(link->alias);
-
- free(link);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free);
-
-static void link_configs_free(link_config_ctx *ctx) {
- link_config *link, *link_next;
-
- if (!ctx)
- return;
-
- LIST_FOREACH_SAFE(links, link, link_next, ctx->links)
- link_config_free(link);
-}
-
-void link_config_ctx_free(link_config_ctx *ctx) {
- if (!ctx)
- return;
-
- safe_close(ctx->ethtool_fd);
-
- sd_netlink_unref(ctx->rtnl);
-
- link_configs_free(ctx);
-
- free(ctx);
-
- return;
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
-
-int link_config_ctx_new(link_config_ctx **ret) {
- _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
-
- if (!ret)
- return -EINVAL;
-
- ctx = new0(link_config_ctx, 1);
- if (!ctx)
- return -ENOMEM;
-
- LIST_HEAD_INIT(ctx->links);
-
- ctx->ethtool_fd = -1;
-
- ctx->enable_name_policy = true;
-
- *ret = ctx;
- ctx = NULL;
-
- return 0;
-}
-
-static int load_link(link_config_ctx *ctx, const char *filename) {
- _cleanup_(link_config_freep) link_config *link = NULL;
- _cleanup_fclose_ FILE *file = NULL;
- int r;
-
- assert(ctx);
- assert(filename);
-
- file = fopen(filename, "re");
- if (!file) {
- if (errno == ENOENT)
- return 0;
- else
- return -errno;
- }
-
- if (null_or_empty_fd(fileno(file))) {
- log_debug("Skipping empty file: %s", filename);
- return 0;
- }
-
- link = new0(link_config, 1);
- if (!link)
- return log_oom();
-
- link->mac_policy = _MACPOLICY_INVALID;
- link->wol = _WOL_INVALID;
- link->duplex = _DUP_INVALID;
-
- memset(&link->features, -1, _NET_DEV_FEAT_MAX);
-
- r = config_parse(NULL, filename, file,
- "Match\0Link\0Ethernet\0",
- config_item_perf_lookup, link_config_gperf_lookup,
- false, false, true, link);
- if (r < 0)
- return r;
- else
- log_debug("Parsed configuration file %s", filename);
-
- if (link->mtu > UINT_MAX || link->speed > UINT_MAX)
- return -ERANGE;
-
- link->filename = strdup(filename);
-
- LIST_PREPEND(links, ctx->links, link);
- link = NULL;
-
- return 0;
-}
-
-static bool enable_name_policy(void) {
- _cleanup_free_ char *value = NULL;
- int r;
-
- r = get_proc_cmdline_key("net.ifnames=", &value);
- if (r > 0 && streq(value, "0"))
- return false;
-
- return true;
-}
-
-int link_config_load(link_config_ctx *ctx) {
- int r;
- _cleanup_strv_free_ char **files;
- char **f;
-
- link_configs_free(ctx);
-
- if (!enable_name_policy()) {
- ctx->enable_name_policy = false;
- log_info("Network interface NamePolicy= disabled on kernel command line, ignoring.");
- }
-
- /* update timestamp */
- paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
-
- r = conf_files_list_strv(&files, ".link", NULL, link_dirs);
- if (r < 0)
- return log_error_errno(r, "failed to enumerate link files: %m");
-
- STRV_FOREACH_BACKWARDS(f, files) {
- r = load_link(ctx, *f);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-bool link_config_should_reload(link_config_ctx *ctx) {
- return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false);
-}
-
-int link_config_get(link_config_ctx *ctx, struct udev_device *device,
- link_config **ret) {
- link_config *link;
-
- assert(ctx);
- assert(device);
- assert(ret);
-
- LIST_FOREACH(links, link, ctx->links) {
- const char* attr_value;
-
- attr_value = udev_device_get_sysattr_value(device, "address");
-
- if (net_match_config(link->match_mac, link->match_path, link->match_driver,
- link->match_type, link->match_name, link->match_host,
- link->match_virt, link->match_kernel, link->match_arch,
- attr_value ? ether_aton(attr_value) : NULL,
- udev_device_get_property_value(device, "ID_PATH"),
- udev_device_get_driver(udev_device_get_parent(device)),
- udev_device_get_property_value(device, "ID_NET_DRIVER"),
- udev_device_get_devtype(device),
- udev_device_get_sysname(device))) {
- if (link->match_name) {
- unsigned char name_assign_type = NET_NAME_UNKNOWN;
-
- attr_value = udev_device_get_sysattr_value(device, "name_assign_type");
- if (attr_value)
- (void) safe_atou8(attr_value, &name_assign_type);
-
- if (name_assign_type == NET_NAME_ENUM) {
- log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'",
- link->filename, udev_device_get_sysname(device));
- *ret = link;
-
- return 0;
- } else if (name_assign_type == NET_NAME_RENAMED) {
- log_warning("Config file %s matches device based on renamed interface name '%s', ignoring",
- link->filename, udev_device_get_sysname(device));
-
- continue;
- }
- }
-
- log_debug("Config file %s applies to device %s",
- link->filename, udev_device_get_sysname(device));
-
- *ret = link;
-
- return 0;
- }
- }
-
- *ret = NULL;
-
- return -ENOENT;
-}
-
-static bool mac_is_random(struct udev_device *device) {
- const char *s;
- unsigned type;
- int r;
-
- /* if we can't get the assign type, assume it is not random */
- s = udev_device_get_sysattr_value(device, "addr_assign_type");
- if (!s)
- return false;
-
- r = safe_atou(s, &type);
- if (r < 0)
- return false;
-
- return type == NET_ADDR_RANDOM;
-}
-
-static bool should_rename(struct udev_device *device, bool respect_predictable) {
- const char *s;
- unsigned type;
- int r;
-
- /* if we can't get the assgin type, assume we should rename */
- s = udev_device_get_sysattr_value(device, "name_assign_type");
- if (!s)
- return true;
-
- r = safe_atou(s, &type);
- if (r < 0)
- return true;
-
- switch (type) {
- case NET_NAME_USER:
- case NET_NAME_RENAMED:
- /* these were already named by userspace, do not touch again */
- return false;
- case NET_NAME_PREDICTABLE:
- /* the kernel claims to have given a predictable name */
- if (respect_predictable)
- return false;
- /* fall through */
- case NET_NAME_ENUM:
- default:
- /* the name is known to be bad, or of an unknown type */
- return true;
- }
-}
-
-static int get_mac(struct udev_device *device, bool want_random,
- struct ether_addr *mac) {
- int r;
-
- if (want_random)
- random_bytes(mac->ether_addr_octet, ETH_ALEN);
- else {
- uint64_t result;
-
- r = net_get_unique_predictable_data(device, &result);
- if (r < 0)
- return r;
-
- assert_cc(ETH_ALEN <= sizeof(result));
- memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
- }
-
- /* see eth_random_addr in the kernel */
- mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
- mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
-
- return 0;
-}
-
-int link_config_apply(link_config_ctx *ctx, link_config *config,
- struct udev_device *device, const char **name) {
- const char *old_name;
- const char *new_name = NULL;
- struct ether_addr generated_mac;
- struct ether_addr *mac = NULL;
- bool respect_predictable = false;
- int r, ifindex;
-
- assert(ctx);
- assert(config);
- assert(device);
- assert(name);
-
- old_name = udev_device_get_sysname(device);
- if (!old_name)
- return -EINVAL;
-
- r = ethtool_set_speed(&ctx->ethtool_fd, old_name, config->speed / 1024, config->duplex);
- if (r < 0)
- log_warning_errno(r, "Could not set speed or duplex of %s to %zu Mbps (%s): %m",
- old_name, config->speed / 1024,
- duplex_to_string(config->duplex));
-
- r = ethtool_set_wol(&ctx->ethtool_fd, old_name, config->wol);
- if (r < 0)
- log_warning_errno(r, "Could not set WakeOnLan of %s to %s: %m",
- old_name, wol_to_string(config->wol));
-
- r = ethtool_set_features(&ctx->ethtool_fd, old_name, config->features);
- if (r < 0)
- log_warning_errno(r, "Could not set offload features of %s: %m", old_name);
-
- ifindex = udev_device_get_ifindex(device);
- if (ifindex <= 0) {
- log_warning("Could not find ifindex");
- return -ENODEV;
- }
-
- if (ctx->enable_name_policy && config->name_policy) {
- NamePolicy *policy;
-
- for (policy = config->name_policy;
- !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
- switch (*policy) {
- case NAMEPOLICY_KERNEL:
- respect_predictable = true;
- break;
- case NAMEPOLICY_DATABASE:
- new_name = udev_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE");
- break;
- case NAMEPOLICY_ONBOARD:
- new_name = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
- break;
- case NAMEPOLICY_SLOT:
- new_name = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
- break;
- case NAMEPOLICY_PATH:
- new_name = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
- break;
- case NAMEPOLICY_MAC:
- new_name = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
- break;
- default:
- break;
- }
- }
- }
-
- if (should_rename(device, respect_predictable)) {
- /* if not set by policy, fall back manually set name */
- if (!new_name)
- new_name = config->name;
- } else
- new_name = NULL;
-
- switch (config->mac_policy) {
- case MACPOLICY_PERSISTENT:
- if (mac_is_random(device)) {
- r = get_mac(device, false, &generated_mac);
- if (r == -ENOENT) {
- log_warning_errno(r, "Could not generate persistent MAC address for %s: %m", old_name);
- break;
- } else if (r < 0)
- return r;
- mac = &generated_mac;
- }
- break;
- case MACPOLICY_RANDOM:
- if (!mac_is_random(device)) {
- r = get_mac(device, true, &generated_mac);
- if (r == -ENOENT) {
- log_warning_errno(r, "Could not generate random MAC address for %s: %m", old_name);
- break;
- } else if (r < 0)
- return r;
- mac = &generated_mac;
- }
- break;
- case MACPOLICY_NONE:
- default:
- mac = config->mac;
- }
-
- r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu);
- if (r < 0)
- return log_warning_errno(r, "Could not set Alias, MACAddress or MTU on %s: %m", old_name);
-
- *name = new_name;
-
- return 0;
-}
-
-int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret) {
- const char *name;
- char *driver = NULL;
- int r;
-
- name = udev_device_get_sysname(device);
- if (!name)
- return -EINVAL;
-
- r = ethtool_get_driver(&ctx->ethtool_fd, name, &driver);
- if (r < 0)
- return r;
-
- *ret = driver;
- return 0;
-}
-
-static const char* const mac_policy_table[_MACPOLICY_MAX] = {
- [MACPOLICY_PERSISTENT] = "persistent",
- [MACPOLICY_RANDOM] = "random",
- [MACPOLICY_NONE] = "none"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy,
- "Failed to parse MAC address policy");
-
-static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
- [NAMEPOLICY_KERNEL] = "kernel",
- [NAMEPOLICY_DATABASE] = "database",
- [NAMEPOLICY_ONBOARD] = "onboard",
- [NAMEPOLICY_SLOT] = "slot",
- [NAMEPOLICY_PATH] = "path",
- [NAMEPOLICY_MAC] = "mac"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
-DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
- _NAMEPOLICY_INVALID,
- "Failed to parse interface name policy");
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
deleted file mode 100644
index 91cc0357c4..0000000000
--- a/src/udev/net/link-config.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "libudev.h"
-
-#include "condition.h"
-#include "ethtool-util.h"
-#include "list.h"
-
-typedef struct link_config_ctx link_config_ctx;
-typedef struct link_config link_config;
-
-typedef enum MACPolicy {
- MACPOLICY_PERSISTENT,
- MACPOLICY_RANDOM,
- MACPOLICY_NONE,
- _MACPOLICY_MAX,
- _MACPOLICY_INVALID = -1
-} MACPolicy;
-
-typedef enum NamePolicy {
- NAMEPOLICY_KERNEL,
- NAMEPOLICY_DATABASE,
- NAMEPOLICY_ONBOARD,
- NAMEPOLICY_SLOT,
- NAMEPOLICY_PATH,
- NAMEPOLICY_MAC,
- _NAMEPOLICY_MAX,
- _NAMEPOLICY_INVALID = -1
-} NamePolicy;
-
-struct link_config {
- char *filename;
-
- struct ether_addr *match_mac;
- char **match_path;
- char **match_driver;
- char **match_type;
- char **match_name;
- Condition *match_host;
- Condition *match_virt;
- Condition *match_kernel;
- Condition *match_arch;
-
- char *description;
- struct ether_addr *mac;
- MACPolicy mac_policy;
- NamePolicy *name_policy;
- char *name;
- char *alias;
- size_t mtu;
- size_t speed;
- Duplex duplex;
- WakeOnLan wol;
- NetDevFeature features[_NET_DEV_FEAT_MAX];
-
- LIST_FIELDS(link_config, links);
-};
-
-int link_config_ctx_new(link_config_ctx **ret);
-void link_config_ctx_free(link_config_ctx *ctx);
-
-int link_config_load(link_config_ctx *ctx);
-bool link_config_should_reload(link_config_ctx *ctx);
-
-int link_config_get(link_config_ctx *ctx, struct udev_device *device, struct link_config **ret);
-int link_config_apply(link_config_ctx *ctx, struct link_config *config, struct udev_device *device, const char **name);
-
-int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret);
-
-const char *name_policy_to_string(NamePolicy p) _const_;
-NamePolicy name_policy_from_string(const char *p) _pure_;
-
-const char *mac_policy_to_string(MACPolicy p) _const_;
-MACPolicy mac_policy_from_string(const char *p) _pure_;
-
-/* gperf lookup function */
-const struct ConfigPerfItem* link_config_gperf_lookup(const char *key, unsigned length);
-
-int config_parse_mac_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_name_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/udev/scsi_id/.gitignore b/src/udev/scsi_id/.gitignore
deleted file mode 100644
index 6aebddd809..0000000000
--- a/src/udev/scsi_id/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-scsi_id_version.h
diff --git a/src/udev/scsi_id/Makefile b/src/udev/scsi_id/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/scsi_id/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/scsi_id/README b/src/udev/scsi_id/README
deleted file mode 100644
index 9cfe73991c..0000000000
--- a/src/udev/scsi_id/README
+++ /dev/null
@@ -1,4 +0,0 @@
-scsi_id - generate a SCSI unique identifier for a given SCSI device
-
-Please send questions, comments or patches to <patmans@us.ibm.com> or
-<linux-hotplug-devel@lists.sourceforge.net>.
diff --git a/src/udev/scsi_id/scsi.h b/src/udev/scsi_id/scsi.h
deleted file mode 100644
index a27a84a40a..0000000000
--- a/src/udev/scsi_id/scsi.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#pragma once
-
-/*
- * scsi.h
- *
- * General scsi and linux scsi specific defines and structs.
- *
- * Copyright (C) IBM Corp. 2003
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation version 2 of the License.
- */
-
-#include <scsi/scsi.h>
-
-struct scsi_ioctl_command {
- unsigned int inlen; /* excluding scsi command length */
- unsigned int outlen;
- unsigned char data[1];
- /* on input, scsi command starts here then opt. data */
-};
-
-/*
- * Default 5 second timeout
- */
-#define DEF_TIMEOUT 5000
-
-#define SENSE_BUFF_LEN 32
-
-/*
- * The request buffer size passed to the SCSI INQUIRY commands, use 254,
- * as this is a nice value for some devices, especially some of the usb
- * mass storage devices.
- */
-#define SCSI_INQ_BUFF_LEN 254
-
-/*
- * SCSI INQUIRY vendor and model (really product) lengths.
- */
-#define VENDOR_LENGTH 8
-#define MODEL_LENGTH 16
-
-#define INQUIRY_CMD 0x12
-#define INQUIRY_CMDLEN 6
-
-/*
- * INQUIRY VPD page 0x83 identifier descriptor related values. Reference the
- * SCSI Primary Commands specification for details.
- */
-
-/*
- * id type values of id descriptors. These are assumed to fit in 4 bits.
- */
-#define SCSI_ID_VENDOR_SPECIFIC 0
-#define SCSI_ID_T10_VENDOR 1
-#define SCSI_ID_EUI_64 2
-#define SCSI_ID_NAA 3
-#define SCSI_ID_RELPORT 4
-#define SCSI_ID_TGTGROUP 5
-#define SCSI_ID_LUNGROUP 6
-#define SCSI_ID_MD5 7
-#define SCSI_ID_NAME 8
-
-/*
- * Supported NAA values. These fit in 4 bits, so the "don't care" value
- * cannot conflict with real values.
- */
-#define SCSI_ID_NAA_DONT_CARE 0xff
-#define SCSI_ID_NAA_IEEE_REG 0x05
-#define SCSI_ID_NAA_IEEE_REG_EXTENDED 0x06
-
-/*
- * Supported Code Set values.
- */
-#define SCSI_ID_BINARY 1
-#define SCSI_ID_ASCII 2
-
-struct scsi_id_search_values {
- u_char id_type;
- u_char naa_type;
- u_char code_set;
-};
-
-/*
- * Following are the "true" SCSI status codes. Linux has traditionally
- * used a 1 bit right and masked version of these. So now CHECK_CONDITION
- * and friends (in <scsi/scsi.h>) are deprecated.
- */
-#define SCSI_CHECK_CONDITION 0x02
-#define SCSI_CONDITION_MET 0x04
-#define SCSI_BUSY 0x08
-#define SCSI_IMMEDIATE 0x10
-#define SCSI_IMMEDIATE_CONDITION_MET 0x14
-#define SCSI_RESERVATION_CONFLICT 0x18
-#define SCSI_COMMAND_TERMINATED 0x22
-#define SCSI_TASK_SET_FULL 0x28
-#define SCSI_ACA_ACTIVE 0x30
-#define SCSI_TASK_ABORTED 0x40
diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c
deleted file mode 100644
index 4655691642..0000000000
--- a/src/udev/scsi_id/scsi_id.c
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * Copyright (C) IBM Corp. 2003
- * Copyright (C) SUSE Linux Products GmbH, 2006
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "libudev.h"
-
-#include "fd-util.h"
-#include "libudev-private.h"
-#include "scsi_id.h"
-#include "string-util.h"
-#include "udev-util.h"
-
-static const struct option options[] = {
- { "device", required_argument, NULL, 'd' },
- { "config", required_argument, NULL, 'f' },
- { "page", required_argument, NULL, 'p' },
- { "blacklisted", no_argument, NULL, 'b' },
- { "whitelisted", no_argument, NULL, 'g' },
- { "replace-whitespace", no_argument, NULL, 'u' },
- { "sg-version", required_argument, NULL, 's' },
- { "verbose", no_argument, NULL, 'v' },
- { "version", no_argument, NULL, 'V' }, /* don't advertise -V */
- { "export", no_argument, NULL, 'x' },
- { "help", no_argument, NULL, 'h' },
- {}
-};
-
-static bool all_good = false;
-static bool dev_specified = false;
-static char config_file[MAX_PATH_LEN] = "/etc/scsi_id.config";
-static enum page_code default_page_code = PAGE_UNSPECIFIED;
-static int sg_version = 4;
-static bool reformat_serial = false;
-static bool export = false;
-static char vendor_str[64];
-static char model_str[64];
-static char vendor_enc_str[256];
-static char model_enc_str[256];
-static char revision_str[16];
-static char type_str[16];
-
-static void set_type(const char *from, char *to, size_t len)
-{
- int type_num;
- char *eptr;
- const char *type = "generic";
-
- type_num = strtoul(from, &eptr, 0);
- if (eptr != from) {
- switch (type_num) {
- case 0:
- type = "disk";
- break;
- case 1:
- type = "tape";
- break;
- case 4:
- type = "optical";
- break;
- case 5:
- type = "cd";
- break;
- case 7:
- type = "optical";
- break;
- case 0xe:
- type = "disk";
- break;
- case 0xf:
- type = "optical";
- break;
- default:
- break;
- }
- }
- strscpy(to, len, type);
-}
-
-/*
- * get_value:
- *
- * buf points to an '=' followed by a quoted string ("foo") or a string ending
- * with a space or ','.
- *
- * Return a pointer to the NUL terminated string, returns NULL if no
- * matches.
- */
-static char *get_value(char **buffer)
-{
- static const char *quote_string = "\"\n";
- static const char *comma_string = ",\n";
- char *val;
- const char *end;
-
- if (**buffer == '"') {
- /*
- * skip leading quote, terminate when quote seen
- */
- (*buffer)++;
- end = quote_string;
- } else {
- end = comma_string;
- }
- val = strsep(buffer, end);
- if (val && end == quote_string)
- /*
- * skip trailing quote
- */
- (*buffer)++;
-
- while (isspace(**buffer))
- (*buffer)++;
-
- return val;
-}
-
-static int argc_count(char *opts)
-{
- int i = 0;
- while (*opts != '\0')
- if (*opts++ == ' ')
- i++;
- return i;
-}
-
-/*
- * get_file_options:
- *
- * If vendor == NULL, find a line in the config file with only "OPTIONS=";
- * if vendor and model are set find the first OPTIONS line in the config
- * file that matches. Set argc and argv to match the OPTIONS string.
- *
- * vendor and model can end in '\n'.
- */
-static int get_file_options(struct udev *udev,
- const char *vendor, const char *model,
- int *argc, char ***newargv)
-{
- char *buffer;
- _cleanup_fclose_ FILE *f;
- char *buf;
- char *str1;
- char *vendor_in, *model_in, *options_in; /* read in from file */
- int lineno;
- int c;
- int retval = 0;
-
- f = fopen(config_file, "re");
- if (f == NULL) {
- if (errno == ENOENT)
- return 1;
- else {
- log_error_errno(errno, "can't open %s: %m", config_file);
- return -1;
- }
- }
-
- /*
- * Allocate a buffer rather than put it on the stack so we can
- * keep it around to parse any options (any allocated newargv
- * points into this buffer for its strings).
- */
- buffer = malloc(MAX_BUFFER_LEN);
- if (!buffer)
- return log_oom();
-
- *newargv = NULL;
- lineno = 0;
- for (;;) {
- vendor_in = model_in = options_in = NULL;
-
- buf = fgets(buffer, MAX_BUFFER_LEN, f);
- if (buf == NULL)
- break;
- lineno++;
- if (buf[strlen(buffer) - 1] != '\n') {
- log_error("Config file line %d too long", lineno);
- break;
- }
-
- while (isspace(*buf))
- buf++;
-
- /* blank or all whitespace line */
- if (*buf == '\0')
- continue;
-
- /* comment line */
- if (*buf == '#')
- continue;
-
- str1 = strsep(&buf, "=");
- if (str1 && strcaseeq(str1, "VENDOR")) {
- str1 = get_value(&buf);
- if (!str1) {
- retval = log_oom();
- break;
- }
- vendor_in = str1;
-
- str1 = strsep(&buf, "=");
- if (str1 && strcaseeq(str1, "MODEL")) {
- str1 = get_value(&buf);
- if (!str1) {
- retval = log_oom();
- break;
- }
- model_in = str1;
- str1 = strsep(&buf, "=");
- }
- }
-
- if (str1 && strcaseeq(str1, "OPTIONS")) {
- str1 = get_value(&buf);
- if (!str1) {
- retval = log_oom();
- break;
- }
- options_in = str1;
- }
-
- /*
- * Only allow: [vendor=foo[,model=bar]]options=stuff
- */
- if (!options_in || (!vendor_in && model_in)) {
- log_error("Error parsing config file line %d '%s'", lineno, buffer);
- retval = -1;
- break;
- }
- if (vendor == NULL) {
- if (vendor_in == NULL)
- break;
- } else if (vendor_in &&
- strneq(vendor, vendor_in, strlen(vendor_in)) &&
- (!model_in ||
- (strneq(model, model_in, strlen(model_in))))) {
- /*
- * Matched vendor and optionally model.
- *
- * Note: a short vendor_in or model_in can
- * give a partial match (that is FOO
- * matches FOOBAR).
- */
- break;
- }
- }
-
- if (retval == 0) {
- if (vendor_in != NULL || model_in != NULL ||
- options_in != NULL) {
- /*
- * Something matched. Allocate newargv, and store
- * values found in options_in.
- */
- strcpy(buffer, options_in);
- c = argc_count(buffer) + 2;
- *newargv = calloc(c, sizeof(**newargv));
- if (!*newargv)
- retval = log_oom();
- else {
- *argc = c;
- c = 0;
- /*
- * argv[0] at 0 is skipped by getopt, but
- * store the buffer address there for
- * later freeing
- */
- (*newargv)[c] = buffer;
- for (c = 1; c < *argc; c++)
- (*newargv)[c] = strsep(&buffer, " \t");
- }
- } else {
- /* No matches */
- retval = 1;
- }
- }
- if (retval != 0)
- free(buffer);
- return retval;
-}
-
-static void help(void) {
- printf("Usage: %s [OPTION...] DEVICE\n\n"
- "SCSI device identification.\n\n"
- " -h --help Print this message\n"
- " --version Print version of the program\n\n"
- " -d --device= Device node for SG_IO commands\n"
- " -f --config= Location of config file\n"
- " -p --page=0x80|0x83|pre-spc3-83 SCSI page (0x80, 0x83, pre-spc3-83)\n"
- " -s --sg-version=3|4 Use SGv3 or SGv4\n"
- " -b --blacklisted Treat device as blacklisted\n"
- " -g --whitelisted Treat device as whitelisted\n"
- " -u --replace-whitespace Replace all whitespace by underscores\n"
- " -v --verbose Verbose logging\n"
- " -x --export Print values as environment keys\n"
- , program_invocation_short_name);
-
-}
-
-static int set_options(struct udev *udev,
- int argc, char **argv,
- char *maj_min_dev)
-{
- int option;
-
- /*
- * optind is a global extern used by getopt. Since we can call
- * set_options twice (once for command line, and once for config
- * file) we have to reset this back to 1.
- */
- optind = 1;
- while ((option = getopt_long(argc, argv, "d:f:gp:uvVxh", options, NULL)) >= 0)
- switch (option) {
- case 'b':
- all_good = false;
- break;
-
- case 'd':
- dev_specified = true;
- strscpy(maj_min_dev, MAX_PATH_LEN, optarg);
- break;
-
- case 'f':
- strscpy(config_file, MAX_PATH_LEN, optarg);
- break;
-
- case 'g':
- all_good = true;
- break;
-
- case 'h':
- help();
- exit(0);
-
- case 'p':
- if (streq(optarg, "0x80"))
- default_page_code = PAGE_80;
- else if (streq(optarg, "0x83"))
- default_page_code = PAGE_83;
- else if (streq(optarg, "pre-spc3-83"))
- default_page_code = PAGE_83_PRE_SPC3;
- else {
- log_error("Unknown page code '%s'", optarg);
- return -1;
- }
- break;
-
- case 's':
- sg_version = atoi(optarg);
- if (sg_version < 3 || sg_version > 4) {
- log_error("Unknown SG version '%s'", optarg);
- return -1;
- }
- break;
-
- case 'u':
- reformat_serial = true;
- break;
-
- case 'v':
- log_set_target(LOG_TARGET_CONSOLE);
- log_set_max_level(LOG_DEBUG);
- log_open();
- break;
-
- case 'V':
- printf("%s\n", VERSION);
- exit(0);
-
- case 'x':
- export = true;
- break;
-
- case '?':
- return -1;
-
- default:
- assert_not_reached("Unknown option");
- }
-
- if (optind < argc && !dev_specified) {
- dev_specified = true;
- strscpy(maj_min_dev, MAX_PATH_LEN, argv[optind]);
- }
-
- return 0;
-}
-
-static int per_dev_options(struct udev *udev,
- struct scsi_id_device *dev_scsi, int *good_bad, int *page_code)
-{
- int retval;
- int newargc;
- char **newargv = NULL;
- int option;
-
- *good_bad = all_good;
- *page_code = default_page_code;
-
- retval = get_file_options(udev, vendor_str, model_str, &newargc, &newargv);
-
- optind = 1; /* reset this global extern */
- while (retval == 0) {
- option = getopt_long(newargc, newargv, "bgp:", options, NULL);
- if (option == -1)
- break;
-
- switch (option) {
- case 'b':
- *good_bad = 0;
- break;
-
- case 'g':
- *good_bad = 1;
- break;
-
- case 'p':
- if (streq(optarg, "0x80")) {
- *page_code = PAGE_80;
- } else if (streq(optarg, "0x83")) {
- *page_code = PAGE_83;
- } else if (streq(optarg, "pre-spc3-83")) {
- *page_code = PAGE_83_PRE_SPC3;
- } else {
- log_error("Unknown page code '%s'", optarg);
- retval = -1;
- }
- break;
-
- default:
- log_error("Unknown or bad option '%c' (0x%x)", option, option);
- retval = -1;
- break;
- }
- }
-
- if (newargv) {
- free(newargv[0]);
- free(newargv);
- }
- return retval;
-}
-
-static int set_inq_values(struct udev *udev, struct scsi_id_device *dev_scsi, const char *path)
-{
- int retval;
-
- dev_scsi->use_sg = sg_version;
-
- retval = scsi_std_inquiry(udev, dev_scsi, path);
- if (retval)
- return retval;
-
- udev_util_encode_string(dev_scsi->vendor, vendor_enc_str, sizeof(vendor_enc_str));
- udev_util_encode_string(dev_scsi->model, model_enc_str, sizeof(model_enc_str));
-
- util_replace_whitespace(dev_scsi->vendor, vendor_str, sizeof(vendor_str));
- util_replace_chars(vendor_str, NULL);
- util_replace_whitespace(dev_scsi->model, model_str, sizeof(model_str));
- util_replace_chars(model_str, NULL);
- set_type(dev_scsi->type, type_str, sizeof(type_str));
- util_replace_whitespace(dev_scsi->revision, revision_str, sizeof(revision_str));
- util_replace_chars(revision_str, NULL);
- return 0;
-}
-
-/*
- * scsi_id: try to get an id, if one is found, printf it to stdout.
- * returns a value passed to exit() - 0 if printed an id, else 1.
- */
-static int scsi_id(struct udev *udev, char *maj_min_dev)
-{
- struct scsi_id_device dev_scsi = {};
- int good_dev;
- int page_code;
- int retval = 0;
-
- if (set_inq_values(udev, &dev_scsi, maj_min_dev) < 0) {
- retval = 1;
- goto out;
- }
-
- /* get per device (vendor + model) options from the config file */
- per_dev_options(udev, &dev_scsi, &good_dev, &page_code);
- if (!good_dev) {
- retval = 1;
- goto out;
- }
-
- /* read serial number from mode pages (no values for optical drives) */
- scsi_get_serial(udev, &dev_scsi, maj_min_dev, page_code, MAX_SERIAL_LEN);
-
- if (export) {
- char serial_str[MAX_SERIAL_LEN];
-
- printf("ID_SCSI=1\n");
- printf("ID_VENDOR=%s\n", vendor_str);
- printf("ID_VENDOR_ENC=%s\n", vendor_enc_str);
- printf("ID_MODEL=%s\n", model_str);
- printf("ID_MODEL_ENC=%s\n", model_enc_str);
- printf("ID_REVISION=%s\n", revision_str);
- printf("ID_TYPE=%s\n", type_str);
- if (dev_scsi.serial[0] != '\0') {
- util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str));
- util_replace_chars(serial_str, NULL);
- printf("ID_SERIAL=%s\n", serial_str);
- util_replace_whitespace(dev_scsi.serial_short, serial_str, sizeof(serial_str));
- util_replace_chars(serial_str, NULL);
- printf("ID_SERIAL_SHORT=%s\n", serial_str);
- }
- if (dev_scsi.wwn[0] != '\0') {
- printf("ID_WWN=0x%s\n", dev_scsi.wwn);
- if (dev_scsi.wwn_vendor_extension[0] != '\0') {
- printf("ID_WWN_VENDOR_EXTENSION=0x%s\n", dev_scsi.wwn_vendor_extension);
- printf("ID_WWN_WITH_EXTENSION=0x%s%s\n", dev_scsi.wwn, dev_scsi.wwn_vendor_extension);
- } else
- printf("ID_WWN_WITH_EXTENSION=0x%s\n", dev_scsi.wwn);
- }
- if (dev_scsi.tgpt_group[0] != '\0')
- printf("ID_TARGET_PORT=%s\n", dev_scsi.tgpt_group);
- if (dev_scsi.unit_serial_number[0] != '\0')
- printf("ID_SCSI_SERIAL=%s\n", dev_scsi.unit_serial_number);
- goto out;
- }
-
- if (dev_scsi.serial[0] == '\0') {
- retval = 1;
- goto out;
- }
-
- if (reformat_serial) {
- char serial_str[MAX_SERIAL_LEN];
-
- util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str));
- util_replace_chars(serial_str, NULL);
- printf("%s\n", serial_str);
- goto out;
- }
-
- printf("%s\n", dev_scsi.serial);
-out:
- return retval;
-}
-
-int main(int argc, char **argv)
-{
- _cleanup_udev_unref_ struct udev *udev;
- int retval = 0;
- char maj_min_dev[MAX_PATH_LEN];
- int newargc;
- char **newargv = NULL;
-
- log_parse_environment();
- log_open();
-
- udev = udev_new();
- if (udev == NULL)
- goto exit;
-
- /*
- * Get config file options.
- */
- retval = get_file_options(udev, NULL, NULL, &newargc, &newargv);
- if (retval < 0) {
- retval = 1;
- goto exit;
- }
- if (retval == 0) {
- assert(newargv);
-
- if (set_options(udev, newargc, newargv, maj_min_dev) < 0) {
- retval = 2;
- goto exit;
- }
- }
-
- /*
- * Get command line options (overriding any config file settings).
- */
- if (set_options(udev, argc, argv, maj_min_dev) < 0)
- exit(1);
-
- if (!dev_specified) {
- log_error("No device specified.");
- retval = 1;
- goto exit;
- }
-
- retval = scsi_id(udev, maj_min_dev);
-
-exit:
- if (newargv) {
- free(newargv[0]);
- free(newargv);
- }
- log_close();
- return retval;
-}
diff --git a/src/udev/scsi_id/scsi_id.h b/src/udev/scsi_id/scsi_id.h
deleted file mode 100644
index 5c2e1c28ee..0000000000
--- a/src/udev/scsi_id/scsi_id.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) IBM Corp. 2003
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#define MAX_PATH_LEN 512
-
-/*
- * MAX_ATTR_LEN: maximum length of the result of reading a sysfs
- * attribute.
- */
-#define MAX_ATTR_LEN 256
-
-/*
- * MAX_SERIAL_LEN: the maximum length of the serial number, including
- * added prefixes such as vendor and product (model) strings.
- */
-#define MAX_SERIAL_LEN 256
-
-/*
- * MAX_BUFFER_LEN: maximum buffer size and line length used while reading
- * the config file.
- */
-#define MAX_BUFFER_LEN 256
-
-struct scsi_id_device {
- char vendor[9];
- char model[17];
- char revision[5];
- char type[33];
- char kernel[64];
- char serial[MAX_SERIAL_LEN];
- char serial_short[MAX_SERIAL_LEN];
- int use_sg;
-
- /* Always from page 0x80 e.g. 'B3G1P8500RWT' - may not be unique */
- char unit_serial_number[MAX_SERIAL_LEN];
-
- /* NULs if not set - otherwise hex encoding using lower-case e.g. '50014ee0016eb572' */
- char wwn[17];
-
- /* NULs if not set - otherwise hex encoding using lower-case e.g. '0xe00000d80000' */
- char wwn_vendor_extension[17];
-
- /* NULs if not set - otherwise decimal number */
- char tgpt_group[8];
-};
-
-int scsi_std_inquiry(struct udev *udev, struct scsi_id_device *dev_scsi, const char *devname);
-int scsi_get_serial(struct udev *udev, struct scsi_id_device *dev_scsi, const char *devname,
- int page_code, int len);
-
-/*
- * Page code values.
- */
-enum page_code {
- PAGE_83_PRE_SPC3 = -0x83,
- PAGE_UNSPECIFIED = 0x00,
- PAGE_80 = 0x80,
- PAGE_83 = 0x83,
-};
diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c
deleted file mode 100644
index e079e28698..0000000000
--- a/src/udev/scsi_id/scsi_serial.c
+++ /dev/null
@@ -1,964 +0,0 @@
-/*
- * Copyright (C) IBM Corp. 2003
- *
- * Author: Patrick Mansfield<patmans@us.ibm.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <linux/bsg.h>
-#include <linux/types.h>
-#include <scsi/scsi.h>
-#include <scsi/sg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "libudev.h"
-
-#include "libudev-private.h"
-#include "random-util.h"
-#include "scsi.h"
-#include "scsi_id.h"
-#include "string-util.h"
-
-/*
- * A priority based list of id, naa, and binary/ascii for the identifier
- * descriptor in VPD page 0x83.
- *
- * Brute force search for a match starting with the first value in the
- * following id_search_list. This is not a performance issue, since there
- * is normally one or some small number of descriptors.
- */
-static const struct scsi_id_search_values id_search_list[] = {
- { SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
- { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY },
- { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII },
- { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY },
- { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII },
- /*
- * Devices already exist using NAA values that are now marked
- * reserved. These should not conflict with other values, or it is
- * a bug in the device. As long as we find the IEEE extended one
- * first, we really don't care what other ones are used. Using
- * don't care here means that a device that returns multiple
- * non-IEEE descriptors in a random order will get different
- * names.
- */
- { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
- { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII },
- { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
- { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII },
- { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
- { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII },
- { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY },
- { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII },
-};
-
-static const char hex_str[]="0123456789abcdef";
-
-/*
- * Values returned in the result/status, only the ones used by the code
- * are used here.
- */
-
-#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */
-#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */
-#define DID_TIME_OUT 0x03 /* Timed out for some other reason */
-#define DRIVER_TIMEOUT 0x06
-#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */
-
-/* The following "category" function returns one of the following */
-#define SG_ERR_CAT_CLEAN 0 /* No errors or other information */
-#define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */
-#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */
-#define SG_ERR_CAT_TIMEOUT 3
-#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */
-#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */
-#define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */
-#define SG_ERR_CAT_OTHER 99 /* Some other error/warning */
-
-static int do_scsi_page80_inquiry(struct udev *udev,
- struct scsi_id_device *dev_scsi, int fd,
- char *serial, char *serial_short, int max_len);
-
-static int sg_err_category_new(struct udev *udev,
- int scsi_status, int msg_status, int
- host_status, int driver_status, const
- unsigned char *sense_buffer, int sb_len)
-{
- scsi_status &= 0x7e;
-
- /*
- * XXX change to return only two values - failed or OK.
- */
-
- if (!scsi_status && !host_status && !driver_status)
- return SG_ERR_CAT_CLEAN;
-
- if ((scsi_status == SCSI_CHECK_CONDITION) ||
- (scsi_status == SCSI_COMMAND_TERMINATED) ||
- ((driver_status & 0xf) == DRIVER_SENSE)) {
- if (sense_buffer && (sb_len > 2)) {
- int sense_key;
- unsigned char asc;
-
- if (sense_buffer[0] & 0x2) {
- sense_key = sense_buffer[1] & 0xf;
- asc = sense_buffer[2];
- } else {
- sense_key = sense_buffer[2] & 0xf;
- asc = (sb_len > 12) ? sense_buffer[12] : 0;
- }
-
- if (sense_key == RECOVERED_ERROR)
- return SG_ERR_CAT_RECOVERED;
- else if (sense_key == UNIT_ATTENTION) {
- if (0x28 == asc)
- return SG_ERR_CAT_MEDIA_CHANGED;
- if (0x29 == asc)
- return SG_ERR_CAT_RESET;
- } else if (sense_key == ILLEGAL_REQUEST)
- return SG_ERR_CAT_NOTSUPPORTED;
- }
- return SG_ERR_CAT_SENSE;
- }
- if (host_status) {
- if ((host_status == DID_NO_CONNECT) ||
- (host_status == DID_BUS_BUSY) ||
- (host_status == DID_TIME_OUT))
- return SG_ERR_CAT_TIMEOUT;
- }
- if (driver_status) {
- if (driver_status == DRIVER_TIMEOUT)
- return SG_ERR_CAT_TIMEOUT;
- }
- return SG_ERR_CAT_OTHER;
-}
-
-static int sg_err_category3(struct udev *udev, struct sg_io_hdr *hp)
-{
- return sg_err_category_new(udev,
- hp->status, hp->msg_status,
- hp->host_status, hp->driver_status,
- hp->sbp, hp->sb_len_wr);
-}
-
-static int sg_err_category4(struct udev *udev, struct sg_io_v4 *hp)
-{
- return sg_err_category_new(udev, hp->device_status, 0,
- hp->transport_status, hp->driver_status,
- (unsigned char *)(uintptr_t)hp->response,
- hp->response_len);
-}
-
-static int scsi_dump_sense(struct udev *udev,
- struct scsi_id_device *dev_scsi,
- unsigned char *sense_buffer, int sb_len)
-{
- int s;
- int code;
- int sense_class;
- int sense_key;
- int asc, ascq;
-#ifdef DUMP_SENSE
- char out_buffer[256];
- int i, j;
-#endif
-
- /*
- * Figure out and print the sense key, asc and ascq.
- *
- * If you want to suppress these for a particular drive model, add
- * a black list entry in the scsi_id config file.
- *
- * XXX We probably need to: lookup the sense/asc/ascq in a retry
- * table, and if found return 1 (after dumping the sense, asc, and
- * ascq). So, if/when we get something like a power on/reset,
- * we'll retry the command.
- */
-
- if (sb_len < 1) {
- log_debug("%s: sense buffer empty", dev_scsi->kernel);
- return -1;
- }
-
- sense_class = (sense_buffer[0] >> 4) & 0x07;
- code = sense_buffer[0] & 0xf;
-
- if (sense_class == 7) {
- /*
- * extended sense data.
- */
- s = sense_buffer[7] + 8;
- if (sb_len < s) {
- log_debug("%s: sense buffer too small %d bytes, %d bytes too short",
- dev_scsi->kernel, sb_len, s - sb_len);
- return -1;
- }
- if ((code == 0x0) || (code == 0x1)) {
- sense_key = sense_buffer[2] & 0xf;
- if (s < 14) {
- /*
- * Possible?
- */
- log_debug("%s: sense result too" " small %d bytes",
- dev_scsi->kernel, s);
- return -1;
- }
- asc = sense_buffer[12];
- ascq = sense_buffer[13];
- } else if ((code == 0x2) || (code == 0x3)) {
- sense_key = sense_buffer[1] & 0xf;
- asc = sense_buffer[2];
- ascq = sense_buffer[3];
- } else {
- log_debug("%s: invalid sense code 0x%x",
- dev_scsi->kernel, code);
- return -1;
- }
- log_debug("%s: sense key 0x%x ASC 0x%x ASCQ 0x%x",
- dev_scsi->kernel, sense_key, asc, ascq);
- } else {
- if (sb_len < 4) {
- log_debug("%s: sense buffer too small %d bytes, %d bytes too short",
- dev_scsi->kernel, sb_len, 4 - sb_len);
- return -1;
- }
-
- if (sense_buffer[0] < 15)
- log_debug("%s: old sense key: 0x%x", dev_scsi->kernel, sense_buffer[0] & 0x0f);
- else
- log_debug("%s: sense = %2x %2x",
- dev_scsi->kernel, sense_buffer[0], sense_buffer[2]);
- log_debug("%s: non-extended sense class %d code 0x%0x",
- dev_scsi->kernel, sense_class, code);
-
- }
-
-#ifdef DUMP_SENSE
- for (i = 0, j = 0; (i < s) && (j < 254); i++) {
- out_buffer[j++] = hex_str[(sense_buffer[i] & 0xf0) >> 4];
- out_buffer[j++] = hex_str[sense_buffer[i] & 0x0f];
- out_buffer[j++] = ' ';
- }
- out_buffer[j] = '\0';
- log_debug("%s: sense dump:", dev_scsi->kernel);
- log_debug("%s: %s", dev_scsi->kernel, out_buffer);
-
-#endif
- return -1;
-}
-
-static int scsi_dump(struct udev *udev,
- struct scsi_id_device *dev_scsi, struct sg_io_hdr *io)
-{
- if (!io->status && !io->host_status && !io->msg_status &&
- !io->driver_status) {
- /*
- * Impossible, should not be called.
- */
- log_debug("%s: called with no error", __FUNCTION__);
- return -1;
- }
-
- log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x",
- dev_scsi->kernel, io->driver_status, io->host_status, io->msg_status, io->status);
- if (io->status == SCSI_CHECK_CONDITION)
- return scsi_dump_sense(udev, dev_scsi, io->sbp, io->sb_len_wr);
- else
- return -1;
-}
-
-static int scsi_dump_v4(struct udev *udev,
- struct scsi_id_device *dev_scsi, struct sg_io_v4 *io)
-{
- if (!io->device_status && !io->transport_status &&
- !io->driver_status) {
- /*
- * Impossible, should not be called.
- */
- log_debug("%s: called with no error", __FUNCTION__);
- return -1;
- }
-
- log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x",
- dev_scsi->kernel, io->driver_status, io->transport_status, io->device_status);
- if (io->device_status == SCSI_CHECK_CONDITION)
- return scsi_dump_sense(udev, dev_scsi, (unsigned char *)(uintptr_t)io->response,
- io->response_len);
- else
- return -1;
-}
-
-static int scsi_inquiry(struct udev *udev,
- struct scsi_id_device *dev_scsi, int fd,
- unsigned char evpd, unsigned char page,
- unsigned char *buf, unsigned int buflen)
-{
- unsigned char inq_cmd[INQUIRY_CMDLEN] =
- { INQUIRY_CMD, evpd, page, 0, buflen, 0 };
- unsigned char sense[SENSE_BUFF_LEN];
- void *io_buf;
- struct sg_io_v4 io_v4;
- struct sg_io_hdr io_hdr;
- int retry = 3; /* rather random */
- int retval;
-
- if (buflen > SCSI_INQ_BUFF_LEN) {
- log_debug("buflen %d too long", buflen);
- return -1;
- }
-
-resend:
- if (dev_scsi->use_sg == 4) {
- memzero(&io_v4, sizeof(struct sg_io_v4));
- io_v4.guard = 'Q';
- io_v4.protocol = BSG_PROTOCOL_SCSI;
- io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
- io_v4.request_len = sizeof(inq_cmd);
- io_v4.request = (uintptr_t)inq_cmd;
- io_v4.max_response_len = sizeof(sense);
- io_v4.response = (uintptr_t)sense;
- io_v4.din_xfer_len = buflen;
- io_v4.din_xferp = (uintptr_t)buf;
- io_buf = (void *)&io_v4;
- } else {
- memzero(&io_hdr, sizeof(struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof(inq_cmd);
- io_hdr.mx_sb_len = sizeof(sense);
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = buflen;
- io_hdr.dxferp = buf;
- io_hdr.cmdp = inq_cmd;
- io_hdr.sbp = sense;
- io_hdr.timeout = DEF_TIMEOUT;
- io_buf = (void *)&io_hdr;
- }
-
- retval = ioctl(fd, SG_IO, io_buf);
- if (retval < 0) {
- if ((errno == EINVAL || errno == ENOSYS) && dev_scsi->use_sg == 4) {
- dev_scsi->use_sg = 3;
- goto resend;
- }
- log_debug_errno(errno, "%s: ioctl failed: %m", dev_scsi->kernel);
- goto error;
- }
-
- if (dev_scsi->use_sg == 4)
- retval = sg_err_category4(udev, io_buf);
- else
- retval = sg_err_category3(udev, io_buf);
-
- switch (retval) {
- case SG_ERR_CAT_NOTSUPPORTED:
- buf[1] = 0;
- /* Fallthrough */
- case SG_ERR_CAT_CLEAN:
- case SG_ERR_CAT_RECOVERED:
- retval = 0;
- break;
-
- default:
- if (dev_scsi->use_sg == 4)
- retval = scsi_dump_v4(udev, dev_scsi, io_buf);
- else
- retval = scsi_dump(udev, dev_scsi, io_buf);
- }
-
- if (!retval) {
- retval = buflen;
- } else if (retval > 0) {
- if (--retry > 0)
- goto resend;
- retval = -1;
- }
-
-error:
- if (retval < 0)
- log_debug("%s: Unable to get INQUIRY vpd %d page 0x%x.",
- dev_scsi->kernel, evpd, page);
-
- return retval;
-}
-
-/* Get list of supported EVPD pages */
-static int do_scsi_page0_inquiry(struct udev *udev,
- struct scsi_id_device *dev_scsi, int fd,
- unsigned char *buffer, unsigned int len)
-{
- int retval;
-
- memzero(buffer, len);
- retval = scsi_inquiry(udev, dev_scsi, fd, 1, 0x0, buffer, len);
- if (retval < 0)
- return 1;
-
- if (buffer[1] != 0) {
- log_debug("%s: page 0 not available.", dev_scsi->kernel);
- return 1;
- }
- if (buffer[3] > len) {
- log_debug("%s: page 0 buffer too long %d", dev_scsi->kernel, buffer[3]);
- return 1;
- }
-
- /*
- * Following check is based on code once included in the 2.5.x
- * kernel.
- *
- * Some ill behaved devices return the standard inquiry here
- * rather than the evpd data, snoop the data to verify.
- */
- if (buffer[3] > MODEL_LENGTH) {
- /*
- * If the vendor id appears in the page assume the page is
- * invalid.
- */
- if (strneq((char *)&buffer[VENDOR_LENGTH], dev_scsi->vendor, VENDOR_LENGTH)) {
- log_debug("%s: invalid page0 data", dev_scsi->kernel);
- return 1;
- }
- }
- return 0;
-}
-
-/*
- * The caller checks that serial is long enough to include the vendor +
- * model.
- */
-static int prepend_vendor_model(struct udev *udev,
- struct scsi_id_device *dev_scsi, char *serial)
-{
- int ind;
-
- strncpy(serial, dev_scsi->vendor, VENDOR_LENGTH);
- strncat(serial, dev_scsi->model, MODEL_LENGTH);
- ind = strlen(serial);
-
- /*
- * This is not a complete check, since we are using strncat/cpy
- * above, ind will never be too large.
- */
- if (ind != (VENDOR_LENGTH + MODEL_LENGTH)) {
- log_debug("%s: expected length %d, got length %d",
- dev_scsi->kernel, (VENDOR_LENGTH + MODEL_LENGTH), ind);
- return -1;
- }
- return ind;
-}
-
-/*
- * check_fill_0x83_id - check the page 0x83 id, if OK allocate and fill
- * serial number.
- */
-static int check_fill_0x83_id(struct udev *udev,
- struct scsi_id_device *dev_scsi,
- unsigned char *page_83,
- const struct scsi_id_search_values
- *id_search, char *serial, char *serial_short,
- int max_len, char *wwn,
- char *wwn_vendor_extension, char *tgpt_group)
-{
- int i, j, s, len;
-
- /*
- * ASSOCIATION must be with the device (value 0)
- * or with the target port for SCSI_ID_TGTPORT
- */
- if ((page_83[1] & 0x30) == 0x10) {
- if (id_search->id_type != SCSI_ID_TGTGROUP)
- return 1;
- } else if ((page_83[1] & 0x30) != 0)
- return 1;
-
- if ((page_83[1] & 0x0f) != id_search->id_type)
- return 1;
-
- /*
- * Possibly check NAA sub-type.
- */
- if ((id_search->naa_type != SCSI_ID_NAA_DONT_CARE) &&
- (id_search->naa_type != (page_83[4] & 0xf0) >> 4))
- return 1;
-
- /*
- * Check for matching code set - ASCII or BINARY.
- */
- if ((page_83[0] & 0x0f) != id_search->code_set)
- return 1;
-
- /*
- * page_83[3]: identifier length
- */
- len = page_83[3];
- if ((page_83[0] & 0x0f) != SCSI_ID_ASCII)
- /*
- * If not ASCII, use two bytes for each binary value.
- */
- len *= 2;
-
- /*
- * Add one byte for the NUL termination, and one for the id_type.
- */
- len += 2;
- if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC)
- len += VENDOR_LENGTH + MODEL_LENGTH;
-
- if (max_len < len) {
- log_debug("%s: length %d too short - need %d",
- dev_scsi->kernel, max_len, len);
- return 1;
- }
-
- if (id_search->id_type == SCSI_ID_TGTGROUP && tgpt_group != NULL) {
- unsigned int group;
-
- group = ((unsigned int)page_83[6] << 8) | page_83[7];
- sprintf(tgpt_group,"%x", group);
- return 1;
- }
-
- serial[0] = hex_str[id_search->id_type];
-
- /*
- * For SCSI_ID_VENDOR_SPECIFIC prepend the vendor and model before
- * the id since it is not unique across all vendors and models,
- * this differs from SCSI_ID_T10_VENDOR, where the vendor is
- * included in the identifier.
- */
- if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC)
- if (prepend_vendor_model(udev, dev_scsi, &serial[1]) < 0)
- return 1;
-
- i = 4; /* offset to the start of the identifier */
- s = j = strlen(serial);
- if ((page_83[0] & 0x0f) == SCSI_ID_ASCII) {
- /*
- * ASCII descriptor.
- */
- while (i < (4 + page_83[3]))
- serial[j++] = page_83[i++];
- } else {
- /*
- * Binary descriptor, convert to ASCII, using two bytes of
- * ASCII for each byte in the page_83.
- */
- while (i < (4 + page_83[3])) {
- serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4];
- serial[j++] = hex_str[page_83[i] & 0x0f];
- i++;
- }
- }
-
- strcpy(serial_short, &serial[s]);
-
- if (id_search->id_type == SCSI_ID_NAA && wwn != NULL) {
- strncpy(wwn, &serial[s], 16);
- if (wwn_vendor_extension != NULL)
- strncpy(wwn_vendor_extension, &serial[s + 16], 16);
- }
-
- return 0;
-}
-
-/* Extract the raw binary from VPD 0x83 pre-SPC devices */
-static int check_fill_0x83_prespc3(struct udev *udev,
- struct scsi_id_device *dev_scsi,
- unsigned char *page_83,
- const struct scsi_id_search_values
- *id_search, char *serial, char *serial_short, int max_len)
-{
- int i, j;
-
- serial[0] = hex_str[id_search->id_type];
- /* serial has been memset to zero before */
- j = strlen(serial); /* j = 1; */
-
- for (i = 0; (i < page_83[3]) && (j < max_len-3); ++i) {
- serial[j++] = hex_str[(page_83[4+i] & 0xf0) >> 4];
- serial[j++] = hex_str[ page_83[4+i] & 0x0f];
- }
- serial[max_len-1] = 0;
- strncpy(serial_short, serial, max_len-1);
- return 0;
-}
-
-
-/* Get device identification VPD page */
-static int do_scsi_page83_inquiry(struct udev *udev,
- struct scsi_id_device *dev_scsi, int fd,
- char *serial, char *serial_short, int len,
- char *unit_serial_number, char *wwn,
- char *wwn_vendor_extension, char *tgpt_group)
-{
- int retval;
- unsigned int id_ind, j;
- unsigned char page_83[SCSI_INQ_BUFF_LEN];
-
- /* also pick up the page 80 serial number */
- do_scsi_page80_inquiry(udev, dev_scsi, fd, NULL, unit_serial_number, MAX_SERIAL_LEN);
-
- memzero(page_83, SCSI_INQ_BUFF_LEN);
- retval = scsi_inquiry(udev, dev_scsi, fd, 1, PAGE_83, page_83,
- SCSI_INQ_BUFF_LEN);
- if (retval < 0)
- return 1;
-
- if (page_83[1] != PAGE_83) {
- log_debug("%s: Invalid page 0x83", dev_scsi->kernel);
- return 1;
- }
-
- /*
- * XXX Some devices (IBM 3542) return all spaces for an identifier if
- * the LUN is not actually configured. This leads to identifiers of
- * the form: "1 ".
- */
-
- /*
- * Model 4, 5, and (some) model 6 EMC Symmetrix devices return
- * a page 83 reply according to SCSI-2 format instead of SPC-2/3.
- *
- * The SCSI-2 page 83 format returns an IEEE WWN in binary
- * encoded hexi-decimal in the 16 bytes following the initial
- * 4-byte page 83 reply header.
- *
- * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part
- * of an Identification descriptor. The 3rd byte of the first
- * Identification descriptor is a reserved (BSZ) byte field.
- *
- * Reference the 7th byte of the page 83 reply to determine
- * whether the reply is compliant with SCSI-2 or SPC-2/3
- * specifications. A zero value in the 7th byte indicates
- * an SPC-2/3 conformant reply, (i.e., the reserved field of the
- * first Identification descriptor). This byte will be non-zero
- * for a SCSI-2 conformant page 83 reply from these EMC
- * Symmetrix models since the 7th byte of the reply corresponds
- * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is,
- * 0x006048.
- */
-
- if (page_83[6] != 0)
- return check_fill_0x83_prespc3(udev,
- dev_scsi, page_83, id_search_list,
- serial, serial_short, len);
-
- /*
- * Search for a match in the prioritized id_search_list - since WWN ids
- * come first we can pick up the WWN in check_fill_0x83_id().
- */
- for (id_ind = 0;
- id_ind < sizeof(id_search_list)/sizeof(id_search_list[0]);
- id_ind++) {
- /*
- * Examine each descriptor returned. There is normally only
- * one or a small number of descriptors.
- */
- for (j = 4; j <= (unsigned int)page_83[3] + 3; j += page_83[j + 3] + 4) {
- retval = check_fill_0x83_id(udev,
- dev_scsi, &page_83[j],
- &id_search_list[id_ind],
- serial, serial_short, len,
- wwn, wwn_vendor_extension,
- tgpt_group);
- if (!retval)
- return retval;
- else if (retval < 0)
- return retval;
- }
- }
- return 1;
-}
-
-/*
- * Get device identification VPD page for older SCSI-2 device which is not
- * compliant with either SPC-2 or SPC-3 format.
- *
- * Return the hard coded error code value 2 if the page 83 reply is not
- * conformant to the SCSI-2 format.
- */
-static int do_scsi_page83_prespc3_inquiry(struct udev *udev,
- struct scsi_id_device *dev_scsi, int fd,
- char *serial, char *serial_short, int len)
-{
- int retval;
- int i, j;
- unsigned char page_83[SCSI_INQ_BUFF_LEN];
-
- memzero(page_83, SCSI_INQ_BUFF_LEN);
- retval = scsi_inquiry(udev, dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN);
- if (retval < 0)
- return 1;
-
- if (page_83[1] != PAGE_83) {
- log_debug("%s: Invalid page 0x83", dev_scsi->kernel);
- return 1;
- }
- /*
- * Model 4, 5, and (some) model 6 EMC Symmetrix devices return
- * a page 83 reply according to SCSI-2 format instead of SPC-2/3.
- *
- * The SCSI-2 page 83 format returns an IEEE WWN in binary
- * encoded hexi-decimal in the 16 bytes following the initial
- * 4-byte page 83 reply header.
- *
- * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part
- * of an Identification descriptor. The 3rd byte of the first
- * Identification descriptor is a reserved (BSZ) byte field.
- *
- * Reference the 7th byte of the page 83 reply to determine
- * whether the reply is compliant with SCSI-2 or SPC-2/3
- * specifications. A zero value in the 7th byte indicates
- * an SPC-2/3 conformant reply, (i.e., the reserved field of the
- * first Identification descriptor). This byte will be non-zero
- * for a SCSI-2 conformant page 83 reply from these EMC
- * Symmetrix models since the 7th byte of the reply corresponds
- * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is,
- * 0x006048.
- */
- if (page_83[6] == 0)
- return 2;
-
- serial[0] = hex_str[id_search_list[0].id_type];
- /*
- * The first four bytes contain data, not a descriptor.
- */
- i = 4;
- j = strlen(serial);
- /*
- * Binary descriptor, convert to ASCII,
- * using two bytes of ASCII for each byte
- * in the page_83.
- */
- while (i < (page_83[3]+4)) {
- serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4];
- serial[j++] = hex_str[page_83[i] & 0x0f];
- i++;
- }
- return 0;
-}
-
-/* Get unit serial number VPD page */
-static int do_scsi_page80_inquiry(struct udev *udev,
- struct scsi_id_device *dev_scsi, int fd,
- char *serial, char *serial_short, int max_len)
-{
- int retval;
- int ser_ind;
- int i;
- int len;
- unsigned char buf[SCSI_INQ_BUFF_LEN];
-
- memzero(buf, SCSI_INQ_BUFF_LEN);
- retval = scsi_inquiry(udev, dev_scsi, fd, 1, PAGE_80, buf, SCSI_INQ_BUFF_LEN);
- if (retval < 0)
- return retval;
-
- if (buf[1] != PAGE_80) {
- log_debug("%s: Invalid page 0x80", dev_scsi->kernel);
- return 1;
- }
-
- len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3];
- if (max_len < len) {
- log_debug("%s: length %d too short - need %d",
- dev_scsi->kernel, max_len, len);
- return 1;
- }
- /*
- * Prepend 'S' to avoid unlikely collision with page 0x83 vendor
- * specific type where we prepend '0' + vendor + model.
- */
- len = buf[3];
- if (serial != NULL) {
- serial[0] = 'S';
- ser_ind = prepend_vendor_model(udev, dev_scsi, &serial[1]);
- if (ser_ind < 0)
- return 1;
- ser_ind++; /* for the leading 'S' */
- for (i = 4; i < len + 4; i++, ser_ind++)
- serial[ser_ind] = buf[i];
- }
- if (serial_short != NULL) {
- memcpy(serial_short, &buf[4], len);
- serial_short[len] = '\0';
- }
- return 0;
-}
-
-int scsi_std_inquiry(struct udev *udev,
- struct scsi_id_device *dev_scsi, const char *devname)
-{
- int fd;
- unsigned char buf[SCSI_INQ_BUFF_LEN];
- struct stat statbuf;
- int err = 0;
-
- fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
- if (fd < 0) {
- log_debug_errno(errno, "scsi_id: cannot open %s: %m", devname);
- return 1;
- }
-
- if (fstat(fd, &statbuf) < 0) {
- log_debug_errno(errno, "scsi_id: cannot stat %s: %m", devname);
- err = 2;
- goto out;
- }
- sprintf(dev_scsi->kernel,"%d:%d", major(statbuf.st_rdev),
- minor(statbuf.st_rdev));
-
- memzero(buf, SCSI_INQ_BUFF_LEN);
- err = scsi_inquiry(udev, dev_scsi, fd, 0, 0, buf, SCSI_INQ_BUFF_LEN);
- if (err < 0)
- goto out;
-
- err = 0;
- memcpy(dev_scsi->vendor, buf + 8, 8);
- dev_scsi->vendor[8] = '\0';
- memcpy(dev_scsi->model, buf + 16, 16);
- dev_scsi->model[16] = '\0';
- memcpy(dev_scsi->revision, buf + 32, 4);
- dev_scsi->revision[4] = '\0';
- sprintf(dev_scsi->type,"%x", buf[0] & 0x1f);
-
-out:
- close(fd);
- return err;
-}
-
-int scsi_get_serial(struct udev *udev,
- struct scsi_id_device *dev_scsi, const char *devname,
- int page_code, int len)
-{
- unsigned char page0[SCSI_INQ_BUFF_LEN];
- int fd = -1;
- int cnt;
- int ind;
- int retval;
-
- memzero(dev_scsi->serial, len);
- initialize_srand();
- for (cnt = 20; cnt > 0; cnt--) {
- struct timespec duration;
-
- fd = open(devname, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
- if (fd >= 0 || errno != EBUSY)
- break;
- duration.tv_sec = 0;
- duration.tv_nsec = (200 * 1000 * 1000) + (rand() % 100 * 1000 * 1000);
- nanosleep(&duration, NULL);
- }
- if (fd < 0)
- return 1;
-
- if (page_code == PAGE_80) {
- if (do_scsi_page80_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len)) {
- retval = 1;
- goto completed;
- } else {
- retval = 0;
- goto completed;
- }
- } else if (page_code == PAGE_83) {
- if (do_scsi_page83_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) {
- retval = 1;
- goto completed;
- } else {
- retval = 0;
- goto completed;
- }
- } else if (page_code == PAGE_83_PRE_SPC3) {
- retval = do_scsi_page83_prespc3_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len);
- if (retval) {
- /*
- * Fallback to servicing a SPC-2/3 compliant page 83
- * inquiry if the page 83 reply format does not
- * conform to pre-SPC3 expectations.
- */
- if (retval == 2) {
- if (do_scsi_page83_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) {
- retval = 1;
- goto completed;
- } else {
- retval = 0;
- goto completed;
- }
- }
- else {
- retval = 1;
- goto completed;
- }
- } else {
- retval = 0;
- goto completed;
- }
- } else if (page_code != 0x00) {
- log_debug("%s: unsupported page code 0x%d", dev_scsi->kernel, page_code);
- retval = 1;
- goto completed;
- }
-
- /*
- * Get page 0, the page of the pages. By default, try from best to
- * worst of supported pages: 0x83 then 0x80.
- */
- if (do_scsi_page0_inquiry(udev, dev_scsi, fd, page0, SCSI_INQ_BUFF_LEN)) {
- /*
- * Don't try anything else. Black list if a specific page
- * should be used for this vendor+model, or maybe have an
- * optional fall-back to page 0x80 or page 0x83.
- */
- retval = 1;
- goto completed;
- }
-
- for (ind = 4; ind <= page0[3] + 3; ind++)
- if (page0[ind] == PAGE_83)
- if (!do_scsi_page83_inquiry(udev, dev_scsi, fd,
- dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) {
- /*
- * Success
- */
- retval = 0;
- goto completed;
- }
-
- for (ind = 4; ind <= page0[3] + 3; ind++)
- if (page0[ind] == PAGE_80)
- if (!do_scsi_page80_inquiry(udev, dev_scsi, fd,
- dev_scsi->serial, dev_scsi->serial_short, len)) {
- /*
- * Success
- */
- retval = 0;
- goto completed;
- }
- retval = 1;
-
-completed:
- close(fd);
- return retval;
-}
diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c
deleted file mode 100644
index 3c58445836..0000000000
--- a/src/udev/udev-builtin-blkid.c
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * probe disks for filesystems and partitions
- *
- * Copyright (C) 2011 Kay Sievers <kay@vrfy.org>
- * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <blkid/blkid.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#include "sd-id128.h"
-
-#include "alloc-util.h"
-#include "efivars.h"
-#include "fd-util.h"
-#include "gpt.h"
-#include "string-util.h"
-#include "udev.h"
-
-static void print_property(struct udev_device *dev, bool test, const char *name, const char *value) {
- char s[256];
-
- s[0] = '\0';
-
- if (streq(name, "TYPE")) {
- udev_builtin_add_property(dev, test, "ID_FS_TYPE", value);
-
- } else if (streq(name, "USAGE")) {
- udev_builtin_add_property(dev, test, "ID_FS_USAGE", value);
-
- } else if (streq(name, "VERSION")) {
- udev_builtin_add_property(dev, test, "ID_FS_VERSION", value);
-
- } else if (streq(name, "UUID")) {
- blkid_safe_string(value, s, sizeof(s));
- udev_builtin_add_property(dev, test, "ID_FS_UUID", s);
- blkid_encode_string(value, s, sizeof(s));
- udev_builtin_add_property(dev, test, "ID_FS_UUID_ENC", s);
-
- } else if (streq(name, "UUID_SUB")) {
- blkid_safe_string(value, s, sizeof(s));
- udev_builtin_add_property(dev, test, "ID_FS_UUID_SUB", s);
- blkid_encode_string(value, s, sizeof(s));
- udev_builtin_add_property(dev, test, "ID_FS_UUID_SUB_ENC", s);
-
- } else if (streq(name, "LABEL")) {
- blkid_safe_string(value, s, sizeof(s));
- udev_builtin_add_property(dev, test, "ID_FS_LABEL", s);
- blkid_encode_string(value, s, sizeof(s));
- udev_builtin_add_property(dev, test, "ID_FS_LABEL_ENC", s);
-
- } else if (streq(name, "PTTYPE")) {
- udev_builtin_add_property(dev, test, "ID_PART_TABLE_TYPE", value);
-
- } else if (streq(name, "PTUUID")) {
- udev_builtin_add_property(dev, test, "ID_PART_TABLE_UUID", value);
-
- } else if (streq(name, "PART_ENTRY_NAME")) {
- blkid_encode_string(value, s, sizeof(s));
- udev_builtin_add_property(dev, test, "ID_PART_ENTRY_NAME", s);
-
- } else if (streq(name, "PART_ENTRY_TYPE")) {
- blkid_encode_string(value, s, sizeof(s));
- udev_builtin_add_property(dev, test, "ID_PART_ENTRY_TYPE", s);
-
- } else if (startswith(name, "PART_ENTRY_")) {
- strscpyl(s, sizeof(s), "ID_", name, NULL);
- udev_builtin_add_property(dev, test, s, value);
-
- } else if (streq(name, "SYSTEM_ID")) {
- blkid_encode_string(value, s, sizeof(s));
- udev_builtin_add_property(dev, test, "ID_FS_SYSTEM_ID", s);
-
- } else if (streq(name, "PUBLISHER_ID")) {
- blkid_encode_string(value, s, sizeof(s));
- udev_builtin_add_property(dev, test, "ID_FS_PUBLISHER_ID", s);
-
- } else if (streq(name, "APPLICATION_ID")) {
- blkid_encode_string(value, s, sizeof(s));
- udev_builtin_add_property(dev, test, "ID_FS_APPLICATION_ID", s);
-
- } else if (streq(name, "BOOT_SYSTEM_ID")) {
- blkid_encode_string(value, s, sizeof(s));
- udev_builtin_add_property(dev, test, "ID_FS_BOOT_SYSTEM_ID", s);
- }
-}
-
-static int find_gpt_root(struct udev_device *dev, blkid_probe pr, bool test) {
-
-#if defined(GPT_ROOT_NATIVE) && defined(ENABLE_EFI)
-
- _cleanup_free_ char *root_id = NULL;
- bool found_esp = false;
- blkid_partlist pl;
- int i, nvals, r;
-
- assert(pr);
-
- /* Iterate through the partitions on this disk, and see if the
- * EFI ESP we booted from is on it. If so, find the first root
- * disk, and add a property indicating its partition UUID. */
-
- errno = 0;
- pl = blkid_probe_get_partitions(pr);
- if (!pl)
- return errno > 0 ? -errno : -ENOMEM;
-
- nvals = blkid_partlist_numof_partitions(pl);
- for (i = 0; i < nvals; i++) {
- blkid_partition pp;
- const char *stype, *sid;
- sd_id128_t type;
-
- pp = blkid_partlist_get_partition(pl, i);
- if (!pp)
- continue;
-
- sid = blkid_partition_get_uuid(pp);
- if (!sid)
- continue;
-
- stype = blkid_partition_get_type_string(pp);
- if (!stype)
- continue;
-
- if (sd_id128_from_string(stype, &type) < 0)
- continue;
-
- if (sd_id128_equal(type, GPT_ESP)) {
- sd_id128_t id, esp;
-
- /* We found an ESP, let's see if it matches
- * the ESP we booted from. */
-
- if (sd_id128_from_string(sid, &id) < 0)
- continue;
-
- r = efi_loader_get_device_part_uuid(&esp);
- if (r < 0)
- return r;
-
- if (sd_id128_equal(id, esp))
- found_esp = true;
-
- } else if (sd_id128_equal(type, GPT_ROOT_NATIVE)) {
- unsigned long long flags;
-
- flags = blkid_partition_get_flags(pp);
- if (flags & GPT_FLAG_NO_AUTO)
- continue;
-
- /* We found a suitable root partition, let's
- * remember the first one. */
-
- if (!root_id) {
- root_id = strdup(sid);
- if (!root_id)
- return -ENOMEM;
- }
- }
- }
-
- /* We found the ESP on this disk, and also found a root
- * partition, nice! Let's export its UUID */
- if (found_esp && root_id)
- udev_builtin_add_property(dev, test, "ID_PART_GPT_AUTO_ROOT_UUID", root_id);
-#endif
-
- return 0;
-}
-
-static int probe_superblocks(blkid_probe pr) {
- struct stat st;
- int rc;
-
- if (fstat(blkid_probe_get_fd(pr), &st))
- return -1;
-
- blkid_probe_enable_partitions(pr, 1);
-
- if (!S_ISCHR(st.st_mode) &&
- blkid_probe_get_size(pr) <= 1024 * 1440 &&
- blkid_probe_is_wholedisk(pr)) {
- /*
- * check if the small disk is partitioned, if yes then
- * don't probe for filesystems.
- */
- blkid_probe_enable_superblocks(pr, 0);
-
- rc = blkid_do_fullprobe(pr);
- if (rc < 0)
- return rc; /* -1 = error, 1 = nothing, 0 = success */
-
- if (blkid_probe_lookup_value(pr, "PTTYPE", NULL, NULL) == 0)
- return 0; /* partition table detected */
- }
-
- blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS);
- blkid_probe_enable_superblocks(pr, 1);
-
- return blkid_do_safeprobe(pr);
-}
-
-static int builtin_blkid(struct udev_device *dev, int argc, char *argv[], bool test) {
- const char *root_partition;
- int64_t offset = 0;
- bool noraid = false;
- _cleanup_close_ int fd = -1;
- blkid_probe pr;
- const char *data;
- const char *name;
- const char *prtype = NULL;
- int nvals;
- int i;
- int err = 0;
- bool is_gpt = false;
-
- static const struct option options[] = {
- { "offset", optional_argument, NULL, 'o' },
- { "noraid", no_argument, NULL, 'R' },
- {}
- };
-
- for (;;) {
- int option;
-
- option = getopt_long(argc, argv, "oR", options, NULL);
- if (option == -1)
- break;
-
- switch (option) {
- case 'o':
- offset = strtoull(optarg, NULL, 0);
- break;
- case 'R':
- noraid = true;
- break;
- }
- }
-
- pr = blkid_new_probe();
- if (!pr)
- return EXIT_FAILURE;
-
- blkid_probe_set_superblocks_flags(pr,
- BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
- BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE |
- BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION |
- BLKID_SUBLKS_BADCSUM);
-
- if (noraid)
- blkid_probe_filter_superblocks_usage(pr, BLKID_FLTR_NOTIN, BLKID_USAGE_RAID);
-
- fd = open(udev_device_get_devnode(dev), O_RDONLY|O_CLOEXEC);
- if (fd < 0) {
- err = log_debug_errno(errno, "Failure opening block device %s: %m", udev_device_get_devnode(dev));
- goto out;
- }
-
- err = blkid_probe_set_device(pr, fd, offset, 0);
- if (err < 0)
- goto out;
-
- log_debug("probe %s %sraid offset=%"PRIi64,
- udev_device_get_devnode(dev),
- noraid ? "no" : "", offset);
-
- err = probe_superblocks(pr);
- if (err < 0)
- goto out;
- if (blkid_probe_has_value(pr, "SBBADCSUM")) {
- if (!blkid_probe_lookup_value(pr, "TYPE", &prtype, NULL))
- log_warning("incorrect %s checksum on %s",
- prtype, udev_device_get_devnode(dev));
- else
- log_warning("incorrect checksum on %s",
- udev_device_get_devnode(dev));
- goto out;
- }
-
- /* If we are a partition then our parent passed on the root
- * partition UUID to us */
- root_partition = udev_device_get_property_value(dev, "ID_PART_GPT_AUTO_ROOT_UUID");
-
- nvals = blkid_probe_numof_values(pr);
- for (i = 0; i < nvals; i++) {
- if (blkid_probe_get_value(pr, i, &name, &data, NULL))
- continue;
-
- print_property(dev, test, name, data);
-
- /* Is this a disk with GPT partition table? */
- if (streq(name, "PTTYPE") && streq(data, "gpt"))
- is_gpt = true;
-
- /* Is this a partition that matches the root partition
- * property we inherited from our parent? */
- if (root_partition && streq(name, "PART_ENTRY_UUID") && streq(data, root_partition))
- udev_builtin_add_property(dev, test, "ID_PART_GPT_AUTO_ROOT", "1");
- }
-
- if (is_gpt)
- find_gpt_root(dev, pr, test);
-
- blkid_free_probe(pr);
-out:
- if (err < 0)
- return EXIT_FAILURE;
-
- return EXIT_SUCCESS;
-}
-
-const struct udev_builtin udev_builtin_blkid = {
- .name = "blkid",
- .cmd = builtin_blkid,
- .help = "Filesystem and partition probing",
- .run_once = true,
-};
diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c
deleted file mode 100644
index cfaa463804..0000000000
--- a/src/udev/udev-builtin-btrfs.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2012 Kay Sievers <kay@vrfy.org>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-
-#ifdef HAVE_LINUX_BTRFS_H
-#include <linux/btrfs.h>
-#endif
-
-#include "fd-util.h"
-#include "missing.h"
-#include "string-util.h"
-#include "udev.h"
-
-static int builtin_btrfs(struct udev_device *dev, int argc, char *argv[], bool test) {
- struct btrfs_ioctl_vol_args args = {};
- _cleanup_close_ int fd = -1;
- int err;
-
- if (argc != 3 || !streq(argv[1], "ready"))
- return EXIT_FAILURE;
-
- fd = open("/dev/btrfs-control", O_RDWR|O_CLOEXEC);
- if (fd < 0)
- return EXIT_FAILURE;
-
- strscpy(args.name, sizeof(args.name), argv[2]);
- err = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args);
- if (err < 0)
- return EXIT_FAILURE;
-
- udev_builtin_add_property(dev, test, "ID_BTRFS_READY", one_zero(err == 0));
- return EXIT_SUCCESS;
-}
-
-const struct udev_builtin udev_builtin_btrfs = {
- .name = "btrfs",
- .cmd = builtin_btrfs,
- .help = "btrfs volume management",
-};
diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c
deleted file mode 100644
index f4a065a97d..0000000000
--- a/src/udev/udev-builtin-hwdb.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2012 Kay Sievers <kay@vrfy.org>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <fnmatch.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "sd-hwdb.h"
-
-#include "alloc-util.h"
-#include "hwdb-util.h"
-#include "string-util.h"
-#include "udev-util.h"
-#include "udev.h"
-
-static sd_hwdb *hwdb;
-
-int udev_builtin_hwdb_lookup(struct udev_device *dev,
- const char *prefix, const char *modalias,
- const char *filter, bool test) {
- _cleanup_free_ char *lookup = NULL;
- const char *key, *value;
- int n = 0;
-
- if (!hwdb)
- return -ENOENT;
-
- if (prefix) {
- lookup = strjoin(prefix, modalias, NULL);
- if (!lookup)
- return -ENOMEM;
- modalias = lookup;
- }
-
- SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value) {
- if (filter && fnmatch(filter, key, FNM_NOESCAPE) != 0)
- continue;
-
- if (udev_builtin_add_property(dev, test, key, value) < 0)
- return -ENOMEM;
- n++;
- }
- return n;
-}
-
-static const char *modalias_usb(struct udev_device *dev, char *s, size_t size) {
- const char *v, *p;
- int vn, pn;
-
- v = udev_device_get_sysattr_value(dev, "idVendor");
- if (!v)
- return NULL;
- p = udev_device_get_sysattr_value(dev, "idProduct");
- if (!p)
- return NULL;
- vn = strtol(v, NULL, 16);
- if (vn <= 0)
- return NULL;
- pn = strtol(p, NULL, 16);
- if (pn <= 0)
- return NULL;
- snprintf(s, size, "usb:v%04Xp%04X*", vn, pn);
- return s;
-}
-
-static int udev_builtin_hwdb_search(struct udev_device *dev, struct udev_device *srcdev,
- const char *subsystem, const char *prefix,
- const char *filter, bool test) {
- struct udev_device *d;
- char s[16];
- bool last = false;
- int r = 0;
-
- assert(dev);
-
- if (!srcdev)
- srcdev = dev;
-
- for (d = srcdev; d && !last; d = udev_device_get_parent(d)) {
- const char *dsubsys;
- const char *modalias = NULL;
-
- dsubsys = udev_device_get_subsystem(d);
- if (!dsubsys)
- continue;
-
- /* look only at devices of a specific subsystem */
- if (subsystem && !streq(dsubsys, subsystem))
- continue;
-
- modalias = udev_device_get_property_value(d, "MODALIAS");
-
- if (streq(dsubsys, "usb") && streq_ptr(udev_device_get_devtype(d), "usb_device")) {
- /* if the usb_device does not have a modalias, compose one */
- if (!modalias)
- modalias = modalias_usb(d, s, sizeof(s));
-
- /* avoid looking at any parent device, they are usually just a USB hub */
- last = true;
- }
-
- if (!modalias)
- continue;
-
- r = udev_builtin_hwdb_lookup(dev, prefix, modalias, filter, test);
- if (r > 0)
- break;
- }
-
- return r;
-}
-
-static int builtin_hwdb(struct udev_device *dev, int argc, char *argv[], bool test) {
- static const struct option options[] = {
- { "filter", required_argument, NULL, 'f' },
- { "device", required_argument, NULL, 'd' },
- { "subsystem", required_argument, NULL, 's' },
- { "lookup-prefix", required_argument, NULL, 'p' },
- {}
- };
- const char *filter = NULL;
- const char *device = NULL;
- const char *subsystem = NULL;
- const char *prefix = NULL;
- _cleanup_udev_device_unref_ struct udev_device *srcdev = NULL;
-
- if (!hwdb)
- return EXIT_FAILURE;
-
- for (;;) {
- int option;
-
- option = getopt_long(argc, argv, "f:d:s:p:", options, NULL);
- if (option == -1)
- break;
-
- switch (option) {
- case 'f':
- filter = optarg;
- break;
-
- case 'd':
- device = optarg;
- break;
-
- case 's':
- subsystem = optarg;
- break;
-
- case 'p':
- prefix = optarg;
- break;
- }
- }
-
- /* query a specific key given as argument */
- if (argv[optind]) {
- if (udev_builtin_hwdb_lookup(dev, prefix, argv[optind], filter, test) > 0)
- return EXIT_SUCCESS;
- return EXIT_FAILURE;
- }
-
- /* read data from another device than the device we will store the data */
- if (device) {
- srcdev = udev_device_new_from_device_id(udev_device_get_udev(dev), device);
- if (!srcdev)
- return EXIT_FAILURE;
- }
-
- if (udev_builtin_hwdb_search(dev, srcdev, subsystem, prefix, filter, test) > 0)
- return EXIT_SUCCESS;
- return EXIT_FAILURE;
-}
-
-/* called at udev startup and reload */
-static int builtin_hwdb_init(struct udev *udev) {
- int r;
-
- if (hwdb)
- return 0;
-
- r = sd_hwdb_new(&hwdb);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-/* called on udev shutdown and reload request */
-static void builtin_hwdb_exit(struct udev *udev) {
- hwdb = sd_hwdb_unref(hwdb);
-}
-
-/* called every couple of seconds during event activity; 'true' if config has changed */
-static bool builtin_hwdb_validate(struct udev *udev) {
- return hwdb_validate(hwdb);
-}
-
-const struct udev_builtin udev_builtin_hwdb = {
- .name = "hwdb",
- .cmd = builtin_hwdb,
- .init = builtin_hwdb_init,
- .exit = builtin_hwdb_exit,
- .validate = builtin_hwdb_validate,
- .help = "Hardware database",
-};
diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c
deleted file mode 100644
index 59b9804dc4..0000000000
--- a/src/udev/udev-builtin-input_id.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * expose input properties via udev
- *
- * Copyright (C) 2009 Martin Pitt <martin.pitt@ubuntu.com>
- * Portions Copyright (C) 2004 David Zeuthen, <david@fubar.dk>
- * Copyright (C) 2011 Kay Sievers <kay@vrfy.org>
- * Copyright (C) 2014 Carlos Garnacho <carlosg@gnome.org>
- * Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <linux/limits.h>
-#include <linux/input.h>
-
-#include "fd-util.h"
-#include "stdio-util.h"
-#include "string-util.h"
-#include "udev.h"
-#include "util.h"
-
-/* we must use this kernel-compatible implementation */
-#define BITS_PER_LONG (sizeof(unsigned long) * 8)
-#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
-#define OFF(x) ((x)%BITS_PER_LONG)
-#define BIT(x) (1UL<<OFF(x))
-#define LONG(x) ((x)/BITS_PER_LONG)
-#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
-
-static inline int abs_size_mm(const struct input_absinfo *absinfo) {
- /* Resolution is defined to be in units/mm for ABS_X/Y */
- return (absinfo->maximum - absinfo->minimum) / absinfo->resolution;
-}
-
-static void extract_info(struct udev_device *dev, const char *devpath, bool test) {
- char width[DECIMAL_STR_MAX(int)], height[DECIMAL_STR_MAX(int)];
- struct input_absinfo xabsinfo = {}, yabsinfo = {};
- _cleanup_close_ int fd = -1;
-
- fd = open(devpath, O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- return;
-
- if (ioctl(fd, EVIOCGABS(ABS_X), &xabsinfo) < 0 ||
- ioctl(fd, EVIOCGABS(ABS_Y), &yabsinfo) < 0)
- return;
-
- if (xabsinfo.resolution <= 0 || yabsinfo.resolution <= 0)
- return;
-
- xsprintf(width, "%d", abs_size_mm(&xabsinfo));
- xsprintf(height, "%d", abs_size_mm(&yabsinfo));
-
- udev_builtin_add_property(dev, test, "ID_INPUT_WIDTH_MM", width);
- udev_builtin_add_property(dev, test, "ID_INPUT_HEIGHT_MM", height);
-}
-
-/*
- * Read a capability attribute and return bitmask.
- * @param dev udev_device
- * @param attr sysfs attribute name (e. g. "capabilities/key")
- * @param bitmask: Output array which has a sizeof of bitmask_size
- */
-static void get_cap_mask(struct udev_device *dev,
- struct udev_device *pdev, const char* attr,
- unsigned long *bitmask, size_t bitmask_size,
- bool test) {
- const char *v;
- char text[4096];
- unsigned i;
- char* word;
- unsigned long val;
-
- v = udev_device_get_sysattr_value(pdev, attr);
- if (!v)
- v = "";
-
- xsprintf(text, "%s", v);
- log_debug("%s raw kernel attribute: %s", attr, text);
-
- memzero(bitmask, bitmask_size);
- i = 0;
- while ((word = strrchr(text, ' ')) != NULL) {
- val = strtoul (word+1, NULL, 16);
- if (i < bitmask_size/sizeof(unsigned long))
- bitmask[i] = val;
- else
- log_debug("ignoring %s block %lX which is larger than maximum size", attr, val);
- *word = '\0';
- ++i;
- }
- val = strtoul (text, NULL, 16);
- if (i < bitmask_size / sizeof(unsigned long))
- bitmask[i] = val;
- else
- log_debug("ignoring %s block %lX which is larger than maximum size", attr, val);
-
- if (test) {
- /* printf pattern with the right unsigned long number of hex chars */
- xsprintf(text, " bit %%4u: %%0%zulX\n",
- 2 * sizeof(unsigned long));
- log_debug("%s decoded bit map:", attr);
- val = bitmask_size / sizeof (unsigned long);
- /* skip over leading zeros */
- while (bitmask[val-1] == 0 && val > 0)
- --val;
- for (i = 0; i < val; ++i) {
- DISABLE_WARNING_FORMAT_NONLITERAL;
- log_debug(text, i * BITS_PER_LONG, bitmask[i]);
- REENABLE_WARNING;
- }
- }
-}
-
-/* pointer devices */
-static bool test_pointers(struct udev_device *dev,
- const unsigned long* bitmask_ev,
- const unsigned long* bitmask_abs,
- const unsigned long* bitmask_key,
- const unsigned long* bitmask_rel,
- const unsigned long* bitmask_props,
- bool test) {
- bool has_abs_coordinates = false;
- bool has_rel_coordinates = false;
- bool has_mt_coordinates = false;
- bool has_joystick_axes_or_buttons = false;
- bool is_direct = false;
- bool has_touch = false;
- bool has_3d_coordinates = false;
- bool has_keys = false;
- bool stylus_or_pen = false;
- bool finger_but_no_pen = false;
- bool has_mouse_button = false;
- bool is_mouse = false;
- bool is_touchpad = false;
- bool is_touchscreen = false;
- bool is_tablet = false;
- bool is_joystick = false;
- bool is_accelerometer = false;
- bool is_pointing_stick= false;
-
- has_keys = test_bit(EV_KEY, bitmask_ev);
- has_abs_coordinates = test_bit(ABS_X, bitmask_abs) && test_bit(ABS_Y, bitmask_abs);
- has_3d_coordinates = has_abs_coordinates && test_bit(ABS_Z, bitmask_abs);
- is_accelerometer = test_bit(INPUT_PROP_ACCELEROMETER, bitmask_props);
-
- if (!has_keys && has_3d_coordinates)
- is_accelerometer = true;
-
- if (is_accelerometer) {
- udev_builtin_add_property(dev, test, "ID_INPUT_ACCELEROMETER", "1");
- return true;
- }
-
- is_pointing_stick = test_bit(INPUT_PROP_POINTING_STICK, bitmask_props);
- stylus_or_pen = test_bit(BTN_STYLUS, bitmask_key) || test_bit(BTN_TOOL_PEN, bitmask_key);
- finger_but_no_pen = test_bit(BTN_TOOL_FINGER, bitmask_key) && !test_bit(BTN_TOOL_PEN, bitmask_key);
- has_mouse_button = test_bit(BTN_LEFT, bitmask_key);
- has_rel_coordinates = test_bit(EV_REL, bitmask_ev) && test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel);
- has_mt_coordinates = test_bit(ABS_MT_POSITION_X, bitmask_abs) && test_bit(ABS_MT_POSITION_Y, bitmask_abs);
-
- /* unset has_mt_coordinates if devices claims to have all abs axis */
- if (has_mt_coordinates && test_bit(ABS_MT_SLOT, bitmask_abs) && test_bit(ABS_MT_SLOT - 1, bitmask_abs))
- has_mt_coordinates = false;
- is_direct = test_bit(INPUT_PROP_DIRECT, bitmask_props);
- has_touch = test_bit(BTN_TOUCH, bitmask_key);
- /* joysticks don't necessarily have buttons; e. g.
- * rudders/pedals are joystick-like, but buttonless; they have
- * other fancy axes */
- has_joystick_axes_or_buttons = test_bit(BTN_TRIGGER, bitmask_key) ||
- test_bit(BTN_A, bitmask_key) ||
- test_bit(BTN_1, bitmask_key) ||
- test_bit(ABS_RX, bitmask_abs) ||
- test_bit(ABS_RY, bitmask_abs) ||
- test_bit(ABS_RZ, bitmask_abs) ||
- test_bit(ABS_THROTTLE, bitmask_abs) ||
- test_bit(ABS_RUDDER, bitmask_abs) ||
- test_bit(ABS_WHEEL, bitmask_abs) ||
- test_bit(ABS_GAS, bitmask_abs) ||
- test_bit(ABS_BRAKE, bitmask_abs);
-
- if (has_abs_coordinates) {
- if (stylus_or_pen)
- is_tablet = true;
- else if (finger_but_no_pen && !is_direct)
- is_touchpad = true;
- else if (has_mouse_button)
- /* This path is taken by VMware's USB mouse, which has
- * absolute axes, but no touch/pressure button. */
- is_mouse = true;
- else if (has_touch || is_direct)
- is_touchscreen = true;
- else if (has_joystick_axes_or_buttons)
- is_joystick = true;
- }
- if (has_mt_coordinates) {
- if (stylus_or_pen)
- is_tablet = true;
- else if (finger_but_no_pen && !is_direct)
- is_touchpad = true;
- else if (has_touch || is_direct)
- is_touchscreen = true;
- }
-
- if (has_rel_coordinates && has_mouse_button)
- is_mouse = true;
-
- if (is_pointing_stick)
- udev_builtin_add_property(dev, test, "ID_INPUT_POINTINGSTICK", "1");
- if (is_mouse)
- udev_builtin_add_property(dev, test, "ID_INPUT_MOUSE", "1");
- if (is_touchpad)
- udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHPAD", "1");
- if (is_touchscreen)
- udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHSCREEN", "1");
- if (is_joystick)
- udev_builtin_add_property(dev, test, "ID_INPUT_JOYSTICK", "1");
- if (is_tablet)
- udev_builtin_add_property(dev, test, "ID_INPUT_TABLET", "1");
-
- return is_tablet || is_mouse || is_touchpad || is_touchscreen || is_joystick || is_pointing_stick;
-}
-
-/* key like devices */
-static bool test_key(struct udev_device *dev,
- const unsigned long* bitmask_ev,
- const unsigned long* bitmask_key,
- bool test) {
- unsigned i;
- unsigned long found;
- unsigned long mask;
- bool ret = false;
-
- /* do we have any KEY_* capability? */
- if (!test_bit(EV_KEY, bitmask_ev)) {
- log_debug("test_key: no EV_KEY capability");
- return false;
- }
-
- /* only consider KEY_* here, not BTN_* */
- found = 0;
- for (i = 0; i < BTN_MISC/BITS_PER_LONG; ++i) {
- found |= bitmask_key[i];
- log_debug("test_key: checking bit block %lu for any keys; found=%i", (unsigned long)i*BITS_PER_LONG, found > 0);
- }
- /* If there are no keys in the lower block, check the higher block */
- if (!found) {
- for (i = KEY_OK; i < BTN_TRIGGER_HAPPY; ++i) {
- if (test_bit(i, bitmask_key)) {
- log_debug("test_key: Found key %x in high block", i);
- found = 1;
- break;
- }
- }
- }
-
- if (found > 0) {
- udev_builtin_add_property(dev, test, "ID_INPUT_KEY", "1");
- ret = true;
- }
-
- /* the first 32 bits are ESC, numbers, and Q to D; if we have all of
- * those, consider it a full keyboard; do not test KEY_RESERVED, though */
- mask = 0xFFFFFFFE;
- if ((bitmask_key[0] & mask) == mask) {
- udev_builtin_add_property(dev, test, "ID_INPUT_KEYBOARD", "1");
- ret = true;
- }
-
- return ret;
-}
-
-static int builtin_input_id(struct udev_device *dev, int argc, char *argv[], bool test) {
- struct udev_device *pdev;
- unsigned long bitmask_ev[NBITS(EV_MAX)];
- unsigned long bitmask_abs[NBITS(ABS_MAX)];
- unsigned long bitmask_key[NBITS(KEY_MAX)];
- unsigned long bitmask_rel[NBITS(REL_MAX)];
- unsigned long bitmask_props[NBITS(INPUT_PROP_MAX)];
- const char *sysname, *devnode;
- bool is_pointer;
- bool is_key;
-
- assert(dev);
-
- /* walk up the parental chain until we find the real input device; the
- * argument is very likely a subdevice of this, like eventN */
- pdev = dev;
- while (pdev != NULL && udev_device_get_sysattr_value(pdev, "capabilities/ev") == NULL)
- pdev = udev_device_get_parent_with_subsystem_devtype(pdev, "input", NULL);
-
- if (pdev) {
- /* Use this as a flag that input devices were detected, so that this
- * program doesn't need to be called more than once per device */
- udev_builtin_add_property(dev, test, "ID_INPUT", "1");
- get_cap_mask(dev, pdev, "capabilities/ev", bitmask_ev, sizeof(bitmask_ev), test);
- get_cap_mask(dev, pdev, "capabilities/abs", bitmask_abs, sizeof(bitmask_abs), test);
- get_cap_mask(dev, pdev, "capabilities/rel", bitmask_rel, sizeof(bitmask_rel), test);
- get_cap_mask(dev, pdev, "capabilities/key", bitmask_key, sizeof(bitmask_key), test);
- get_cap_mask(dev, pdev, "properties", bitmask_props, sizeof(bitmask_props), test);
- is_pointer = test_pointers(dev, bitmask_ev, bitmask_abs,
- bitmask_key, bitmask_rel,
- bitmask_props, test);
- is_key = test_key(dev, bitmask_ev, bitmask_key, test);
- /* Some evdev nodes have only a scrollwheel */
- if (!is_pointer && !is_key && test_bit(EV_REL, bitmask_ev) &&
- (test_bit(REL_WHEEL, bitmask_rel) || test_bit(REL_HWHEEL, bitmask_rel)))
- udev_builtin_add_property(dev, test, "ID_INPUT_KEY", "1");
- }
-
- devnode = udev_device_get_devnode(dev);
- sysname = udev_device_get_sysname(dev);
- if (devnode && sysname && startswith(sysname, "event"))
- extract_info(dev, devnode, test);
-
- return EXIT_SUCCESS;
-}
-
-const struct udev_builtin udev_builtin_input_id = {
- .name = "input_id",
- .cmd = builtin_input_id,
- .help = "Input device properties",
-};
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c
deleted file mode 100644
index aa10beafb0..0000000000
--- a/src/udev/udev-builtin-keyboard.c
+++ /dev/null
@@ -1,277 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2013 Kay Sievers <kay@vrfy.org>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <linux/input.h>
-
-#include "fd-util.h"
-#include "parse-util.h"
-#include "stdio-util.h"
-#include "string-util.h"
-#include "udev.h"
-
-static const struct key *keyboard_lookup_key(const char *str, unsigned len);
-#include "keyboard-keys-from-name.h"
-
-static int install_force_release(struct udev_device *dev, const unsigned *release, unsigned release_count) {
- struct udev_device *atkbd;
- const char *cur;
- char codes[4096];
- char *s;
- size_t l;
- unsigned i;
- int ret;
-
- assert(dev);
- assert(release);
-
- atkbd = udev_device_get_parent_with_subsystem_devtype(dev, "serio", NULL);
- if (!atkbd)
- return -ENODEV;
-
- cur = udev_device_get_sysattr_value(atkbd, "force_release");
- if (!cur)
- return -ENODEV;
-
- s = codes;
- l = sizeof(codes);
-
- /* copy current content */
- l = strpcpy(&s, l, cur);
-
- /* append new codes */
- for (i = 0; i < release_count; i++)
- l = strpcpyf(&s, l, ",%u", release[i]);
-
- log_debug("keyboard: updating force-release list with '%s'", codes);
- ret = udev_device_set_sysattr_value(atkbd, "force_release", codes);
- if (ret < 0)
- log_error_errno(ret, "Error writing force-release attribute: %m");
- return ret;
-}
-
-static void map_keycode(int fd, const char *devnode, int scancode, const char *keycode)
-{
- struct {
- unsigned scan;
- unsigned key;
- } map;
- char *endptr;
- const struct key *k;
- unsigned keycode_num;
-
- /* translate identifier to key code */
- k = keyboard_lookup_key(keycode, strlen(keycode));
- if (k) {
- keycode_num = k->id;
- } else {
- /* check if it's a numeric code already */
- keycode_num = strtoul(keycode, &endptr, 0);
- if (endptr[0] !='\0') {
- log_error("Unknown key identifier '%s'", keycode);
- return;
- }
- }
-
- map.scan = scancode;
- map.key = keycode_num;
-
- log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)",
- map.scan, map.scan, map.key, map.key);
-
- if (ioctl(fd, EVIOCSKEYCODE, &map) < 0)
- log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", devnode, map.scan, map.key);
-}
-
-static inline char* parse_token(const char *current, int32_t *val_out) {
- char *next;
- int32_t val;
-
- if (!current)
- return NULL;
-
- val = strtol(current, &next, 0);
- if (*next && *next != ':')
- return NULL;
-
- if (next != current)
- *val_out = val;
-
- if (*next)
- next++;
-
- return next;
-}
-
-static void override_abs(int fd, const char *devnode,
- unsigned evcode, const char *value) {
- struct input_absinfo absinfo;
- int rc;
- char *next;
-
- rc = ioctl(fd, EVIOCGABS(evcode), &absinfo);
- if (rc < 0) {
- log_error_errno(errno, "Unable to EVIOCGABS device \"%s\"", devnode);
- return;
- }
-
- next = parse_token(value, &absinfo.minimum);
- next = parse_token(next, &absinfo.maximum);
- next = parse_token(next, &absinfo.resolution);
- next = parse_token(next, &absinfo.fuzz);
- next = parse_token(next, &absinfo.flat);
- if (!next) {
- log_error("Unable to parse EV_ABS override '%s' for '%s'", value, devnode);
- return;
- }
-
- log_debug("keyboard: %x overridden with %"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32" for \"%s\"",
- evcode,
- absinfo.minimum, absinfo.maximum, absinfo.resolution, absinfo.fuzz, absinfo.flat,
- devnode);
- rc = ioctl(fd, EVIOCSABS(evcode), &absinfo);
- if (rc < 0)
- log_error_errno(errno, "Unable to EVIOCSABS device \"%s\"", devnode);
-}
-
-static void set_trackpoint_sensitivity(struct udev_device *dev, const char *value)
-{
- struct udev_device *pdev;
- char val_s[DECIMAL_STR_MAX(int)];
- int r, val_i;
-
- assert(dev);
- assert(value);
-
- /* The sensitivity sysfs attr belongs to the serio parent device */
- pdev = udev_device_get_parent_with_subsystem_devtype(dev, "serio", NULL);
- if (!pdev) {
- log_warning("Failed to get serio parent for '%s'", udev_device_get_devnode(dev));
- return;
- }
-
- r = safe_atoi(value, &val_i);
- if (r < 0) {
- log_error("Unable to parse POINTINGSTICK_SENSITIVITY '%s' for '%s'", value, udev_device_get_devnode(dev));
- return;
- }
-
- xsprintf(val_s, "%d", val_i);
-
- r = udev_device_set_sysattr_value(pdev, "sensitivity", val_s);
- if (r < 0)
- log_error_errno(r, "Failed to write 'sensitivity' attribute for '%s': %m", udev_device_get_devnode(pdev));
-}
-
-static int open_device(const char *devnode) {
- int fd;
-
- fd = open(devnode, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
- if (fd < 0)
- return log_error_errno(errno, "Error opening device \"%s\": %m", devnode);
-
- return fd;
-}
-
-static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) {
- struct udev_list_entry *entry;
- unsigned release[1024];
- unsigned release_count = 0;
- _cleanup_close_ int fd = -1;
- const char *node;
-
- node = udev_device_get_devnode(dev);
- if (!node) {
- log_error("No device node for \"%s\"", udev_device_get_syspath(dev));
- return EXIT_FAILURE;
- }
-
- udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) {
- const char *key;
- char *endptr;
-
- key = udev_list_entry_get_name(entry);
- if (startswith(key, "KEYBOARD_KEY_")) {
- const char *keycode;
- unsigned scancode;
-
- /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */
- scancode = strtoul(key + 13, &endptr, 16);
- if (endptr[0] != '\0') {
- log_warning("Unable to parse scan code from \"%s\"", key);
- continue;
- }
-
- keycode = udev_list_entry_get_value(entry);
-
- /* a leading '!' needs a force-release entry */
- if (keycode[0] == '!') {
- keycode++;
-
- release[release_count] = scancode;
- if (release_count < ELEMENTSOF(release)-1)
- release_count++;
-
- if (keycode[0] == '\0')
- continue;
- }
-
- if (fd == -1) {
- fd = open_device(node);
- if (fd < 0)
- return EXIT_FAILURE;
- }
-
- map_keycode(fd, node, scancode, keycode);
- } else if (startswith(key, "EVDEV_ABS_")) {
- unsigned evcode;
-
- /* EVDEV_ABS_<EV_ABS code>=<min>:<max>:<res>:<fuzz>:<flat> */
- evcode = strtoul(key + 10, &endptr, 16);
- if (endptr[0] != '\0') {
- log_warning("Unable to parse EV_ABS code from \"%s\"", key);
- continue;
- }
-
- if (fd == -1) {
- fd = open_device(node);
- if (fd < 0)
- return EXIT_FAILURE;
- }
-
- override_abs(fd, node, evcode, udev_list_entry_get_value(entry));
- } else if (streq(key, "POINTINGSTICK_SENSITIVITY"))
- set_trackpoint_sensitivity(dev, udev_list_entry_get_value(entry));
- }
-
- /* install list of force-release codes */
- if (release_count > 0)
- install_force_release(dev, release, release_count);
-
- return EXIT_SUCCESS;
-}
-
-const struct udev_builtin udev_builtin_keyboard = {
- .name = "keyboard",
- .cmd = builtin_keyboard,
- .help = "Keyboard scan code to key mapping",
-};
diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c
deleted file mode 100644
index 9665f678fd..0000000000
--- a/src/udev/udev-builtin-kmod.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * load kernel modules
- *
- * Copyright (C) 2011-2012 Kay Sievers <kay@vrfy.org>
- * Copyright (C) 2011 ProFUSION embedded systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <libkmod.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "string-util.h"
-#include "udev.h"
-
-static struct kmod_ctx *ctx = NULL;
-
-static int load_module(struct udev *udev, const char *alias) {
- struct kmod_list *list = NULL;
- struct kmod_list *l;
- int err;
-
- err = kmod_module_new_from_lookup(ctx, alias, &list);
- if (err < 0)
- return err;
-
- if (list == NULL)
- log_debug("No module matches '%s'", alias);
-
- kmod_list_foreach(l, list) {
- struct kmod_module *mod = kmod_module_get_module(l);
-
- err = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, NULL);
- if (err == KMOD_PROBE_APPLY_BLACKLIST)
- log_debug("Module '%s' is blacklisted", kmod_module_get_name(mod));
- else if (err == 0)
- log_debug("Inserted '%s'", kmod_module_get_name(mod));
- else
- log_debug("Failed to insert '%s'", kmod_module_get_name(mod));
-
- kmod_module_unref(mod);
- }
-
- kmod_module_unref_list(list);
- return err;
-}
-
-_printf_(6,0) static void udev_kmod_log(void *data, int priority, const char *file, int line, const char *fn, const char *format, va_list args) {
- log_internalv(priority, 0, file, line, fn, format, args);
-}
-
-static int builtin_kmod(struct udev_device *dev, int argc, char *argv[], bool test) {
- struct udev *udev = udev_device_get_udev(dev);
- int i;
-
- if (!ctx)
- return 0;
-
- if (argc < 3 || !streq(argv[1], "load")) {
- log_error("expect: %s load <module>", argv[0]);
- return EXIT_FAILURE;
- }
-
- for (i = 2; argv[i]; i++) {
- log_debug("Execute '%s' '%s'", argv[1], argv[i]);
- load_module(udev, argv[i]);
- }
-
- return EXIT_SUCCESS;
-}
-
-/* called at udev startup and reload */
-static int builtin_kmod_init(struct udev *udev) {
- if (ctx)
- return 0;
-
- ctx = kmod_new(NULL, NULL);
- if (!ctx)
- return -ENOMEM;
-
- log_debug("Load module index");
- kmod_set_log_fn(ctx, udev_kmod_log, udev);
- kmod_load_resources(ctx);
- return 0;
-}
-
-/* called on udev shutdown and reload request */
-static void builtin_kmod_exit(struct udev *udev) {
- log_debug("Unload module index");
- ctx = kmod_unref(ctx);
-}
-
-/* called every couple of seconds during event activity; 'true' if config has changed */
-static bool builtin_kmod_validate(struct udev *udev) {
- log_debug("Validate module index");
- if (!ctx)
- return false;
- return (kmod_validate_resources(ctx) != KMOD_RESOURCES_OK);
-}
-
-const struct udev_builtin udev_builtin_kmod = {
- .name = "kmod",
- .cmd = builtin_kmod,
- .init = builtin_kmod_init,
- .exit = builtin_kmod_exit,
- .validate = builtin_kmod_validate,
- .help = "Kernel module loader",
- .run_once = false,
-};
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
deleted file mode 100644
index fe9d6f4482..0000000000
--- a/src/udev/udev-builtin-net_id.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2012 Kay Sievers <kay@vrfy.org>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/*
- * Predictable network interface device names based on:
- * - firmware/bios-provided index numbers for on-board devices
- * - firmware-provided pci-express hotplug slot index number
- * - physical/geographical location of the hardware
- * - the interface's MAC address
- *
- * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
- *
- * Two character prefixes based on the type of interface:
- * en — Ethernet
- * sl — serial line IP (slip)
- * wl — wlan
- * ww — wwan
- *
- * Type of names:
- * b<number> — BCMA bus core number
- * c<bus_id> — CCW bus group name, without leading zeros [s390]
- * o<index>[n<phys_port_name>|d<dev_port>]
- * — on-board device index number
- * s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
- * — hotplug slot index number
- * x<MAC> — MAC address
- * [P<domain>]p<bus>s<slot>[f<function>][n<phys_port_name>|d<dev_port>]
- * — PCI geographical location
- * [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
- * — USB port number chain
- *
- * All multi-function PCI devices will carry the [f<function>] number in the
- * device name, including the function 0 device.
- *
- * When using PCI geography, The PCI domain is only prepended when it is not 0.
- *
- * For USB devices the full chain of port numbers of hubs is composed. If the
- * name gets longer than the maximum number of 15 characters, the name is not
- * exported.
- * The usual USB configuration == 1 and interface == 0 values are suppressed.
- *
- * PCI Ethernet card with firmware index "1":
- * ID_NET_NAME_ONBOARD=eno1
- * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
- *
- * PCI Ethernet card in hotplug slot with firmware index number:
- * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
- * ID_NET_NAME_MAC=enx000000000466
- * ID_NET_NAME_PATH=enp5s0
- * ID_NET_NAME_SLOT=ens1
- *
- * PCI Ethernet multi-function card with 2 ports:
- * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
- * ID_NET_NAME_MAC=enx78e7d1ea46da
- * ID_NET_NAME_PATH=enp2s0f0
- * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
- * ID_NET_NAME_MAC=enx78e7d1ea46dc
- * ID_NET_NAME_PATH=enp2s0f1
- *
- * PCI wlan card:
- * /sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
- * ID_NET_NAME_MAC=wlx0024d7e31130
- * ID_NET_NAME_PATH=wlp3s0
- *
- * USB built-in 3G modem:
- * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
- * ID_NET_NAME_MAC=wwx028037ec0200
- * ID_NET_NAME_PATH=wwp0s29u1u4i6
- *
- * USB Android phone:
- * /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
- * ID_NET_NAME_MAC=enxd626b3450fb5
- * ID_NET_NAME_PATH=enp0s29u1u2
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <linux/pci_regs.h>
-
-#include "fd-util.h"
-#include "fileio.h"
-#include "stdio-util.h"
-#include "string-util.h"
-#include "udev.h"
-
-#define ONBOARD_INDEX_MAX (16*1024-1)
-
-enum netname_type{
- NET_UNDEF,
- NET_PCI,
- NET_USB,
- NET_BCMA,
- NET_VIRTIO,
- NET_CCWGROUP,
-};
-
-struct netnames {
- enum netname_type type;
-
- uint8_t mac[6];
- bool mac_valid;
-
- struct udev_device *pcidev;
- char pci_slot[IFNAMSIZ];
- char pci_path[IFNAMSIZ];
- char pci_onboard[IFNAMSIZ];
- const char *pci_onboard_label;
-
- char usb_ports[IFNAMSIZ];
- char bcma_core[IFNAMSIZ];
- char ccw_group[IFNAMSIZ];
-};
-
-/* retrieve on-board index number and label from firmware */
-static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
- unsigned dev_port = 0;
- size_t l;
- char *s;
- const char *attr, *port_name;
- int idx;
-
- /* ACPI _DSM — device specific method for naming a PCI or PCI Express device */
- attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
- /* SMBIOS type 41 — Onboard Devices Extended Information */
- if (!attr)
- attr = udev_device_get_sysattr_value(names->pcidev, "index");
- if (!attr)
- return -ENOENT;
-
- idx = strtoul(attr, NULL, 0);
- if (idx <= 0)
- return -EINVAL;
-
- /* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to report for
- * example). Let's define a cut-off where we don't consider the index reliable anymore. We pick some arbitrary
- * cut-off, which is somewhere beyond the realistic number of physical network interface a system might
- * have. Ideally the kernel would already filter his crap for us, but it doesn't currently. */
- if (idx > ONBOARD_INDEX_MAX)
- return -ENOENT;
-
- /* kernel provided port index for multiple ports on a single PCI function */
- attr = udev_device_get_sysattr_value(dev, "dev_port");
- if (attr)
- dev_port = strtol(attr, NULL, 10);
-
- /* kernel provided front panel port name for multiple port PCI device */
- port_name = udev_device_get_sysattr_value(dev, "phys_port_name");
-
- s = names->pci_onboard;
- l = sizeof(names->pci_onboard);
- l = strpcpyf(&s, l, "o%d", idx);
- if (port_name)
- l = strpcpyf(&s, l, "n%s", port_name);
- else if (dev_port > 0)
- l = strpcpyf(&s, l, "d%d", dev_port);
- if (l == 0)
- names->pci_onboard[0] = '\0';
-
- names->pci_onboard_label = udev_device_get_sysattr_value(names->pcidev, "label");
-
- return 0;
-}
-
-/* read the 256 bytes PCI configuration space to check the multi-function bit */
-static bool is_pci_multifunction(struct udev_device *dev) {
- _cleanup_close_ int fd = -1;
- const char *filename;
- uint8_t config[64];
-
- filename = strjoina(udev_device_get_syspath(dev), "/config");
- fd = open(filename, O_RDONLY | O_CLOEXEC);
- if (fd < 0)
- return false;
- if (read(fd, &config, sizeof(config)) != sizeof(config))
- return false;
-
- /* bit 0-6 header type, bit 7 multi/single function device */
- if ((config[PCI_HEADER_TYPE] & 0x80) != 0)
- return true;
-
- return false;
-}
-
-static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
- struct udev *udev = udev_device_get_udev(names->pcidev);
- unsigned domain, bus, slot, func, dev_port = 0;
- size_t l;
- char *s;
- const char *attr, *port_name;
- struct udev_device *pci = NULL;
- char slots[PATH_MAX];
- _cleanup_closedir_ DIR *dir = NULL;
- struct dirent *dent;
- int hotplug_slot = 0, err = 0;
-
- if (sscanf(udev_device_get_sysname(names->pcidev), "%x:%x:%x.%u", &domain, &bus, &slot, &func) != 4)
- return -ENOENT;
-
- /* kernel provided port index for multiple ports on a single PCI function */
- attr = udev_device_get_sysattr_value(dev, "dev_port");
- if (attr)
- dev_port = strtol(attr, NULL, 10);
-
- /* kernel provided front panel port name for multiple port PCI device */
- port_name = udev_device_get_sysattr_value(dev, "phys_port_name");
-
- /* compose a name based on the raw kernel's PCI bus, slot numbers */
- s = names->pci_path;
- l = sizeof(names->pci_path);
- if (domain > 0)
- l = strpcpyf(&s, l, "P%u", domain);
- l = strpcpyf(&s, l, "p%us%u", bus, slot);
- if (func > 0 || is_pci_multifunction(names->pcidev))
- l = strpcpyf(&s, l, "f%u", func);
- if (port_name)
- l = strpcpyf(&s, l, "n%s", port_name);
- else if (dev_port > 0)
- l = strpcpyf(&s, l, "d%u", dev_port);
- if (l == 0)
- names->pci_path[0] = '\0';
-
- /* ACPI _SUN — slot user number */
- pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
- if (!pci) {
- err = -ENOENT;
- goto out;
- }
-
- snprintf(slots, sizeof slots, "%s/slots", udev_device_get_syspath(pci));
- dir = opendir(slots);
- if (!dir) {
- err = -errno;
- goto out;
- }
-
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
- int i;
- char *rest, *address, str[PATH_MAX];
-
- if (dent->d_name[0] == '.')
- continue;
- i = strtol(dent->d_name, &rest, 10);
- if (rest[0] != '\0')
- continue;
- if (i < 1)
- continue;
-
- snprintf(str, sizeof str, "%s/%s/address", slots, dent->d_name);
- if (read_one_line_file(str, &address) >= 0) {
- /* match slot address with device by stripping the function */
- if (strneq(address, udev_device_get_sysname(names->pcidev), strlen(address)))
- hotplug_slot = i;
- free(address);
- }
-
- if (hotplug_slot > 0)
- break;
- }
-
- if (hotplug_slot > 0) {
- s = names->pci_slot;
- l = sizeof(names->pci_slot);
- if (domain > 0)
- l = strpcpyf(&s, l, "P%d", domain);
- l = strpcpyf(&s, l, "s%d", hotplug_slot);
- if (func > 0 || is_pci_multifunction(names->pcidev))
- l = strpcpyf(&s, l, "f%d", func);
- if (port_name)
- l = strpcpyf(&s, l, "n%s", port_name);
- else if (dev_port > 0)
- l = strpcpyf(&s, l, "d%d", dev_port);
- if (l == 0)
- names->pci_slot[0] = '\0';
- }
-out:
- udev_device_unref(pci);
- return err;
-}
-
-static int names_pci(struct udev_device *dev, struct netnames *names) {
- struct udev_device *parent;
-
- assert(dev);
- assert(names);
-
- parent = udev_device_get_parent(dev);
-
- /* there can only ever be one virtio bus per parent device, so we can
- safely ignore any virtio buses. see
- <http://lists.linuxfoundation.org/pipermail/virtualization/2015-August/030331.html> */
- while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent)))
- parent = udev_device_get_parent(parent);
-
- if (!parent)
- return -ENOENT;
-
- /* check if our direct parent is a PCI device with no other bus in-between */
- if (streq_ptr("pci", udev_device_get_subsystem(parent))) {
- names->type = NET_PCI;
- names->pcidev = parent;
- } else {
- names->pcidev = udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL);
- if (!names->pcidev)
- return -ENOENT;
- }
- dev_pci_onboard(dev, names);
- dev_pci_slot(dev, names);
- return 0;
-}
-
-static int names_usb(struct udev_device *dev, struct netnames *names) {
- struct udev_device *usbdev;
- char name[256];
- char *ports;
- char *config;
- char *interf;
- size_t l;
- char *s;
-
- assert(dev);
- assert(names);
-
- usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
- if (!usbdev)
- return -ENOENT;
-
- /* get USB port number chain, configuration, interface */
- strscpy(name, sizeof(name), udev_device_get_sysname(usbdev));
- s = strchr(name, '-');
- if (!s)
- return -EINVAL;
- ports = s+1;
-
- s = strchr(ports, ':');
- if (!s)
- return -EINVAL;
- s[0] = '\0';
- config = s+1;
-
- s = strchr(config, '.');
- if (!s)
- return -EINVAL;
- s[0] = '\0';
- interf = s+1;
-
- /* prefix every port number in the chain with "u" */
- s = ports;
- while ((s = strchr(s, '.')))
- s[0] = 'u';
- s = names->usb_ports;
- l = strpcpyl(&s, sizeof(names->usb_ports), "u", ports, NULL);
-
- /* append USB config number, suppress the common config == 1 */
- if (!streq(config, "1"))
- l = strpcpyl(&s, sizeof(names->usb_ports), "c", config, NULL);
-
- /* append USB interface number, suppress the interface == 0 */
- if (!streq(interf, "0"))
- l = strpcpyl(&s, sizeof(names->usb_ports), "i", interf, NULL);
- if (l == 0)
- return -ENAMETOOLONG;
-
- names->type = NET_USB;
- return 0;
-}
-
-static int names_bcma(struct udev_device *dev, struct netnames *names) {
- struct udev_device *bcmadev;
- unsigned int core;
-
- assert(dev);
- assert(names);
-
- bcmadev = udev_device_get_parent_with_subsystem_devtype(dev, "bcma", NULL);
- if (!bcmadev)
- return -ENOENT;
-
- /* bus num:core num */
- if (sscanf(udev_device_get_sysname(bcmadev), "bcma%*u:%u", &core) != 1)
- return -EINVAL;
- /* suppress the common core == 0 */
- if (core > 0)
- xsprintf(names->bcma_core, "b%u", core);
-
- names->type = NET_BCMA;
- return 0;
-}
-
-static int names_ccw(struct udev_device *dev, struct netnames *names) {
- struct udev_device *cdev;
- const char *bus_id;
- size_t bus_id_len;
- int rc;
-
- assert(dev);
- assert(names);
-
- /* Retrieve the associated CCW device */
- cdev = udev_device_get_parent(dev);
- if (!cdev)
- return -ENOENT;
-
- /* Network devices are always grouped CCW devices */
- if (!streq_ptr("ccwgroup", udev_device_get_subsystem(cdev)))
- return -ENOENT;
-
- /* Retrieve bus-ID of the grouped CCW device. The bus-ID uniquely
- * identifies the network device on the Linux on System z channel
- * subsystem. Note that the bus-ID contains lowercase characters.
- */
- bus_id = udev_device_get_sysname(cdev);
- if (!bus_id)
- return -ENOENT;
-
- /* Check the length of the bus-ID. Rely on that the kernel provides
- * a correct bus-ID; alternatively, improve this check and parse and
- * verify each bus-ID part...
- */
- bus_id_len = strlen(bus_id);
- if (!bus_id_len || bus_id_len < 8 || bus_id_len > 9)
- return -EINVAL;
-
- /* Strip leading zeros from the bus id for aesthetic purposes. This
- * keeps the ccw names stable, yet much shorter in general case of
- * bus_id 0.0.0600 -> 600. This is similar to e.g. how PCI domain is
- * not prepended when it is zero.
- */
- bus_id += strspn(bus_id, ".0");
-
- /* Store the CCW bus-ID for use as network device name */
- rc = snprintf(names->ccw_group, sizeof(names->ccw_group), "c%s", bus_id);
- if (rc >= 0 && rc < (int)sizeof(names->ccw_group))
- names->type = NET_CCWGROUP;
- return 0;
-}
-
-static int names_mac(struct udev_device *dev, struct netnames *names) {
- const char *s;
- unsigned int i;
- unsigned int a1, a2, a3, a4, a5, a6;
-
- /* check for NET_ADDR_PERM, skip random MAC addresses */
- s = udev_device_get_sysattr_value(dev, "addr_assign_type");
- if (!s)
- return EXIT_FAILURE;
- i = strtoul(s, NULL, 0);
- if (i != 0)
- return 0;
-
- s = udev_device_get_sysattr_value(dev, "address");
- if (!s)
- return -ENOENT;
- if (sscanf(s, "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6) != 6)
- return -EINVAL;
-
- /* skip empty MAC addresses */
- if (a1 + a2 + a3 + a4 + a5 + a6 == 0)
- return -EINVAL;
-
- names->mac[0] = a1;
- names->mac[1] = a2;
- names->mac[2] = a3;
- names->mac[3] = a4;
- names->mac[4] = a5;
- names->mac[5] = a6;
- names->mac_valid = true;
- return 0;
-}
-
-/* IEEE Organizationally Unique Identifier vendor string */
-static int ieee_oui(struct udev_device *dev, struct netnames *names, bool test) {
- char str[32];
-
- if (!names->mac_valid)
- return -ENOENT;
- /* skip commonly misused 00:00:00 (Xerox) prefix */
- if (memcmp(names->mac, "\0\0\0", 3) == 0)
- return -EINVAL;
- xsprintf(str, "OUI:%02X%02X%02X%02X%02X%02X", names->mac[0],
- names->mac[1], names->mac[2], names->mac[3], names->mac[4],
- names->mac[5]);
- udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test);
- return 0;
-}
-
-static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool test) {
- const char *s;
- const char *p;
- unsigned int i;
- const char *devtype;
- const char *prefix = "en";
- struct netnames names = {};
- int err;
-
- /* handle only ARPHRD_ETHER and ARPHRD_SLIP devices */
- s = udev_device_get_sysattr_value(dev, "type");
- if (!s)
- return EXIT_FAILURE;
- i = strtoul(s, NULL, 0);
- switch (i) {
- case ARPHRD_ETHER:
- prefix = "en";
- break;
- case ARPHRD_SLIP:
- prefix = "sl";
- break;
- default:
- return 0;
- }
-
- /* skip stacked devices, like VLANs, ... */
- s = udev_device_get_sysattr_value(dev, "ifindex");
- if (!s)
- return EXIT_FAILURE;
- p = udev_device_get_sysattr_value(dev, "iflink");
- if (!p)
- return EXIT_FAILURE;
- if (!streq(s, p))
- return 0;
-
- devtype = udev_device_get_devtype(dev);
- if (devtype) {
- if (streq("wlan", devtype))
- prefix = "wl";
- else if (streq("wwan", devtype))
- prefix = "ww";
- }
-
- err = names_mac(dev, &names);
- if (err >= 0 && names.mac_valid) {
- char str[IFNAMSIZ];
-
- xsprintf(str, "%sx%02x%02x%02x%02x%02x%02x", prefix,
- names.mac[0], names.mac[1], names.mac[2],
- names.mac[3], names.mac[4], names.mac[5]);
- udev_builtin_add_property(dev, test, "ID_NET_NAME_MAC", str);
-
- ieee_oui(dev, &names, test);
- }
-
- /* get path names for Linux on System z network devices */
- err = names_ccw(dev, &names);
- if (err >= 0 && names.type == NET_CCWGROUP) {
- char str[IFNAMSIZ];
-
- if (snprintf(str, sizeof(str), "%s%s", prefix, names.ccw_group) < (int)sizeof(str))
- udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
- goto out;
- }
-
- /* get PCI based path names, we compose only PCI based paths */
- err = names_pci(dev, &names);
- if (err < 0)
- goto out;
-
- /* plain PCI device */
- if (names.type == NET_PCI) {
- char str[IFNAMSIZ];
-
- if (names.pci_onboard[0])
- if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard) < (int)sizeof(str))
- udev_builtin_add_property(dev, test, "ID_NET_NAME_ONBOARD", str);
-
- if (names.pci_onboard_label)
- if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_onboard_label) < (int)sizeof(str))
- udev_builtin_add_property(dev, test, "ID_NET_LABEL_ONBOARD", str);
-
- if (names.pci_path[0])
- if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_path) < (int)sizeof(str))
- udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
-
- if (names.pci_slot[0])
- if (snprintf(str, sizeof(str), "%s%s", prefix, names.pci_slot) < (int)sizeof(str))
- udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
- goto out;
- }
-
- /* USB device */
- err = names_usb(dev, &names);
- if (err >= 0 && names.type == NET_USB) {
- char str[IFNAMSIZ];
-
- if (names.pci_path[0])
- if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.usb_ports) < (int)sizeof(str))
- udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
-
- if (names.pci_slot[0])
- if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.usb_ports) < (int)sizeof(str))
- udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
- goto out;
- }
-
- /* Broadcom bus */
- err = names_bcma(dev, &names);
- if (err >= 0 && names.type == NET_BCMA) {
- char str[IFNAMSIZ];
-
- if (names.pci_path[0])
- if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_path, names.bcma_core) < (int)sizeof(str))
- udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
-
- if (names.pci_slot[0])
- if (snprintf(str, sizeof(str), "%s%s%s", prefix, names.pci_slot, names.bcma_core) < (int)sizeof(str))
- udev_builtin_add_property(dev, test, "ID_NET_NAME_SLOT", str);
- goto out;
- }
-out:
- return EXIT_SUCCESS;
-}
-
-const struct udev_builtin udev_builtin_net_id = {
- .name = "net_id",
- .cmd = builtin_net_id,
- .help = "Network device properties",
-};
diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c
deleted file mode 100644
index 8e47775135..0000000000
--- a/src/udev/udev-builtin-net_setup_link.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2013 Tom Gundersen
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "alloc-util.h"
-#include "link-config.h"
-#include "log.h"
-#include "udev.h"
-
-static link_config_ctx *ctx = NULL;
-
-static int builtin_net_setup_link(struct udev_device *dev, int argc, char **argv, bool test) {
- _cleanup_free_ char *driver = NULL;
- const char *name = NULL;
- link_config *link;
- int r;
-
- if (argc > 1) {
- log_error("This program takes no arguments.");
- return EXIT_FAILURE;
- }
-
- r = link_get_driver(ctx, dev, &driver);
- if (r >= 0)
- udev_builtin_add_property(dev, test, "ID_NET_DRIVER", driver);
-
- r = link_config_get(ctx, dev, &link);
- if (r < 0) {
- if (r == -ENOENT) {
- log_debug("No matching link configuration found.");
- return EXIT_SUCCESS;
- } else {
- log_error_errno(r, "Could not get link config: %m");
- return EXIT_FAILURE;
- }
- }
-
- r = link_config_apply(ctx, link, dev, &name);
- if (r < 0) {
- log_error_errno(r, "Could not apply link config to %s: %m", udev_device_get_sysname(dev));
- return EXIT_FAILURE;
- }
-
- udev_builtin_add_property(dev, test, "ID_NET_LINK_FILE", link->filename);
-
- if (name)
- udev_builtin_add_property(dev, test, "ID_NET_NAME", name);
-
- return EXIT_SUCCESS;
-}
-
-static int builtin_net_setup_link_init(struct udev *udev) {
- int r;
-
- if (ctx)
- return 0;
-
- r = link_config_ctx_new(&ctx);
- if (r < 0)
- return r;
-
- r = link_config_load(ctx);
- if (r < 0)
- return r;
-
- log_debug("Created link configuration context.");
- return 0;
-}
-
-static void builtin_net_setup_link_exit(struct udev *udev) {
- link_config_ctx_free(ctx);
- ctx = NULL;
- log_debug("Unloaded link configuration context.");
-}
-
-static bool builtin_net_setup_link_validate(struct udev *udev) {
- log_debug("Check if link configuration needs reloading.");
- if (!ctx)
- return false;
-
- return link_config_should_reload(ctx);
-}
-
-const struct udev_builtin udev_builtin_net_setup_link = {
- .name = "net_setup_link",
- .cmd = builtin_net_setup_link,
- .init = builtin_net_setup_link_init,
- .exit = builtin_net_setup_link_exit,
- .validate = builtin_net_setup_link_validate,
- .help = "Configure network link",
- .run_once = false,
-};
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
deleted file mode 100644
index 1825ee75a7..0000000000
--- a/src/udev/udev-builtin-path_id.c
+++ /dev/null
@@ -1,770 +0,0 @@
-/*
- * compose persistent device path
- *
- * Copyright (C) 2009-2011 Kay Sievers <kay@vrfy.org>
- *
- * Logic based on Hannes Reinecke's shell script.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "string-util.h"
-#include "udev.h"
-
-_printf_(2,3)
-static int path_prepend(char **path, const char *fmt, ...) {
- va_list va;
- char *pre;
- int err = 0;
-
- va_start(va, fmt);
- err = vasprintf(&pre, fmt, va);
- va_end(va);
- if (err < 0)
- goto out;
-
- if (*path != NULL) {
- char *new;
-
- err = asprintf(&new, "%s-%s", pre, *path);
- free(pre);
- if (err < 0)
- goto out;
- free(*path);
- *path = new;
- } else {
- *path = pre;
- }
-out:
- return err;
-}
-
-/*
-** Linux only supports 32 bit luns.
-** See drivers/scsi/scsi_scan.c::scsilun_to_int() for more details.
-*/
-static int format_lun_number(struct udev_device *dev, char **path) {
- unsigned long lun = strtoul(udev_device_get_sysnum(dev), NULL, 10);
-
- /* address method 0, peripheral device addressing with bus id of zero */
- if (lun < 256)
- return path_prepend(path, "lun-%lu", lun);
- /* handle all other lun addressing methods by using a variant of the original lun format */
- return path_prepend(path, "lun-0x%04lx%04lx00000000", lun & 0xffff, (lun >> 16) & 0xffff);
-}
-
-static struct udev_device *skip_subsystem(struct udev_device *dev, const char *subsys) {
- struct udev_device *parent = dev;
-
- assert(dev);
- assert(subsys);
-
- while (parent != NULL) {
- const char *subsystem;
-
- subsystem = udev_device_get_subsystem(parent);
- if (subsystem == NULL || !streq(subsystem, subsys))
- break;
- dev = parent;
- parent = udev_device_get_parent(parent);
- }
- return dev;
-}
-
-static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) {
- struct udev *udev = udev_device_get_udev(parent);
- struct udev_device *targetdev;
- struct udev_device *fcdev = NULL;
- const char *port;
- char *lun = NULL;
-
- assert(parent);
- assert(path);
-
- targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
- if (targetdev == NULL)
- return NULL;
-
- fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev));
- if (fcdev == NULL)
- return NULL;
- port = udev_device_get_sysattr_value(fcdev, "port_name");
- if (port == NULL) {
- parent = NULL;
- goto out;
- }
-
- format_lun_number(parent, &lun);
- path_prepend(path, "fc-%s-%s", port, lun);
- free(lun);
-out:
- udev_device_unref(fcdev);
- return parent;
-}
-
-static struct udev_device *handle_scsi_sas_wide_port(struct udev_device *parent, char **path) {
- struct udev *udev = udev_device_get_udev(parent);
- struct udev_device *targetdev;
- struct udev_device *target_parent;
- struct udev_device *sasdev;
- const char *sas_address;
- char *lun = NULL;
-
- assert(parent);
- assert(path);
-
- targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
- if (targetdev == NULL)
- return NULL;
-
- target_parent = udev_device_get_parent(targetdev);
- if (target_parent == NULL)
- return NULL;
-
- sasdev = udev_device_new_from_subsystem_sysname(udev, "sas_device",
- udev_device_get_sysname(target_parent));
- if (sasdev == NULL)
- return NULL;
-
- sas_address = udev_device_get_sysattr_value(sasdev, "sas_address");
- if (sas_address == NULL) {
- parent = NULL;
- goto out;
- }
-
- format_lun_number(parent, &lun);
- path_prepend(path, "sas-%s-%s", sas_address, lun);
- free(lun);
-out:
- udev_device_unref(sasdev);
- return parent;
-}
-
-static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **path)
-{
- struct udev *udev = udev_device_get_udev(parent);
- struct udev_device *targetdev;
- struct udev_device *target_parent;
- struct udev_device *port;
- struct udev_device *expander;
- struct udev_device *target_sasdev = NULL;
- struct udev_device *expander_sasdev = NULL;
- struct udev_device *port_sasdev = NULL;
- const char *sas_address = NULL;
- const char *phy_id;
- const char *phy_count;
- char *lun = NULL;
-
- assert(parent);
- assert(path);
-
- targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
- if (targetdev == NULL)
- return NULL;
-
- target_parent = udev_device_get_parent(targetdev);
- if (target_parent == NULL)
- return NULL;
-
- /* Get sas device */
- target_sasdev = udev_device_new_from_subsystem_sysname(udev,
- "sas_device", udev_device_get_sysname(target_parent));
- if (target_sasdev == NULL)
- return NULL;
-
- /* The next parent is sas port */
- port = udev_device_get_parent(target_parent);
- if (port == NULL) {
- parent = NULL;
- goto out;
- }
-
- /* Get port device */
- port_sasdev = udev_device_new_from_subsystem_sysname(udev,
- "sas_port", udev_device_get_sysname(port));
-
- phy_count = udev_device_get_sysattr_value(port_sasdev, "num_phys");
- if (phy_count == NULL) {
- parent = NULL;
- goto out;
- }
-
- /* Check if we are simple disk */
- if (strncmp(phy_count, "1", 2) != 0) {
- parent = handle_scsi_sas_wide_port(parent, path);
- goto out;
- }
-
- /* Get connected phy */
- phy_id = udev_device_get_sysattr_value(target_sasdev, "phy_identifier");
- if (phy_id == NULL) {
- parent = NULL;
- goto out;
- }
-
- /* The port's parent is either hba or expander */
- expander = udev_device_get_parent(port);
- if (expander == NULL) {
- parent = NULL;
- goto out;
- }
-
- /* Get expander device */
- expander_sasdev = udev_device_new_from_subsystem_sysname(udev,
- "sas_device", udev_device_get_sysname(expander));
- if (expander_sasdev != NULL) {
- /* Get expander's address */
- sas_address = udev_device_get_sysattr_value(expander_sasdev,
- "sas_address");
- if (sas_address == NULL) {
- parent = NULL;
- goto out;
- }
- }
-
- format_lun_number(parent, &lun);
- if (sas_address)
- path_prepend(path, "sas-exp%s-phy%s-%s", sas_address, phy_id, lun);
- else
- path_prepend(path, "sas-phy%s-%s", phy_id, lun);
-
- free(lun);
-out:
- udev_device_unref(target_sasdev);
- udev_device_unref(expander_sasdev);
- udev_device_unref(port_sasdev);
- return parent;
-}
-
-static struct udev_device *handle_scsi_iscsi(struct udev_device *parent, char **path) {
- struct udev *udev = udev_device_get_udev(parent);
- struct udev_device *transportdev;
- struct udev_device *sessiondev = NULL;
- const char *target;
- char *connname;
- struct udev_device *conndev = NULL;
- const char *addr;
- const char *port;
- char *lun = NULL;
-
- assert(parent);
- assert(path);
-
- /* find iscsi session */
- transportdev = parent;
- for (;;) {
- transportdev = udev_device_get_parent(transportdev);
- if (transportdev == NULL)
- return NULL;
- if (startswith(udev_device_get_sysname(transportdev), "session"))
- break;
- }
-
- /* find iscsi session device */
- sessiondev = udev_device_new_from_subsystem_sysname(udev, "iscsi_session", udev_device_get_sysname(transportdev));
- if (sessiondev == NULL)
- return NULL;
- target = udev_device_get_sysattr_value(sessiondev, "targetname");
- if (target == NULL) {
- parent = NULL;
- goto out;
- }
-
- if (asprintf(&connname, "connection%s:0", udev_device_get_sysnum(transportdev)) < 0) {
- parent = NULL;
- goto out;
- }
- conndev = udev_device_new_from_subsystem_sysname(udev, "iscsi_connection", connname);
- free(connname);
- if (conndev == NULL) {
- parent = NULL;
- goto out;
- }
- addr = udev_device_get_sysattr_value(conndev, "persistent_address");
- port = udev_device_get_sysattr_value(conndev, "persistent_port");
- if (addr == NULL || port == NULL) {
- parent = NULL;
- goto out;
- }
-
- format_lun_number(parent, &lun);
- path_prepend(path, "ip-%s:%s-iscsi-%s-%s", addr, port, target, lun);
- free(lun);
-out:
- udev_device_unref(sessiondev);
- udev_device_unref(conndev);
- return parent;
-}
-
-static struct udev_device *handle_scsi_ata(struct udev_device *parent, char **path) {
- struct udev *udev = udev_device_get_udev(parent);
- struct udev_device *targetdev;
- struct udev_device *target_parent;
- struct udev_device *atadev;
- const char *port_no;
-
- assert(parent);
- assert(path);
-
- targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host");
- if (!targetdev)
- return NULL;
-
- target_parent = udev_device_get_parent(targetdev);
- if (!target_parent)
- return NULL;
-
- atadev = udev_device_new_from_subsystem_sysname(udev, "ata_port", udev_device_get_sysname(target_parent));
- if (!atadev)
- return NULL;
-
- port_no = udev_device_get_sysattr_value(atadev, "port_no");
- if (!port_no) {
- parent = NULL;
- goto out;
- }
- path_prepend(path, "ata-%s", port_no);
-out:
- udev_device_unref(atadev);
- return parent;
-}
-
-static struct udev_device *handle_scsi_default(struct udev_device *parent, char **path) {
- struct udev_device *hostdev;
- int host, bus, target, lun;
- const char *name;
- char *base;
- char *pos;
- DIR *dir;
- struct dirent *dent;
- int basenum;
-
- assert(parent);
- assert(path);
-
- hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host");
- if (hostdev == NULL)
- return NULL;
-
- name = udev_device_get_sysname(parent);
- if (sscanf(name, "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4)
- return NULL;
-
- /*
- * Rebase host offset to get the local relative number
- *
- * Note: This is by definition racy, unreliable and too simple.
- * Please do not copy this model anywhere. It's just a left-over
- * from the time we had no idea how things should look like in
- * the end.
- *
- * Making assumptions about a global in-kernel counter and use
- * that to calculate a local offset is a very broken concept. It
- * can only work as long as things are in strict order.
- *
- * The kernel needs to export the instance/port number of a
- * controller directly, without the need for rebase magic like
- * this. Manual driver unbind/bind, parallel hotplug/unplug will
- * get into the way of this "I hope it works" logic.
- */
- basenum = -1;
- base = strdup(udev_device_get_syspath(hostdev));
- if (base == NULL)
- return NULL;
- pos = strrchr(base, '/');
- if (pos == NULL) {
- parent = NULL;
- goto out;
- }
- pos[0] = '\0';
- dir = opendir(base);
- if (dir == NULL) {
- parent = NULL;
- goto out;
- }
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
- char *rest;
- int i;
-
- if (dent->d_name[0] == '.')
- continue;
- if (dent->d_type != DT_DIR && dent->d_type != DT_LNK)
- continue;
- if (!startswith(dent->d_name, "host"))
- continue;
- i = strtoul(&dent->d_name[4], &rest, 10);
- if (rest[0] != '\0')
- continue;
- /*
- * find the smallest number; the host really needs to export its
- * own instance number per parent device; relying on the global host
- * enumeration and plainly rebasing the numbers sounds unreliable
- */
- if (basenum == -1 || i < basenum)
- basenum = i;
- }
- closedir(dir);
- if (basenum == -1) {
- parent = NULL;
- goto out;
- }
- host -= basenum;
-
- path_prepend(path, "scsi-%u:%u:%u:%u", host, bus, target, lun);
-out:
- free(base);
- return hostdev;
-}
-
-static struct udev_device *handle_scsi_hyperv(struct udev_device *parent, char **path) {
- struct udev_device *hostdev;
- struct udev_device *vmbusdev;
- const char *guid_str;
- char *lun = NULL;
- char guid[38];
- size_t i, k;
-
- assert(parent);
- assert(path);
-
- hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host");
- if (!hostdev)
- return NULL;
-
- vmbusdev = udev_device_get_parent(hostdev);
- if (!vmbusdev)
- return NULL;
-
- guid_str = udev_device_get_sysattr_value(vmbusdev, "device_id");
- if (!guid_str)
- return NULL;
-
- if (strlen(guid_str) < 37 || guid_str[0] != '{' || guid_str[36] != '}')
- return NULL;
-
- for (i = 1, k = 0; i < 36; i++) {
- if (guid_str[i] == '-')
- continue;
- guid[k++] = guid_str[i];
- }
- guid[k] = '\0';
-
- format_lun_number(parent, &lun);
- path_prepend(path, "vmbus-%s-%s", guid, lun);
- free(lun);
- return parent;
-}
-
-static struct udev_device *handle_scsi(struct udev_device *parent, char **path, bool *supported_parent) {
- const char *devtype;
- const char *name;
- const char *id;
-
- devtype = udev_device_get_devtype(parent);
- if (devtype == NULL || !streq(devtype, "scsi_device"))
- return parent;
-
- /* firewire */
- id = udev_device_get_sysattr_value(parent, "ieee1394_id");
- if (id != NULL) {
- parent = skip_subsystem(parent, "scsi");
- path_prepend(path, "ieee1394-0x%s", id);
- *supported_parent = true;
- goto out;
- }
-
- /* scsi sysfs does not have a "subsystem" for the transport */
- name = udev_device_get_syspath(parent);
-
- if (strstr(name, "/rport-") != NULL) {
- parent = handle_scsi_fibre_channel(parent, path);
- *supported_parent = true;
- goto out;
- }
-
- if (strstr(name, "/end_device-") != NULL) {
- parent = handle_scsi_sas(parent, path);
- *supported_parent = true;
- goto out;
- }
-
- if (strstr(name, "/session") != NULL) {
- parent = handle_scsi_iscsi(parent, path);
- *supported_parent = true;
- goto out;
- }
-
- if (strstr(name, "/ata") != NULL) {
- parent = handle_scsi_ata(parent, path);
- goto out;
- }
-
- if (strstr(name, "/vmbus_") != NULL) {
- parent = handle_scsi_hyperv(parent, path);
- goto out;
- }
-
- parent = handle_scsi_default(parent, path);
-out:
- return parent;
-}
-
-static struct udev_device *handle_cciss(struct udev_device *parent, char **path) {
- const char *str;
- unsigned int controller, disk;
-
- str = udev_device_get_sysname(parent);
- if (sscanf(str, "c%ud%u%*s", &controller, &disk) != 2)
- return NULL;
-
- path_prepend(path, "cciss-disk%u", disk);
- parent = skip_subsystem(parent, "cciss");
- return parent;
-}
-
-static void handle_scsi_tape(struct udev_device *dev, char **path) {
- const char *name;
-
- /* must be the last device in the syspath */
- if (*path != NULL)
- return;
-
- name = udev_device_get_sysname(dev);
- if (startswith(name, "nst") && strchr("lma", name[3]) != NULL)
- path_prepend(path, "nst%c", name[3]);
- else if (startswith(name, "st") && strchr("lma", name[2]) != NULL)
- path_prepend(path, "st%c", name[2]);
-}
-
-static struct udev_device *handle_usb(struct udev_device *parent, char **path) {
- const char *devtype;
- const char *str;
- const char *port;
-
- devtype = udev_device_get_devtype(parent);
- if (devtype == NULL)
- return parent;
- if (!streq(devtype, "usb_interface") && !streq(devtype, "usb_device"))
- return parent;
-
- str = udev_device_get_sysname(parent);
- port = strchr(str, '-');
- if (port == NULL)
- return parent;
- port++;
-
- parent = skip_subsystem(parent, "usb");
- path_prepend(path, "usb-0:%s", port);
- return parent;
-}
-
-static struct udev_device *handle_bcma(struct udev_device *parent, char **path) {
- const char *sysname;
- unsigned int core;
-
- sysname = udev_device_get_sysname(parent);
- if (sscanf(sysname, "bcma%*u:%u", &core) != 1)
- return NULL;
-
- path_prepend(path, "bcma-%u", core);
- return parent;
-}
-
-/* Handle devices of AP bus in System z platform. */
-static struct udev_device *handle_ap(struct udev_device *parent, char **path) {
- const char *type, *func;
-
- assert(parent);
- assert(path);
-
- type = udev_device_get_sysattr_value(parent, "type");
- func = udev_device_get_sysattr_value(parent, "ap_functions");
-
- if (type != NULL && func != NULL) {
- path_prepend(path, "ap-%s-%s", type, func);
- goto out;
- }
- path_prepend(path, "ap-%s", udev_device_get_sysname(parent));
-out:
- parent = skip_subsystem(parent, "ap");
- return parent;
-}
-
-static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool test) {
- struct udev_device *parent;
- char *path = NULL;
- bool supported_transport = false;
- bool supported_parent = false;
-
- assert(dev);
-
- /* walk up the chain of devices and compose path */
- parent = dev;
- while (parent != NULL) {
- const char *subsys;
-
- subsys = udev_device_get_subsystem(parent);
- if (subsys == NULL) {
- ;
- } else if (streq(subsys, "scsi_tape")) {
- handle_scsi_tape(parent, &path);
- } else if (streq(subsys, "scsi")) {
- parent = handle_scsi(parent, &path, &supported_parent);
- supported_transport = true;
- } else if (streq(subsys, "cciss")) {
- parent = handle_cciss(parent, &path);
- supported_transport = true;
- } else if (streq(subsys, "usb")) {
- parent = handle_usb(parent, &path);
- supported_transport = true;
- } else if (streq(subsys, "bcma")) {
- parent = handle_bcma(parent, &path);
- supported_transport = true;
- } else if (streq(subsys, "serio")) {
- path_prepend(&path, "serio-%s", udev_device_get_sysnum(parent));
- parent = skip_subsystem(parent, "serio");
- } else if (streq(subsys, "pci")) {
- path_prepend(&path, "pci-%s", udev_device_get_sysname(parent));
- parent = skip_subsystem(parent, "pci");
- supported_parent = true;
- } else if (streq(subsys, "platform")) {
- path_prepend(&path, "platform-%s", udev_device_get_sysname(parent));
- parent = skip_subsystem(parent, "platform");
- supported_transport = true;
- supported_parent = true;
- } else if (streq(subsys, "acpi")) {
- path_prepend(&path, "acpi-%s", udev_device_get_sysname(parent));
- parent = skip_subsystem(parent, "acpi");
- supported_parent = true;
- } else if (streq(subsys, "xen")) {
- path_prepend(&path, "xen-%s", udev_device_get_sysname(parent));
- parent = skip_subsystem(parent, "xen");
- supported_parent = true;
- } else if (streq(subsys, "virtio")) {
- while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent)))
- parent = udev_device_get_parent(parent);
- path_prepend(&path, "virtio-pci-%s", udev_device_get_sysname(parent));
- supported_transport = true;
- supported_parent = true;
- } else if (streq(subsys, "scm")) {
- path_prepend(&path, "scm-%s", udev_device_get_sysname(parent));
- parent = skip_subsystem(parent, "scm");
- supported_transport = true;
- supported_parent = true;
- } else if (streq(subsys, "ccw")) {
- path_prepend(&path, "ccw-%s", udev_device_get_sysname(parent));
- parent = skip_subsystem(parent, "ccw");
- supported_transport = true;
- supported_parent = true;
- } else if (streq(subsys, "ccwgroup")) {
- path_prepend(&path, "ccwgroup-%s", udev_device_get_sysname(parent));
- parent = skip_subsystem(parent, "ccwgroup");
- supported_transport = true;
- supported_parent = true;
- } else if (streq(subsys, "ap")) {
- parent = handle_ap(parent, &path);
- supported_transport = true;
- supported_parent = true;
- } else if (streq(subsys, "iucv")) {
- path_prepend(&path, "iucv-%s", udev_device_get_sysname(parent));
- parent = skip_subsystem(parent, "iucv");
- supported_transport = true;
- supported_parent = true;
- } else if (streq(subsys, "nvme")) {
- const char *nsid = udev_device_get_sysattr_value(dev, "nsid");
-
- if (nsid) {
- path_prepend(&path, "nvme-%s", nsid);
- parent = skip_subsystem(parent, "nvme");
- supported_parent = true;
- supported_transport = true;
- }
- }
-
- if (parent)
- parent = udev_device_get_parent(parent);
- }
-
- /*
- * Do not return devices with an unknown parent device type. They
- * might produce conflicting IDs if the parent does not provide a
- * unique and predictable name.
- */
- if (!supported_parent)
- path = mfree(path);
-
- /*
- * Do not return block devices without a well-known transport. Some
- * devices do not expose their buses and do not provide a unique
- * and predictable name that way.
- */
- if (streq_ptr(udev_device_get_subsystem(dev), "block") && !supported_transport)
- path = mfree(path);
-
- if (path != NULL) {
- char tag[UTIL_NAME_SIZE];
- size_t i;
- const char *p;
-
- /* compose valid udev tag name */
- for (p = path, i = 0; *p; p++) {
- if ((*p >= '0' && *p <= '9') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= 'a' && *p <= 'z') ||
- *p == '-') {
- tag[i++] = *p;
- continue;
- }
-
- /* skip all leading '_' */
- if (i == 0)
- continue;
-
- /* avoid second '_' */
- if (tag[i-1] == '_')
- continue;
-
- tag[i++] = '_';
- }
- /* strip trailing '_' */
- while (i > 0 && tag[i-1] == '_')
- i--;
- tag[i] = '\0';
-
- udev_builtin_add_property(dev, test, "ID_PATH", path);
- udev_builtin_add_property(dev, test, "ID_PATH_TAG", tag);
- free(path);
- return EXIT_SUCCESS;
- }
- return EXIT_FAILURE;
-}
-
-const struct udev_builtin udev_builtin_path_id = {
- .name = "path_id",
- .cmd = builtin_path_id,
- .help = "Compose persistent device path",
- .run_once = true,
-};
diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c
deleted file mode 100644
index 3ebe36f043..0000000000
--- a/src/udev/udev-builtin-uaccess.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * manage device node user ACL
- *
- * Copyright 2010-2012 Kay Sievers <kay@vrfy.org>
- * Copyright 2010 Lennart Poettering
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "sd-login.h"
-
-#include "login-util.h"
-#include "logind-acl.h"
-#include "udev.h"
-#include "util.h"
-
-static int builtin_uaccess(struct udev_device *dev, int argc, char *argv[], bool test) {
- int r;
- const char *path = NULL, *seat;
- bool changed_acl = false;
- uid_t uid;
-
- umask(0022);
-
- /* don't muck around with ACLs when the system is not running systemd */
- if (!logind_running())
- return 0;
-
- path = udev_device_get_devnode(dev);
- seat = udev_device_get_property_value(dev, "ID_SEAT");
- if (!seat)
- seat = "seat0";
-
- r = sd_seat_get_active(seat, NULL, &uid);
- if (r == -ENXIO || r == -ENODATA) {
- /* No active session on this seat */
- r = 0;
- goto finish;
- } else if (r < 0) {
- log_error("Failed to determine active user on seat %s.", seat);
- goto finish;
- }
-
- r = devnode_acl(path, true, false, 0, true, uid);
- if (r < 0) {
- log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL on %s: %m", path);
- goto finish;
- }
-
- changed_acl = true;
- r = 0;
-
-finish:
- if (path && !changed_acl) {
- int k;
-
- /* Better be safe than sorry and reset ACL */
- k = devnode_acl(path, true, false, 0, false, 0);
- if (k < 0) {
- log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, k, "Failed to apply ACL on %s: %m", path);
- if (r >= 0)
- r = k;
- }
- }
-
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
-
-const struct udev_builtin udev_builtin_uaccess = {
- .name = "uaccess",
- .cmd = builtin_uaccess,
- .help = "Manage device node user ACL",
-};
diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c
deleted file mode 100644
index 587649eff0..0000000000
--- a/src/udev/udev-builtin-usb_id.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * USB device properties and persistent device path
- *
- * Copyright (c) 2005 SUSE Linux Products GmbH, Germany
- * Author: Hannes Reinecke <hare@suse.de>
- *
- * Copyright (C) 2005-2011 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "fd-util.h"
-#include "string-util.h"
-#include "udev.h"
-
-static void set_usb_iftype(char *to, int if_class_num, size_t len) {
- const char *type = "generic";
-
- switch (if_class_num) {
- case 1:
- type = "audio";
- break;
- case 2: /* CDC-Control */
- break;
- case 3:
- type = "hid";
- break;
- case 5: /* Physical */
- break;
- case 6:
- type = "media";
- break;
- case 7:
- type = "printer";
- break;
- case 8:
- type = "storage";
- break;
- case 9:
- type = "hub";
- break;
- case 0x0a: /* CDC-Data */
- break;
- case 0x0b: /* Chip/Smart Card */
- break;
- case 0x0d: /* Content Security */
- break;
- case 0x0e:
- type = "video";
- break;
- case 0xdc: /* Diagnostic Device */
- break;
- case 0xe0: /* Wireless Controller */
- break;
- case 0xfe: /* Application-specific */
- break;
- case 0xff: /* Vendor-specific */
- break;
- default:
- break;
- }
- strncpy(to, type, len);
- to[len-1] = '\0';
-}
-
-static int set_usb_mass_storage_ifsubtype(char *to, const char *from, size_t len) {
- int type_num = 0;
- char *eptr;
- const char *type = "generic";
-
- type_num = strtoul(from, &eptr, 0);
- if (eptr != from) {
- switch (type_num) {
- case 1: /* RBC devices */
- type = "rbc";
- break;
- case 2:
- type = "atapi";
- break;
- case 3:
- type = "tape";
- break;
- case 4: /* UFI */
- type = "floppy";
- break;
- case 6: /* Transparent SPC-2 devices */
- type = "scsi";
- break;
- default:
- break;
- }
- }
- strscpy(to, len, type);
- return type_num;
-}
-
-static void set_scsi_type(char *to, const char *from, size_t len) {
- int type_num;
- char *eptr;
- const char *type = "generic";
-
- type_num = strtoul(from, &eptr, 0);
- if (eptr != from) {
- switch (type_num) {
- case 0:
- case 0xe:
- type = "disk";
- break;
- case 1:
- type = "tape";
- break;
- case 4:
- case 7:
- case 0xf:
- type = "optical";
- break;
- case 5:
- type = "cd";
- break;
- default:
- break;
- }
- }
- strscpy(to, len, type);
-}
-
-#define USB_DT_DEVICE 0x01
-#define USB_DT_INTERFACE 0x04
-
-static int dev_if_packed_info(struct udev_device *dev, char *ifs_str, size_t len) {
- _cleanup_free_ char *filename = NULL;
- _cleanup_close_ int fd = -1;
- ssize_t size;
- unsigned char buf[18 + 65535];
- size_t pos = 0;
- unsigned strpos = 0;
- struct usb_interface_descriptor {
- uint8_t bLength;
- uint8_t bDescriptorType;
- uint8_t bInterfaceNumber;
- uint8_t bAlternateSetting;
- uint8_t bNumEndpoints;
- uint8_t bInterfaceClass;
- uint8_t bInterfaceSubClass;
- uint8_t bInterfaceProtocol;
- uint8_t iInterface;
- } _packed_;
-
- if (asprintf(&filename, "%s/descriptors", udev_device_get_syspath(dev)) < 0)
- return log_oom();
-
- fd = open(filename, O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- return log_debug_errno(errno, "Error opening USB device 'descriptors' file: %m");
-
- size = read(fd, buf, sizeof(buf));
- if (size < 18 || size == sizeof(buf))
- return -EIO;
-
- ifs_str[0] = '\0';
- while (pos + sizeof(struct usb_interface_descriptor) < (size_t) size &&
- strpos + 7 < len - 2) {
-
- struct usb_interface_descriptor *desc;
- char if_str[8];
-
- desc = (struct usb_interface_descriptor *) &buf[pos];
- if (desc->bLength < 3)
- break;
- pos += desc->bLength;
-
- if (desc->bDescriptorType != USB_DT_INTERFACE)
- continue;
-
- if (snprintf(if_str, 8, ":%02x%02x%02x",
- desc->bInterfaceClass,
- desc->bInterfaceSubClass,
- desc->bInterfaceProtocol) != 7)
- continue;
-
- if (strstr(ifs_str, if_str) != NULL)
- continue;
-
- memcpy(&ifs_str[strpos], if_str, 8),
- strpos += 7;
- }
-
- if (strpos > 0) {
- ifs_str[strpos++] = ':';
- ifs_str[strpos++] = '\0';
- }
-
- return 0;
-}
-
-/*
- * A unique USB identification is generated like this:
- *
- * 1.) Get the USB device type from InterfaceClass and InterfaceSubClass
- * 2.) If the device type is 'Mass-Storage/SPC-2' or 'Mass-Storage/RBC',
- * use the SCSI vendor and model as USB-Vendor and USB-model.
- * 3.) Otherwise, use the USB manufacturer and product as
- * USB-Vendor and USB-model. Any non-printable characters
- * in those strings will be skipped; a slash '/' will be converted
- * into a full stop '.'.
- * 4.) If that fails, too, we will use idVendor and idProduct
- * as USB-Vendor and USB-model.
- * 5.) The USB identification is the USB-vendor and USB-model
- * string concatenated with an underscore '_'.
- * 6.) If the device supplies a serial number, this number
- * is concatenated with the identification with an underscore '_'.
- */
-static int builtin_usb_id(struct udev_device *dev, int argc, char *argv[], bool test) {
- char vendor_str[64] = "";
- char vendor_str_enc[256];
- const char *vendor_id;
- char model_str[64] = "";
- char model_str_enc[256];
- const char *product_id;
- char serial_str[UTIL_NAME_SIZE] = "";
- char packed_if_str[UTIL_NAME_SIZE] = "";
- char revision_str[64] = "";
- char type_str[64] = "";
- char instance_str[64] = "";
- const char *ifnum = NULL;
- const char *driver = NULL;
- char serial[256];
-
- struct udev_device *dev_interface = NULL;
- struct udev_device *dev_usb = NULL;
- const char *if_class, *if_subclass;
- int if_class_num;
- int protocol = 0;
- size_t l;
- char *s;
-
- assert(dev);
-
- /* shortcut, if we are called directly for a "usb_device" type */
- if (udev_device_get_devtype(dev) != NULL && streq(udev_device_get_devtype(dev), "usb_device")) {
- dev_if_packed_info(dev, packed_if_str, sizeof(packed_if_str));
- dev_usb = dev;
- goto fallback;
- }
-
- /* usb interface directory */
- dev_interface = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
- if (dev_interface == NULL) {
- log_debug("unable to access usb_interface device of '%s'",
- udev_device_get_syspath(dev));
- return EXIT_FAILURE;
- }
-
- ifnum = udev_device_get_sysattr_value(dev_interface, "bInterfaceNumber");
- driver = udev_device_get_sysattr_value(dev_interface, "driver");
-
- if_class = udev_device_get_sysattr_value(dev_interface, "bInterfaceClass");
- if (!if_class) {
- log_debug("%s: cannot get bInterfaceClass attribute",
- udev_device_get_sysname(dev));
- return EXIT_FAILURE;
- }
-
- if_class_num = strtoul(if_class, NULL, 16);
- if (if_class_num == 8) {
- /* mass storage */
- if_subclass = udev_device_get_sysattr_value(dev_interface, "bInterfaceSubClass");
- if (if_subclass != NULL)
- protocol = set_usb_mass_storage_ifsubtype(type_str, if_subclass, sizeof(type_str)-1);
- } else {
- set_usb_iftype(type_str, if_class_num, sizeof(type_str)-1);
- }
-
- log_debug("%s: if_class %d protocol %d",
- udev_device_get_syspath(dev_interface), if_class_num, protocol);
-
- /* usb device directory */
- dev_usb = udev_device_get_parent_with_subsystem_devtype(dev_interface, "usb", "usb_device");
- if (!dev_usb) {
- log_debug("unable to find parent 'usb' device of '%s'",
- udev_device_get_syspath(dev));
- return EXIT_FAILURE;
- }
-
- /* all interfaces of the device in a single string */
- dev_if_packed_info(dev_usb, packed_if_str, sizeof(packed_if_str));
-
- /* mass storage : SCSI or ATAPI */
- if (protocol == 6 || protocol == 2) {
- struct udev_device *dev_scsi;
- const char *scsi_model, *scsi_vendor, *scsi_type, *scsi_rev;
- int host, bus, target, lun;
-
- /* get scsi device */
- dev_scsi = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device");
- if (dev_scsi == NULL) {
- log_debug("unable to find parent 'scsi' device of '%s'",
- udev_device_get_syspath(dev));
- goto fallback;
- }
- if (sscanf(udev_device_get_sysname(dev_scsi), "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4) {
- log_debug("invalid scsi device '%s'", udev_device_get_sysname(dev_scsi));
- goto fallback;
- }
-
- /* Generic SPC-2 device */
- scsi_vendor = udev_device_get_sysattr_value(dev_scsi, "vendor");
- if (!scsi_vendor) {
- log_debug("%s: cannot get SCSI vendor attribute",
- udev_device_get_sysname(dev_scsi));
- goto fallback;
- }
- udev_util_encode_string(scsi_vendor, vendor_str_enc, sizeof(vendor_str_enc));
- util_replace_whitespace(scsi_vendor, vendor_str, sizeof(vendor_str)-1);
- util_replace_chars(vendor_str, NULL);
-
- scsi_model = udev_device_get_sysattr_value(dev_scsi, "model");
- if (!scsi_model) {
- log_debug("%s: cannot get SCSI model attribute",
- udev_device_get_sysname(dev_scsi));
- goto fallback;
- }
- udev_util_encode_string(scsi_model, model_str_enc, sizeof(model_str_enc));
- util_replace_whitespace(scsi_model, model_str, sizeof(model_str)-1);
- util_replace_chars(model_str, NULL);
-
- scsi_type = udev_device_get_sysattr_value(dev_scsi, "type");
- if (!scsi_type) {
- log_debug("%s: cannot get SCSI type attribute",
- udev_device_get_sysname(dev_scsi));
- goto fallback;
- }
- set_scsi_type(type_str, scsi_type, sizeof(type_str)-1);
-
- scsi_rev = udev_device_get_sysattr_value(dev_scsi, "rev");
- if (!scsi_rev) {
- log_debug("%s: cannot get SCSI revision attribute",
- udev_device_get_sysname(dev_scsi));
- goto fallback;
- }
- util_replace_whitespace(scsi_rev, revision_str, sizeof(revision_str)-1);
- util_replace_chars(revision_str, NULL);
-
- /*
- * some broken devices have the same identifiers
- * for all luns, export the target:lun number
- */
- sprintf(instance_str, "%d:%d", target, lun);
- }
-
-fallback:
- vendor_id = udev_device_get_sysattr_value(dev_usb, "idVendor");
- product_id = udev_device_get_sysattr_value(dev_usb, "idProduct");
-
- /* fallback to USB vendor & device */
- if (vendor_str[0] == '\0') {
- const char *usb_vendor = NULL;
-
- usb_vendor = udev_device_get_sysattr_value(dev_usb, "manufacturer");
- if (!usb_vendor)
- usb_vendor = vendor_id;
- if (!usb_vendor) {
- log_debug("No USB vendor information available");
- return EXIT_FAILURE;
- }
- udev_util_encode_string(usb_vendor, vendor_str_enc, sizeof(vendor_str_enc));
- util_replace_whitespace(usb_vendor, vendor_str, sizeof(vendor_str)-1);
- util_replace_chars(vendor_str, NULL);
- }
-
- if (model_str[0] == '\0') {
- const char *usb_model = NULL;
-
- usb_model = udev_device_get_sysattr_value(dev_usb, "product");
- if (!usb_model)
- usb_model = product_id;
- if (!usb_model)
- return EXIT_FAILURE;
- udev_util_encode_string(usb_model, model_str_enc, sizeof(model_str_enc));
- util_replace_whitespace(usb_model, model_str, sizeof(model_str)-1);
- util_replace_chars(model_str, NULL);
- }
-
- if (revision_str[0] == '\0') {
- const char *usb_rev;
-
- usb_rev = udev_device_get_sysattr_value(dev_usb, "bcdDevice");
- if (usb_rev) {
- util_replace_whitespace(usb_rev, revision_str, sizeof(revision_str)-1);
- util_replace_chars(revision_str, NULL);
- }
- }
-
- if (serial_str[0] == '\0') {
- const char *usb_serial;
-
- usb_serial = udev_device_get_sysattr_value(dev_usb, "serial");
- if (usb_serial) {
- const unsigned char *p;
-
- /* http://msdn.microsoft.com/en-us/library/windows/hardware/gg487321.aspx */
- for (p = (unsigned char *)usb_serial; *p != '\0'; p++)
- if (*p < 0x20 || *p > 0x7f || *p == ',') {
- usb_serial = NULL;
- break;
- }
- }
-
- if (usb_serial) {
- util_replace_whitespace(usb_serial, serial_str, sizeof(serial_str)-1);
- util_replace_chars(serial_str, NULL);
- }
- }
-
- s = serial;
- l = strpcpyl(&s, sizeof(serial), vendor_str, "_", model_str, NULL);
- if (!isempty(serial_str))
- l = strpcpyl(&s, l, "_", serial_str, NULL);
-
- if (!isempty(instance_str))
- strpcpyl(&s, l, "-", instance_str, NULL);
-
- udev_builtin_add_property(dev, test, "ID_VENDOR", vendor_str);
- udev_builtin_add_property(dev, test, "ID_VENDOR_ENC", vendor_str_enc);
- udev_builtin_add_property(dev, test, "ID_VENDOR_ID", vendor_id);
- udev_builtin_add_property(dev, test, "ID_MODEL", model_str);
- udev_builtin_add_property(dev, test, "ID_MODEL_ENC", model_str_enc);
- udev_builtin_add_property(dev, test, "ID_MODEL_ID", product_id);
- udev_builtin_add_property(dev, test, "ID_REVISION", revision_str);
- udev_builtin_add_property(dev, test, "ID_SERIAL", serial);
- if (!isempty(serial_str))
- udev_builtin_add_property(dev, test, "ID_SERIAL_SHORT", serial_str);
- if (!isempty(type_str))
- udev_builtin_add_property(dev, test, "ID_TYPE", type_str);
- if (!isempty(instance_str))
- udev_builtin_add_property(dev, test, "ID_INSTANCE", instance_str);
- udev_builtin_add_property(dev, test, "ID_BUS", "usb");
- if (!isempty(packed_if_str))
- udev_builtin_add_property(dev, test, "ID_USB_INTERFACES", packed_if_str);
- if (ifnum != NULL)
- udev_builtin_add_property(dev, test, "ID_USB_INTERFACE_NUM", ifnum);
- if (driver != NULL)
- udev_builtin_add_property(dev, test, "ID_USB_DRIVER", driver);
- return EXIT_SUCCESS;
-}
-
-const struct udev_builtin udev_builtin_usb_id = {
- .name = "usb_id",
- .cmd = builtin_usb_id,
- .help = "USB device properties",
- .run_once = true,
-};
diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c
deleted file mode 100644
index e6b36f124f..0000000000
--- a/src/udev/udev-builtin.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2007-2012 Kay Sievers <kay@vrfy.org>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <getopt.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "string-util.h"
-#include "udev.h"
-
-static bool initialized;
-
-static const struct udev_builtin *builtins[] = {
-#ifdef HAVE_BLKID
- [UDEV_BUILTIN_BLKID] = &udev_builtin_blkid,
-#endif
- [UDEV_BUILTIN_BTRFS] = &udev_builtin_btrfs,
- [UDEV_BUILTIN_HWDB] = &udev_builtin_hwdb,
- [UDEV_BUILTIN_INPUT_ID] = &udev_builtin_input_id,
- [UDEV_BUILTIN_KEYBOARD] = &udev_builtin_keyboard,
-#ifdef HAVE_KMOD
- [UDEV_BUILTIN_KMOD] = &udev_builtin_kmod,
-#endif
- [UDEV_BUILTIN_NET_ID] = &udev_builtin_net_id,
- [UDEV_BUILTIN_NET_LINK] = &udev_builtin_net_setup_link,
- [UDEV_BUILTIN_PATH_ID] = &udev_builtin_path_id,
- [UDEV_BUILTIN_USB_ID] = &udev_builtin_usb_id,
-#ifdef HAVE_ACL
- [UDEV_BUILTIN_UACCESS] = &udev_builtin_uaccess,
-#endif
-};
-
-void udev_builtin_init(struct udev *udev) {
- unsigned int i;
-
- if (initialized)
- return;
-
- for (i = 0; i < ELEMENTSOF(builtins); i++)
- if (builtins[i] && builtins[i]->init)
- builtins[i]->init(udev);
-
- initialized = true;
-}
-
-void udev_builtin_exit(struct udev *udev) {
- unsigned int i;
-
- if (!initialized)
- return;
-
- for (i = 0; i < ELEMENTSOF(builtins); i++)
- if (builtins[i] && builtins[i]->exit)
- builtins[i]->exit(udev);
-
- initialized = false;
-}
-
-bool udev_builtin_validate(struct udev *udev) {
- unsigned int i;
-
- for (i = 0; i < ELEMENTSOF(builtins); i++)
- if (builtins[i] && builtins[i]->validate && builtins[i]->validate(udev))
- return true;
- return false;
-}
-
-void udev_builtin_list(struct udev *udev) {
- unsigned int i;
-
- for (i = 0; i < ELEMENTSOF(builtins); i++)
- if (builtins[i])
- fprintf(stderr, " %-14s %s\n", builtins[i]->name, builtins[i]->help);
-}
-
-const char *udev_builtin_name(enum udev_builtin_cmd cmd) {
- if (!builtins[cmd])
- return NULL;
-
- return builtins[cmd]->name;
-}
-
-bool udev_builtin_run_once(enum udev_builtin_cmd cmd) {
- if (!builtins[cmd])
- return false;
-
- return builtins[cmd]->run_once;
-}
-
-enum udev_builtin_cmd udev_builtin_lookup(const char *command) {
- char name[UTIL_PATH_SIZE];
- enum udev_builtin_cmd i;
- char *pos;
-
- strscpy(name, sizeof(name), command);
- pos = strchr(name, ' ');
- if (pos)
- pos[0] = '\0';
- for (i = 0; i < ELEMENTSOF(builtins); i++)
- if (builtins[i] && streq(builtins[i]->name, name))
- return i;
- return UDEV_BUILTIN_MAX;
-}
-
-int udev_builtin_run(struct udev_device *dev, enum udev_builtin_cmd cmd, const char *command, bool test) {
- char arg[UTIL_PATH_SIZE];
- int argc;
- char *argv[128];
-
- if (!builtins[cmd])
- return -EOPNOTSUPP;
-
- /* we need '0' here to reset the internal state */
- optind = 0;
- strscpy(arg, sizeof(arg), command);
- udev_build_argv(udev_device_get_udev(dev), arg, &argc, argv);
- return builtins[cmd]->cmd(dev, argc, argv, test);
-}
-
-int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val) {
- udev_device_add_property(dev, key, val);
-
- if (test)
- printf("%s=%s\n", key, val);
- return 0;
-}
diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c
deleted file mode 100644
index 7717ac7924..0000000000
--- a/src/udev/udev-ctrl.c
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay@vrfy.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- */
-
-#include <errno.h>
-#include <poll.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "fd-util.h"
-#include "formats-util.h"
-#include "socket-util.h"
-#include "udev.h"
-
-/* wire protocol magic must match */
-#define UDEV_CTRL_MAGIC 0xdead1dea
-
-enum udev_ctrl_msg_type {
- UDEV_CTRL_UNKNOWN,
- UDEV_CTRL_SET_LOG_LEVEL,
- UDEV_CTRL_STOP_EXEC_QUEUE,
- UDEV_CTRL_START_EXEC_QUEUE,
- UDEV_CTRL_RELOAD,
- UDEV_CTRL_SET_ENV,
- UDEV_CTRL_SET_CHILDREN_MAX,
- UDEV_CTRL_PING,
- UDEV_CTRL_EXIT,
-};
-
-struct udev_ctrl_msg_wire {
- char version[16];
- unsigned int magic;
- enum udev_ctrl_msg_type type;
- union {
- int intval;
- char buf[256];
- };
-};
-
-struct udev_ctrl_msg {
- int refcount;
- struct udev_ctrl_connection *conn;
- struct udev_ctrl_msg_wire ctrl_msg_wire;
-};
-
-struct udev_ctrl {
- int refcount;
- struct udev *udev;
- int sock;
- union sockaddr_union saddr;
- socklen_t addrlen;
- bool bound;
- bool cleanup_socket;
- bool connected;
-};
-
-struct udev_ctrl_connection {
- int refcount;
- struct udev_ctrl *uctrl;
- int sock;
-};
-
-struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) {
- struct udev_ctrl *uctrl;
- const int on = 1;
- int r;
-
- uctrl = new0(struct udev_ctrl, 1);
- if (uctrl == NULL)
- return NULL;
- uctrl->refcount = 1;
- uctrl->udev = udev;
-
- if (fd < 0) {
- uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
- if (uctrl->sock < 0) {
- log_error_errno(errno, "error getting socket: %m");
- udev_ctrl_unref(uctrl);
- return NULL;
- }
- } else {
- uctrl->bound = true;
- uctrl->sock = fd;
- }
-
- /*
- * FIXME: remove it as soon as we can depend on this:
- * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=90c6bd34f884cd9cee21f1d152baf6c18bcac949
- */
- r = setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
- if (r < 0)
- log_warning_errno(errno, "could not set SO_PASSCRED: %m");
-
- uctrl->saddr.un.sun_family = AF_LOCAL;
- strscpy(uctrl->saddr.un.sun_path, sizeof(uctrl->saddr.un.sun_path), "/run/udev/control");
- uctrl->addrlen = SOCKADDR_UN_LEN(uctrl->saddr.un);
- return uctrl;
-}
-
-struct udev_ctrl *udev_ctrl_new(struct udev *udev) {
- return udev_ctrl_new_from_fd(udev, -1);
-}
-
-int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
- int err;
-
- if (!uctrl->bound) {
- err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen);
- if (err < 0 && errno == EADDRINUSE) {
- unlink(uctrl->saddr.un.sun_path);
- err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen);
- }
-
- if (err < 0)
- return log_error_errno(errno, "bind failed: %m");
-
- err = listen(uctrl->sock, 0);
- if (err < 0)
- return log_error_errno(errno, "listen failed: %m");
-
- uctrl->bound = true;
- uctrl->cleanup_socket = true;
- }
- return 0;
-}
-
-struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl) {
- return uctrl->udev;
-}
-
-static struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl) {
- if (uctrl)
- uctrl->refcount++;
-
- return uctrl;
-}
-
-struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl) {
- if (uctrl && -- uctrl->refcount == 0) {
- if (uctrl->sock >= 0)
- close(uctrl->sock);
- free(uctrl);
- }
-
- return NULL;
-}
-
-int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
- if (uctrl == NULL)
- return 0;
- if (uctrl->cleanup_socket)
- unlink(uctrl->saddr.un.sun_path);
- return 0;
-}
-
-int udev_ctrl_get_fd(struct udev_ctrl *uctrl) {
- if (uctrl == NULL)
- return -EINVAL;
- return uctrl->sock;
-}
-
-struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl) {
- struct udev_ctrl_connection *conn;
- struct ucred ucred = {};
- const int on = 1;
- int r;
-
- conn = new(struct udev_ctrl_connection, 1);
- if (conn == NULL)
- return NULL;
- conn->refcount = 1;
- conn->uctrl = uctrl;
-
- conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
- if (conn->sock < 0) {
- if (errno != EINTR)
- log_error_errno(errno, "unable to receive ctrl connection: %m");
- goto err;
- }
-
- /* check peer credential of connection */
- r = getpeercred(conn->sock, &ucred);
- if (r < 0) {
- log_error_errno(r, "unable to receive credentials of ctrl connection: %m");
- goto err;
- }
- if (ucred.uid > 0) {
- log_error("sender uid="UID_FMT", message ignored", ucred.uid);
- goto err;
- }
-
- /* enable receiving of the sender credentials in the messages */
- r = setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
- if (r < 0)
- log_warning_errno(errno, "could not set SO_PASSCRED: %m");
-
- udev_ctrl_ref(uctrl);
- return conn;
-err:
- if (conn->sock >= 0)
- close(conn->sock);
- return mfree(conn);
-}
-
-struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn) {
- if (conn == NULL)
- return NULL;
- conn->refcount++;
- return conn;
-}
-
-struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn) {
- if (conn && -- conn->refcount == 0) {
- if (conn->sock >= 0)
- close(conn->sock);
-
- udev_ctrl_unref(conn->uctrl);
-
- free(conn);
- }
-
- return NULL;
-}
-
-static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout) {
- struct udev_ctrl_msg_wire ctrl_msg_wire;
- int err = 0;
-
- memzero(&ctrl_msg_wire, sizeof(struct udev_ctrl_msg_wire));
- strcpy(ctrl_msg_wire.version, "udev-" VERSION);
- ctrl_msg_wire.magic = UDEV_CTRL_MAGIC;
- ctrl_msg_wire.type = type;
-
- if (buf != NULL)
- strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf);
- else
- ctrl_msg_wire.intval = intval;
-
- if (!uctrl->connected) {
- if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0) {
- err = -errno;
- goto out;
- }
- uctrl->connected = true;
- }
- if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) {
- err = -errno;
- goto out;
- }
-
- /* wait for peer message handling or disconnect */
- for (;;) {
- struct pollfd pfd[1];
- int r;
-
- pfd[0].fd = uctrl->sock;
- pfd[0].events = POLLIN;
- r = poll(pfd, 1, timeout * MSEC_PER_SEC);
- if (r < 0) {
- if (errno == EINTR)
- continue;
- err = -errno;
- break;
- }
-
- if (r > 0 && pfd[0].revents & POLLERR) {
- err = -EIO;
- break;
- }
-
- if (r == 0)
- err = -ETIMEDOUT;
- break;
- }
-out:
- return err;
-}
-
-int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout) {
- return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout);
-}
-
-int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout) {
- return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout);
-}
-
-int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout) {
- return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout);
-}
-
-int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout) {
- return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout);
-}
-
-int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout) {
- return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout);
-}
-
-int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout) {
- return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout);
-}
-
-int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout) {
- return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout);
-}
-
-int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout) {
- return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout);
-}
-
-struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn) {
- struct udev_ctrl_msg *uctrl_msg;
- ssize_t size;
- struct cmsghdr *cmsg;
- struct iovec iov;
- char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
- struct msghdr smsg = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_control = cred_msg,
- .msg_controllen = sizeof(cred_msg),
- };
- struct ucred *cred;
-
- uctrl_msg = new0(struct udev_ctrl_msg, 1);
- if (uctrl_msg == NULL)
- return NULL;
- uctrl_msg->refcount = 1;
- uctrl_msg->conn = conn;
- udev_ctrl_connection_ref(conn);
-
- /* wait for the incoming message */
- for (;;) {
- struct pollfd pfd[1];
- int r;
-
- pfd[0].fd = conn->sock;
- pfd[0].events = POLLIN;
-
- r = poll(pfd, 1, 10000);
- if (r < 0) {
- if (errno == EINTR)
- continue;
- goto err;
- } else if (r == 0) {
- log_error("timeout waiting for ctrl message");
- goto err;
- } else {
- if (!(pfd[0].revents & POLLIN)) {
- log_error_errno(errno, "ctrl connection error: %m");
- goto err;
- }
- }
-
- break;
- }
-
- iov.iov_base = &uctrl_msg->ctrl_msg_wire;
- iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
-
- size = recvmsg(conn->sock, &smsg, 0);
- if (size < 0) {
- log_error_errno(errno, "unable to receive ctrl message: %m");
- goto err;
- }
-
- cmsg_close_all(&smsg);
-
- cmsg = CMSG_FIRSTHDR(&smsg);
-
- if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
- log_error("no sender credentials received, message ignored");
- goto err;
- }
-
- cred = (struct ucred *) CMSG_DATA(cmsg);
-
- if (cred->uid != 0) {
- log_error("sender uid="UID_FMT", message ignored", cred->uid);
- goto err;
- }
-
- if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
- log_error("message magic 0x%08x doesn't match, ignore it", uctrl_msg->ctrl_msg_wire.magic);
- goto err;
- }
-
- return uctrl_msg;
-err:
- udev_ctrl_msg_unref(uctrl_msg);
- return NULL;
-}
-
-struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg) {
- if (ctrl_msg && -- ctrl_msg->refcount == 0) {
- udev_ctrl_connection_unref(ctrl_msg->conn);
- free(ctrl_msg);
- }
-
- return NULL;
-}
-
-int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg) {
- if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL)
- return ctrl_msg->ctrl_msg_wire.intval;
- return -1;
-}
-
-int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg) {
- if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE)
- return 1;
- return -1;
-}
-
-int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg) {
- if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE)
- return 1;
- return -1;
-}
-
-int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg) {
- if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD)
- return 1;
- return -1;
-}
-
-const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg) {
- if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV)
- return ctrl_msg->ctrl_msg_wire.buf;
- return NULL;
-}
-
-int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg) {
- if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_CHILDREN_MAX)
- return ctrl_msg->ctrl_msg_wire.intval;
- return -1;
-}
-
-int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg) {
- if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING)
- return 1;
- return -1;
-}
-
-int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg) {
- if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_EXIT)
- return 1;
- return -1;
-}
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
deleted file mode 100644
index 54cd741bb1..0000000000
--- a/src/udev/udev-event.c
+++ /dev/null
@@ -1,943 +0,0 @@
-/*
- * Copyright (C) 2003-2013 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <net/if.h>
-#include <poll.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/prctl.h>
-#include <sys/signalfd.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "fd-util.h"
-#include "formats-util.h"
-#include "netlink-util.h"
-#include "process-util.h"
-#include "signal-util.h"
-#include "string-util.h"
-#include "udev.h"
-
-typedef struct Spawn {
- const char *cmd;
- pid_t pid;
- usec_t timeout_warn;
- usec_t timeout;
- bool accept_failure;
-} Spawn;
-
-struct udev_event *udev_event_new(struct udev_device *dev) {
- struct udev *udev = udev_device_get_udev(dev);
- struct udev_event *event;
-
- event = new0(struct udev_event, 1);
- if (event == NULL)
- return NULL;
- event->dev = dev;
- event->udev = udev;
- udev_list_init(udev, &event->run_list, false);
- udev_list_init(udev, &event->seclabel_list, false);
- event->birth_usec = clock_boottime_or_monotonic();
- return event;
-}
-
-void udev_event_unref(struct udev_event *event) {
- if (event == NULL)
- return;
- sd_netlink_unref(event->rtnl);
- udev_list_cleanup(&event->run_list);
- udev_list_cleanup(&event->seclabel_list);
- free(event->program_result);
- free(event->name);
- free(event);
-}
-
-size_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size) {
- struct udev_device *dev = event->dev;
- enum subst_type {
- SUBST_UNKNOWN,
- SUBST_DEVNODE,
- SUBST_ATTR,
- SUBST_ENV,
- SUBST_KERNEL,
- SUBST_KERNEL_NUMBER,
- SUBST_DRIVER,
- SUBST_DEVPATH,
- SUBST_ID,
- SUBST_MAJOR,
- SUBST_MINOR,
- SUBST_RESULT,
- SUBST_PARENT,
- SUBST_NAME,
- SUBST_LINKS,
- SUBST_ROOT,
- SUBST_SYS,
- };
- static const struct subst_map {
- const char *name;
- const char fmt;
- enum subst_type type;
- } map[] = {
- { .name = "devnode", .fmt = 'N', .type = SUBST_DEVNODE },
- { .name = "tempnode", .fmt = 'N', .type = SUBST_DEVNODE },
- { .name = "attr", .fmt = 's', .type = SUBST_ATTR },
- { .name = "sysfs", .fmt = 's', .type = SUBST_ATTR },
- { .name = "env", .fmt = 'E', .type = SUBST_ENV },
- { .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL },
- { .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER },
- { .name = "driver", .fmt = 'd', .type = SUBST_DRIVER },
- { .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH },
- { .name = "id", .fmt = 'b', .type = SUBST_ID },
- { .name = "major", .fmt = 'M', .type = SUBST_MAJOR },
- { .name = "minor", .fmt = 'm', .type = SUBST_MINOR },
- { .name = "result", .fmt = 'c', .type = SUBST_RESULT },
- { .name = "parent", .fmt = 'P', .type = SUBST_PARENT },
- { .name = "name", .fmt = 'D', .type = SUBST_NAME },
- { .name = "links", .fmt = 'L', .type = SUBST_LINKS },
- { .name = "root", .fmt = 'r', .type = SUBST_ROOT },
- { .name = "sys", .fmt = 'S', .type = SUBST_SYS },
- };
- const char *from;
- char *s;
- size_t l;
-
- assert(dev);
-
- from = src;
- s = dest;
- l = size;
-
- for (;;) {
- enum subst_type type = SUBST_UNKNOWN;
- char attrbuf[UTIL_PATH_SIZE];
- char *attr = NULL;
-
- while (from[0] != '\0') {
- if (from[0] == '$') {
- /* substitute named variable */
- unsigned int i;
-
- if (from[1] == '$') {
- from++;
- goto copy;
- }
-
- for (i = 0; i < ELEMENTSOF(map); i++) {
- if (startswith(&from[1], map[i].name)) {
- type = map[i].type;
- from += strlen(map[i].name)+1;
- goto subst;
- }
- }
- } else if (from[0] == '%') {
- /* substitute format char */
- unsigned int i;
-
- if (from[1] == '%') {
- from++;
- goto copy;
- }
-
- for (i = 0; i < ELEMENTSOF(map); i++) {
- if (from[1] == map[i].fmt) {
- type = map[i].type;
- from += 2;
- goto subst;
- }
- }
- }
-copy:
- /* copy char */
- if (l == 0)
- goto out;
- s[0] = from[0];
- from++;
- s++;
- l--;
- }
-
- goto out;
-subst:
- /* extract possible $format{attr} */
- if (from[0] == '{') {
- unsigned int i;
-
- from++;
- for (i = 0; from[i] != '}'; i++) {
- if (from[i] == '\0') {
- log_error("missing closing brace for format '%s'", src);
- goto out;
- }
- }
- if (i >= sizeof(attrbuf))
- goto out;
- memcpy(attrbuf, from, i);
- attrbuf[i] = '\0';
- from += i+1;
- attr = attrbuf;
- } else {
- attr = NULL;
- }
-
- switch (type) {
- case SUBST_DEVPATH:
- l = strpcpy(&s, l, udev_device_get_devpath(dev));
- break;
- case SUBST_KERNEL:
- l = strpcpy(&s, l, udev_device_get_sysname(dev));
- break;
- case SUBST_KERNEL_NUMBER:
- if (udev_device_get_sysnum(dev) == NULL)
- break;
- l = strpcpy(&s, l, udev_device_get_sysnum(dev));
- break;
- case SUBST_ID:
- if (event->dev_parent == NULL)
- break;
- l = strpcpy(&s, l, udev_device_get_sysname(event->dev_parent));
- break;
- case SUBST_DRIVER: {
- const char *driver;
-
- if (event->dev_parent == NULL)
- break;
-
- driver = udev_device_get_driver(event->dev_parent);
- if (driver == NULL)
- break;
- l = strpcpy(&s, l, driver);
- break;
- }
- case SUBST_MAJOR: {
- char num[UTIL_PATH_SIZE];
-
- sprintf(num, "%u", major(udev_device_get_devnum(dev)));
- l = strpcpy(&s, l, num);
- break;
- }
- case SUBST_MINOR: {
- char num[UTIL_PATH_SIZE];
-
- sprintf(num, "%u", minor(udev_device_get_devnum(dev)));
- l = strpcpy(&s, l, num);
- break;
- }
- case SUBST_RESULT: {
- char *rest;
- int i;
-
- if (event->program_result == NULL)
- break;
- /* get part of the result string */
- i = 0;
- if (attr != NULL)
- i = strtoul(attr, &rest, 10);
- if (i > 0) {
- char result[UTIL_PATH_SIZE];
- char tmp[UTIL_PATH_SIZE];
- char *cpos;
-
- strscpy(result, sizeof(result), event->program_result);
- cpos = result;
- while (--i) {
- while (cpos[0] != '\0' && !isspace(cpos[0]))
- cpos++;
- while (isspace(cpos[0]))
- cpos++;
- if (cpos[0] == '\0')
- break;
- }
- if (i > 0) {
- log_error("requested part of result string not found");
- break;
- }
- strscpy(tmp, sizeof(tmp), cpos);
- /* %{2+}c copies the whole string from the second part on */
- if (rest[0] != '+') {
- cpos = strchr(tmp, ' ');
- if (cpos)
- cpos[0] = '\0';
- }
- l = strpcpy(&s, l, tmp);
- } else {
- l = strpcpy(&s, l, event->program_result);
- }
- break;
- }
- case SUBST_ATTR: {
- const char *value = NULL;
- char vbuf[UTIL_NAME_SIZE];
- size_t len;
- int count;
-
- if (attr == NULL) {
- log_error("missing file parameter for attr");
- break;
- }
-
- /* try to read the value specified by "[dmi/id]product_name" */
- if (util_resolve_subsys_kernel(event->udev, attr, vbuf, sizeof(vbuf), 1) == 0)
- value = vbuf;
-
- /* try to read the attribute the device */
- if (value == NULL)
- value = udev_device_get_sysattr_value(event->dev, attr);
-
- /* try to read the attribute of the parent device, other matches have selected */
- if (value == NULL && event->dev_parent != NULL && event->dev_parent != event->dev)
- value = udev_device_get_sysattr_value(event->dev_parent, attr);
-
- if (value == NULL)
- break;
-
- /* strip trailing whitespace, and replace unwanted characters */
- if (value != vbuf)
- strscpy(vbuf, sizeof(vbuf), value);
- len = strlen(vbuf);
- while (len > 0 && isspace(vbuf[--len]))
- vbuf[len] = '\0';
- count = util_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT);
- if (count > 0)
- log_debug("%i character(s) replaced" , count);
- l = strpcpy(&s, l, vbuf);
- break;
- }
- case SUBST_PARENT: {
- struct udev_device *dev_parent;
- const char *devnode;
-
- dev_parent = udev_device_get_parent(event->dev);
- if (dev_parent == NULL)
- break;
- devnode = udev_device_get_devnode(dev_parent);
- if (devnode != NULL)
- l = strpcpy(&s, l, devnode + strlen("/dev/"));
- break;
- }
- case SUBST_DEVNODE:
- if (udev_device_get_devnode(dev) != NULL)
- l = strpcpy(&s, l, udev_device_get_devnode(dev));
- break;
- case SUBST_NAME:
- if (event->name != NULL)
- l = strpcpy(&s, l, event->name);
- else if (udev_device_get_devnode(dev) != NULL)
- l = strpcpy(&s, l, udev_device_get_devnode(dev) + strlen("/dev/"));
- else
- l = strpcpy(&s, l, udev_device_get_sysname(dev));
- break;
- case SUBST_LINKS: {
- struct udev_list_entry *list_entry;
-
- list_entry = udev_device_get_devlinks_list_entry(dev);
- if (list_entry == NULL)
- break;
- l = strpcpy(&s, l, udev_list_entry_get_name(list_entry) + strlen("/dev/"));
- udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry))
- l = strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry) + strlen("/dev/"), NULL);
- break;
- }
- case SUBST_ROOT:
- l = strpcpy(&s, l, "/dev");
- break;
- case SUBST_SYS:
- l = strpcpy(&s, l, "/sys");
- break;
- case SUBST_ENV:
- if (attr == NULL) {
- break;
- } else {
- const char *value;
-
- value = udev_device_get_property_value(event->dev, attr);
- if (value == NULL)
- break;
- l = strpcpy(&s, l, value);
- break;
- }
- default:
- log_error("unknown substitution type=%i", type);
- break;
- }
- }
-
-out:
- s[0] = '\0';
- return l;
-}
-
-static int spawn_exec(struct udev_event *event,
- const char *cmd, char *const argv[], char **envp,
- int fd_stdout, int fd_stderr) {
- _cleanup_close_ int fd = -1;
- int r;
-
- /* discard child output or connect to pipe */
- fd = open("/dev/null", O_RDWR);
- if (fd >= 0) {
- r = dup2(fd, STDIN_FILENO);
- if (r < 0)
- log_warning_errno(errno, "redirecting stdin failed: %m");
-
- if (fd_stdout < 0) {
- r = dup2(fd, STDOUT_FILENO);
- if (r < 0)
- log_warning_errno(errno, "redirecting stdout failed: %m");
- }
-
- if (fd_stderr < 0) {
- r = dup2(fd, STDERR_FILENO);
- if (r < 0)
- log_warning_errno(errno, "redirecting stderr failed: %m");
- }
- } else
- log_warning_errno(errno, "open /dev/null failed: %m");
-
- /* connect pipes to std{out,err} */
- if (fd_stdout >= 0) {
- r = dup2(fd_stdout, STDOUT_FILENO);
- if (r < 0)
- log_warning_errno(errno, "redirecting stdout failed: %m");
-
- fd_stdout = safe_close(fd_stdout);
- }
-
- if (fd_stderr >= 0) {
- r = dup2(fd_stderr, STDERR_FILENO);
- if (r < 0)
- log_warning_errno(errno, "redirecting stdout failed: %m");
-
- fd_stderr = safe_close(fd_stderr);
- }
-
- /* terminate child in case parent goes away */
- prctl(PR_SET_PDEATHSIG, SIGTERM);
-
- /* restore sigmask before exec */
- (void) reset_signal_mask();
-
- execve(argv[0], argv, envp);
-
- /* exec failed */
- return log_error_errno(errno, "failed to execute '%s' '%s': %m", argv[0], cmd);
-}
-
-static void spawn_read(struct udev_event *event,
- usec_t timeout_usec,
- const char *cmd,
- int fd_stdout, int fd_stderr,
- char *result, size_t ressize) {
- _cleanup_close_ int fd_ep = -1;
- struct epoll_event ep_outpipe = {
- .events = EPOLLIN,
- .data.ptr = &fd_stdout,
- };
- struct epoll_event ep_errpipe = {
- .events = EPOLLIN,
- .data.ptr = &fd_stderr,
- };
- size_t respos = 0;
- int r;
-
- /* read from child if requested */
- if (fd_stdout < 0 && fd_stderr < 0)
- return;
-
- fd_ep = epoll_create1(EPOLL_CLOEXEC);
- if (fd_ep < 0) {
- log_error_errno(errno, "error creating epoll fd: %m");
- return;
- }
-
- if (fd_stdout >= 0) {
- r = epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stdout, &ep_outpipe);
- if (r < 0) {
- log_error_errno(errno, "fail to add stdout fd to epoll: %m");
- return;
- }
- }
-
- if (fd_stderr >= 0) {
- r = epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stderr, &ep_errpipe);
- if (r < 0) {
- log_error_errno(errno, "fail to add stderr fd to epoll: %m");
- return;
- }
- }
-
- /* read child output */
- while (fd_stdout >= 0 || fd_stderr >= 0) {
- int timeout;
- int fdcount;
- struct epoll_event ev[4];
- int i;
-
- if (timeout_usec > 0) {
- usec_t age_usec;
-
- age_usec = clock_boottime_or_monotonic() - event->birth_usec;
- if (age_usec >= timeout_usec) {
- log_error("timeout '%s'", cmd);
- return;
- }
- timeout = ((timeout_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC;
- } else {
- timeout = -1;
- }
-
- fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), timeout);
- if (fdcount < 0) {
- if (errno == EINTR)
- continue;
- log_error_errno(errno, "failed to poll: %m");
- return;
- } else if (fdcount == 0) {
- log_error("timeout '%s'", cmd);
- return;
- }
-
- for (i = 0; i < fdcount; i++) {
- int *fd = (int *)ev[i].data.ptr;
-
- if (*fd < 0)
- continue;
-
- if (ev[i].events & EPOLLIN) {
- ssize_t count;
- char buf[4096];
-
- count = read(*fd, buf, sizeof(buf)-1);
- if (count <= 0)
- continue;
- buf[count] = '\0';
-
- /* store stdout result */
- if (result != NULL && *fd == fd_stdout) {
- if (respos + count < ressize) {
- memcpy(&result[respos], buf, count);
- respos += count;
- } else {
- log_error("'%s' ressize %zu too short", cmd, ressize);
- }
- }
-
- /* log debug output only if we watch stderr */
- if (fd_stderr >= 0) {
- char *pos;
- char *line;
-
- pos = buf;
- while ((line = strsep(&pos, "\n"))) {
- if (pos != NULL || line[0] != '\0')
- log_debug("'%s'(%s) '%s'", cmd, *fd == fd_stdout ? "out" : "err" , line);
- }
- }
- } else if (ev[i].events & EPOLLHUP) {
- r = epoll_ctl(fd_ep, EPOLL_CTL_DEL, *fd, NULL);
- if (r < 0) {
- log_error_errno(errno, "failed to remove fd from epoll: %m");
- return;
- }
- *fd = -1;
- }
- }
- }
-
- /* return the child's stdout string */
- if (result != NULL)
- result[respos] = '\0';
-}
-
-static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
- Spawn *spawn = userdata;
- char timeout[FORMAT_TIMESTAMP_RELATIVE_MAX];
-
- assert(spawn);
-
- kill_and_sigcont(spawn->pid, SIGKILL);
-
- log_error("spawned process '%s' ["PID_FMT"] timed out after %s, killing", spawn->cmd, spawn->pid,
- format_timestamp_relative(timeout, sizeof(timeout), spawn->timeout));
-
- return 1;
-}
-
-static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
- Spawn *spawn = userdata;
- char timeout[FORMAT_TIMESTAMP_RELATIVE_MAX];
-
- assert(spawn);
-
- log_warning("spawned process '%s' ["PID_FMT"] is taking longer than %s to complete", spawn->cmd, spawn->pid,
- format_timestamp_relative(timeout, sizeof(timeout), spawn->timeout));
-
- return 1;
-}
-
-static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
- Spawn *spawn = userdata;
-
- assert(spawn);
-
- switch (si->si_code) {
- case CLD_EXITED:
- if (si->si_status == 0) {
- log_debug("Process '%s' succeeded.", spawn->cmd);
- sd_event_exit(sd_event_source_get_event(s), 0);
-
- return 1;
- } else if (spawn->accept_failure)
- log_debug("Process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
- else
- log_warning("Process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
-
- break;
- case CLD_KILLED:
- case CLD_DUMPED:
- log_warning("Process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status));
-
- break;
- default:
- log_error("Process '%s' failed due to unknown reason.", spawn->cmd);
- }
-
- sd_event_exit(sd_event_source_get_event(s), -EIO);
-
- return 1;
-}
-
-static int spawn_wait(struct udev_event *event,
- usec_t timeout_usec,
- usec_t timeout_warn_usec,
- const char *cmd, pid_t pid,
- bool accept_failure) {
- Spawn spawn = {
- .cmd = cmd,
- .pid = pid,
- .accept_failure = accept_failure,
- };
- _cleanup_(sd_event_unrefp) sd_event *e = NULL;
- int r, ret;
-
- r = sd_event_new(&e);
- if (r < 0)
- return r;
-
- if (timeout_usec > 0) {
- usec_t usec, age_usec;
-
- usec = now(clock_boottime_or_monotonic());
- age_usec = usec - event->birth_usec;
- if (age_usec < timeout_usec) {
- if (timeout_warn_usec > 0 && timeout_warn_usec < timeout_usec && age_usec < timeout_warn_usec) {
- spawn.timeout_warn = timeout_warn_usec - age_usec;
-
- r = sd_event_add_time(e, NULL, clock_boottime_or_monotonic(),
- usec + spawn.timeout_warn, USEC_PER_SEC,
- on_spawn_timeout_warning, &spawn);
- if (r < 0)
- return r;
- }
-
- spawn.timeout = timeout_usec - age_usec;
-
- r = sd_event_add_time(e, NULL, clock_boottime_or_monotonic(),
- usec + spawn.timeout, USEC_PER_SEC, on_spawn_timeout, &spawn);
- if (r < 0)
- return r;
- }
- }
-
- r = sd_event_add_child(e, NULL, pid, WEXITED, on_spawn_sigchld, &spawn);
- if (r < 0)
- return r;
-
- r = sd_event_loop(e);
- if (r < 0)
- return r;
-
- r = sd_event_get_exit_code(e, &ret);
- if (r < 0)
- return r;
-
- return ret;
-}
-
-int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]) {
- int i = 0;
- char *pos;
-
- if (strchr(cmd, ' ') == NULL) {
- argv[i++] = cmd;
- goto out;
- }
-
- pos = cmd;
- while (pos != NULL && pos[0] != '\0') {
- if (pos[0] == '\'') {
- /* do not separate quotes */
- pos++;
- argv[i] = strsep(&pos, "\'");
- if (pos != NULL)
- while (pos[0] == ' ')
- pos++;
- } else {
- argv[i] = strsep(&pos, " ");
- if (pos != NULL)
- while (pos[0] == ' ')
- pos++;
- }
- i++;
- }
-out:
- argv[i] = NULL;
- if (argc)
- *argc = i;
- return 0;
-}
-
-int udev_event_spawn(struct udev_event *event,
- usec_t timeout_usec,
- usec_t timeout_warn_usec,
- bool accept_failure,
- const char *cmd,
- char *result, size_t ressize) {
- int outpipe[2] = {-1, -1};
- int errpipe[2] = {-1, -1};
- pid_t pid;
- int err = 0;
-
- /* pipes from child to parent */
- if (result != NULL || log_get_max_level() >= LOG_INFO) {
- if (pipe2(outpipe, O_NONBLOCK) != 0) {
- err = log_error_errno(errno, "pipe failed: %m");
- goto out;
- }
- }
- if (log_get_max_level() >= LOG_INFO) {
- if (pipe2(errpipe, O_NONBLOCK) != 0) {
- err = log_error_errno(errno, "pipe failed: %m");
- goto out;
- }
- }
-
- pid = fork();
- switch(pid) {
- case 0:
- {
- char arg[UTIL_PATH_SIZE];
- char *argv[128];
- char program[UTIL_PATH_SIZE];
-
- /* child closes parent's ends of pipes */
- outpipe[READ_END] = safe_close(outpipe[READ_END]);
- errpipe[READ_END] = safe_close(errpipe[READ_END]);
-
- strscpy(arg, sizeof(arg), cmd);
- udev_build_argv(event->udev, arg, NULL, argv);
-
- /* allow programs in /usr/lib/udev/ to be called without the path */
- if (argv[0][0] != '/') {
- strscpyl(program, sizeof(program), UDEVLIBEXECDIR "/", argv[0], NULL);
- argv[0] = program;
- }
-
- log_debug("starting '%s'", cmd);
-
- spawn_exec(event, cmd, argv, udev_device_get_properties_envp(event->dev),
- outpipe[WRITE_END], errpipe[WRITE_END]);
-
- _exit(2);
- }
- case -1:
- log_error_errno(errno, "fork of '%s' failed: %m", cmd);
- err = -1;
- goto out;
- default:
- /* parent closed child's ends of pipes */
- outpipe[WRITE_END] = safe_close(outpipe[WRITE_END]);
- errpipe[WRITE_END] = safe_close(errpipe[WRITE_END]);
-
- spawn_read(event,
- timeout_usec,
- cmd,
- outpipe[READ_END], errpipe[READ_END],
- result, ressize);
-
- err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid, accept_failure);
- }
-
-out:
- if (outpipe[READ_END] >= 0)
- close(outpipe[READ_END]);
- if (outpipe[WRITE_END] >= 0)
- close(outpipe[WRITE_END]);
- if (errpipe[READ_END] >= 0)
- close(errpipe[READ_END]);
- if (errpipe[WRITE_END] >= 0)
- close(errpipe[WRITE_END]);
- return err;
-}
-
-static int rename_netif(struct udev_event *event) {
- struct udev_device *dev = event->dev;
- char name[IFNAMSIZ];
- const char *oldname;
- int r;
-
- oldname = udev_device_get_sysname(dev);
-
- strscpy(name, IFNAMSIZ, event->name);
-
- r = rtnl_set_link_name(&event->rtnl, udev_device_get_ifindex(dev), name);
- if (r < 0)
- return log_error_errno(r, "Error changing net interface name '%s' to '%s': %m", oldname, name);
-
- log_debug("renamed network interface '%s' to '%s'", oldname, name);
-
- return 0;
-}
-
-void udev_event_execute_rules(struct udev_event *event,
- usec_t timeout_usec, usec_t timeout_warn_usec,
- struct udev_list *properties_list,
- struct udev_rules *rules) {
- struct udev_device *dev = event->dev;
-
- if (udev_device_get_subsystem(dev) == NULL)
- return;
-
- if (streq(udev_device_get_action(dev), "remove")) {
- udev_device_read_db(dev);
- udev_device_tag_index(dev, NULL, false);
- udev_device_delete_db(dev);
-
- if (major(udev_device_get_devnum(dev)) != 0)
- udev_watch_end(event->udev, dev);
-
- udev_rules_apply_to_event(rules, event,
- timeout_usec, timeout_warn_usec,
- properties_list);
-
- if (major(udev_device_get_devnum(dev)) != 0)
- udev_node_remove(dev);
- } else {
- event->dev_db = udev_device_clone_with_db(dev);
- if (event->dev_db != NULL) {
- /* disable watch during event processing */
- if (major(udev_device_get_devnum(dev)) != 0)
- udev_watch_end(event->udev, event->dev_db);
-
- if (major(udev_device_get_devnum(dev)) == 0 &&
- streq(udev_device_get_action(dev), "move"))
- udev_device_copy_properties(dev, event->dev_db);
- }
-
- udev_rules_apply_to_event(rules, event,
- timeout_usec, timeout_warn_usec,
- properties_list);
-
- /* rename a new network interface, if needed */
- if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") &&
- event->name != NULL && !streq(event->name, udev_device_get_sysname(dev))) {
- int r;
-
- r = rename_netif(event);
- if (r < 0)
- log_warning_errno(r, "could not rename interface '%d' from '%s' to '%s': %m", udev_device_get_ifindex(dev),
- udev_device_get_sysname(dev), event->name);
- else {
- r = udev_device_rename(dev, event->name);
- if (r < 0)
- log_warning_errno(r, "renamed interface '%d' from '%s' to '%s', but could not update udev_device: %m",
- udev_device_get_ifindex(dev), udev_device_get_sysname(dev), event->name);
- else
- log_debug("changed devpath to '%s'", udev_device_get_devpath(dev));
- }
- }
-
- if (major(udev_device_get_devnum(dev)) > 0) {
- bool apply;
-
- /* remove/update possible left-over symlinks from old database entry */
- if (event->dev_db != NULL)
- udev_node_update_old_links(dev, event->dev_db);
-
- if (!event->owner_set)
- event->uid = udev_device_get_devnode_uid(dev);
-
- if (!event->group_set)
- event->gid = udev_device_get_devnode_gid(dev);
-
- if (!event->mode_set) {
- if (udev_device_get_devnode_mode(dev) > 0) {
- /* kernel supplied value */
- event->mode = udev_device_get_devnode_mode(dev);
- } else if (event->gid > 0) {
- /* default 0660 if a group is assigned */
- event->mode = 0660;
- } else {
- /* default 0600 */
- event->mode = 0600;
- }
- }
-
- apply = streq(udev_device_get_action(dev), "add") || event->owner_set || event->group_set || event->mode_set;
- udev_node_add(dev, apply, event->mode, event->uid, event->gid, &event->seclabel_list);
- }
-
- /* preserve old, or get new initialization timestamp */
- udev_device_ensure_usec_initialized(event->dev, event->dev_db);
-
- /* (re)write database file */
- udev_device_tag_index(dev, event->dev_db, true);
- udev_device_update_db(dev);
- udev_device_set_is_initialized(dev);
-
- event->dev_db = udev_device_unref(event->dev_db);
- }
-}
-
-void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec) {
- struct udev_list_entry *list_entry;
-
- udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) {
- char command[UTIL_PATH_SIZE];
- const char *cmd = udev_list_entry_get_name(list_entry);
- enum udev_builtin_cmd builtin_cmd = udev_list_entry_get_num(list_entry);
-
- udev_event_apply_format(event, cmd, command, sizeof(command));
-
- if (builtin_cmd < UDEV_BUILTIN_MAX)
- udev_builtin_run(event->dev, builtin_cmd, command, false);
- else {
- if (event->exec_delay > 0) {
- log_debug("delay execution of '%s'", command);
- sleep(event->exec_delay);
- }
-
- udev_event_spawn(event, timeout_usec, timeout_warn_usec, false, command, NULL, 0);
- }
- }
-}
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
deleted file mode 100644
index 43004bc0bc..0000000000
--- a/src/udev/udev-node.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (C) 2003-2013 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "formats-util.h"
-#include "fs-util.h"
-#include "selinux-util.h"
-#include "smack-util.h"
-#include "stdio-util.h"
-#include "string-util.h"
-#include "udev.h"
-
-static int node_symlink(struct udev_device *dev, const char *node, const char *slink) {
- struct stat stats;
- char target[UTIL_PATH_SIZE];
- char *s;
- size_t l;
- char slink_tmp[UTIL_PATH_SIZE + 32];
- int i = 0;
- int tail = 0;
- int err = 0;
-
- /* use relative link */
- target[0] = '\0';
- while (node[i] && (node[i] == slink[i])) {
- if (node[i] == '/')
- tail = i+1;
- i++;
- }
- s = target;
- l = sizeof(target);
- while (slink[i] != '\0') {
- if (slink[i] == '/')
- l = strpcpy(&s, l, "../");
- i++;
- }
- l = strscpy(s, l, &node[tail]);
- if (l == 0) {
- err = -EINVAL;
- goto exit;
- }
-
- /* preserve link with correct target, do not replace node of other device */
- if (lstat(slink, &stats) == 0) {
- if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
- log_error("conflicting device node '%s' found, link to '%s' will not be created", slink, node);
- goto exit;
- } else if (S_ISLNK(stats.st_mode)) {
- char buf[UTIL_PATH_SIZE];
- int len;
-
- len = readlink(slink, buf, sizeof(buf));
- if (len > 0 && len < (int)sizeof(buf)) {
- buf[len] = '\0';
- if (streq(target, buf)) {
- log_debug("preserve already existing symlink '%s' to '%s'", slink, target);
- label_fix(slink, true, false);
- utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
- goto exit;
- }
- }
- }
- } else {
- log_debug("creating symlink '%s' to '%s'", slink, target);
- do {
- err = mkdir_parents_label(slink, 0755);
- if (err != 0 && err != -ENOENT)
- break;
- mac_selinux_create_file_prepare(slink, S_IFLNK);
- err = symlink(target, slink);
- if (err != 0)
- err = -errno;
- mac_selinux_create_file_clear();
- } while (err == -ENOENT);
- if (err == 0)
- goto exit;
- }
-
- log_debug("atomically replace '%s'", slink);
- strscpyl(slink_tmp, sizeof(slink_tmp), slink, ".tmp-", udev_device_get_id_filename(dev), NULL);
- unlink(slink_tmp);
- do {
- err = mkdir_parents_label(slink_tmp, 0755);
- if (err != 0 && err != -ENOENT)
- break;
- mac_selinux_create_file_prepare(slink_tmp, S_IFLNK);
- err = symlink(target, slink_tmp);
- if (err != 0)
- err = -errno;
- mac_selinux_create_file_clear();
- } while (err == -ENOENT);
- if (err != 0) {
- log_error_errno(errno, "symlink '%s' '%s' failed: %m", target, slink_tmp);
- goto exit;
- }
- err = rename(slink_tmp, slink);
- if (err != 0) {
- log_error_errno(errno, "rename '%s' '%s' failed: %m", slink_tmp, slink);
- unlink(slink_tmp);
- }
-exit:
- return err;
-}
-
-/* find device node of device with highest priority */
-static const char *link_find_prioritized(struct udev_device *dev, bool add, const char *stackdir, char *buf, size_t bufsize) {
- struct udev *udev = udev_device_get_udev(dev);
- DIR *dir;
- int priority = 0;
- const char *target = NULL;
-
- if (add) {
- priority = udev_device_get_devlink_priority(dev);
- strscpy(buf, bufsize, udev_device_get_devnode(dev));
- target = buf;
- }
-
- dir = opendir(stackdir);
- if (dir == NULL)
- return target;
- for (;;) {
- struct udev_device *dev_db;
- struct dirent *dent;
-
- dent = readdir(dir);
- if (dent == NULL || dent->d_name[0] == '\0')
- break;
- if (dent->d_name[0] == '.')
- continue;
-
- log_debug("found '%s' claiming '%s'", dent->d_name, stackdir);
-
- /* did we find ourself? */
- if (streq(dent->d_name, udev_device_get_id_filename(dev)))
- continue;
-
- dev_db = udev_device_new_from_device_id(udev, dent->d_name);
- if (dev_db != NULL) {
- const char *devnode;
-
- devnode = udev_device_get_devnode(dev_db);
- if (devnode != NULL) {
- if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) {
- log_debug("'%s' claims priority %i for '%s'",
- udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir);
- priority = udev_device_get_devlink_priority(dev_db);
- strscpy(buf, bufsize, devnode);
- target = buf;
- }
- }
- udev_device_unref(dev_db);
- }
- }
- closedir(dir);
- return target;
-}
-
-/* manage "stack of names" with possibly specified device priorities */
-static void link_update(struct udev_device *dev, const char *slink, bool add) {
- char name_enc[UTIL_PATH_SIZE];
- char filename[UTIL_PATH_SIZE * 2];
- char dirname[UTIL_PATH_SIZE];
- const char *target;
- char buf[UTIL_PATH_SIZE];
-
- util_path_encode(slink + strlen("/dev"), name_enc, sizeof(name_enc));
- strscpyl(dirname, sizeof(dirname), "/run/udev/links/", name_enc, NULL);
- strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL);
-
- if (!add && unlink(filename) == 0)
- rmdir(dirname);
-
- target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf));
- if (target == NULL) {
- log_debug("no reference left, remove '%s'", slink);
- if (unlink(slink) == 0)
- rmdir_parents(slink, "/");
- } else {
- log_debug("creating link '%s' to '%s'", slink, target);
- node_symlink(dev, target, slink);
- }
-
- if (add) {
- int err;
-
- do {
- int fd;
-
- err = mkdir_parents(filename, 0755);
- if (err != 0 && err != -ENOENT)
- break;
- fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
- if (fd >= 0)
- close(fd);
- else
- err = -errno;
- } while (err == -ENOENT);
- }
-}
-
-void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old) {
- struct udev_list_entry *list_entry;
-
- /* update possible left-over symlinks */
- udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev_old)) {
- const char *name = udev_list_entry_get_name(list_entry);
- struct udev_list_entry *list_entry_current;
- int found;
-
- /* check if old link name still belongs to this device */
- found = 0;
- udev_list_entry_foreach(list_entry_current, udev_device_get_devlinks_list_entry(dev)) {
- const char *name_current = udev_list_entry_get_name(list_entry_current);
-
- if (streq(name, name_current)) {
- found = 1;
- break;
- }
- }
- if (found)
- continue;
-
- log_debug("update old name, '%s' no longer belonging to '%s'",
- name, udev_device_get_devpath(dev));
- link_update(dev, name, false);
- }
-}
-
-static int node_permissions_apply(struct udev_device *dev, bool apply,
- mode_t mode, uid_t uid, gid_t gid,
- struct udev_list *seclabel_list) {
- const char *devnode = udev_device_get_devnode(dev);
- dev_t devnum = udev_device_get_devnum(dev);
- struct stat stats;
- struct udev_list_entry *entry;
- int err = 0;
-
- if (streq(udev_device_get_subsystem(dev), "block"))
- mode |= S_IFBLK;
- else
- mode |= S_IFCHR;
-
- if (lstat(devnode, &stats) != 0) {
- err = log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode);
- goto out;
- }
-
- if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) {
- err = -EEXIST;
- log_debug("found node '%s' with non-matching devnum %s, skip handling",
- udev_device_get_devnode(dev), udev_device_get_id_filename(dev));
- goto out;
- }
-
- if (apply) {
- bool selinux = false;
- bool smack = false;
-
- if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) {
- log_debug("set permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid);
- err = chmod(devnode, mode);
- if (err < 0)
- log_warning_errno(errno, "setting mode of %s to %#o failed: %m", devnode, mode);
- err = chown(devnode, uid, gid);
- if (err < 0)
- log_warning_errno(errno, "setting owner of %s to uid=%u, gid=%u failed: %m", devnode, uid, gid);
- } else {
- log_debug("preserve permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid);
- }
-
- /* apply SECLABEL{$module}=$label */
- udev_list_entry_foreach(entry, udev_list_get_entry(seclabel_list)) {
- const char *name, *label;
- int r;
-
- name = udev_list_entry_get_name(entry);
- label = udev_list_entry_get_value(entry);
-
- if (streq(name, "selinux")) {
- selinux = true;
-
- r = mac_selinux_apply(devnode, label);
- if (r < 0)
- log_error_errno(r, "SECLABEL: failed to set SELinux label '%s': %m", label);
- else
- log_debug("SECLABEL: set SELinux label '%s'", label);
-
- } else if (streq(name, "smack")) {
- smack = true;
-
- r = mac_smack_apply(devnode, SMACK_ATTR_ACCESS, label);
- if (r < 0)
- log_error_errno(r, "SECLABEL: failed to set SMACK label '%s': %m", label);
- else
- log_debug("SECLABEL: set SMACK label '%s'", label);
-
- } else
- log_error("SECLABEL: unknown subsystem, ignoring '%s'='%s'", name, label);
- }
-
- /* set the defaults */
- if (!selinux)
- mac_selinux_fix(devnode, true, false);
- if (!smack)
- mac_smack_apply(devnode, SMACK_ATTR_ACCESS, NULL);
- }
-
- /* always update timestamp when we re-use the node, like on media change events */
- utimensat(AT_FDCWD, devnode, NULL, 0);
-out:
- return err;
-}
-
-void udev_node_add(struct udev_device *dev, bool apply,
- mode_t mode, uid_t uid, gid_t gid,
- struct udev_list *seclabel_list) {
- char filename[sizeof("/dev/block/:") + 2*DECIMAL_STR_MAX(unsigned)];
- struct udev_list_entry *list_entry;
-
- log_debug("handling device node '%s', devnum=%s, mode=%#o, uid="UID_FMT", gid="GID_FMT,
- udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid);
-
- if (node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list) < 0)
- return;
-
- /* always add /dev/{block,char}/$major:$minor */
- xsprintf(filename, "/dev/%s/%u:%u",
- streq(udev_device_get_subsystem(dev), "block") ? "block" : "char",
- major(udev_device_get_devnum(dev)),
- minor(udev_device_get_devnum(dev)));
- node_symlink(dev, udev_device_get_devnode(dev), filename);
-
- /* create/update symlinks, add symlinks to name index */
- udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev))
- link_update(dev, udev_list_entry_get_name(list_entry), true);
-}
-
-void udev_node_remove(struct udev_device *dev) {
- struct udev_list_entry *list_entry;
- char filename[sizeof("/dev/block/:") + 2*DECIMAL_STR_MAX(unsigned)];
-
- /* remove/update symlinks, remove symlinks from name index */
- udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev))
- link_update(dev, udev_list_entry_get_name(list_entry), false);
-
- /* remove /dev/{block,char}/$major:$minor */
- xsprintf(filename, "/dev/%s/%u:%u",
- streq(udev_device_get_subsystem(dev), "block") ? "block" : "char",
- major(udev_device_get_devnum(dev)),
- minor(udev_device_get_devnum(dev)));
- unlink(filename);
-}
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
deleted file mode 100644
index f6c416bf70..0000000000
--- a/src/udev/udev-rules.c
+++ /dev/null
@@ -1,2582 +0,0 @@
-/*
- * Copyright (C) 2003-2012 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <fnmatch.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "conf-files.h"
-#include "escape.h"
-#include "fd-util.h"
-#include "fs-util.h"
-#include "glob-util.h"
-#include "path-util.h"
-#include "stat-util.h"
-#include "stdio-util.h"
-#include "strbuf.h"
-#include "string-util.h"
-#include "strv.h"
-#include "sysctl-util.h"
-#include "udev.h"
-#include "user-util.h"
-#include "util.h"
-
-#define PREALLOC_TOKEN 2048
-
-struct uid_gid {
- unsigned int name_off;
- union {
- uid_t uid;
- gid_t gid;
- };
-};
-
-static const char* const rules_dirs[] = {
- "/etc/udev/rules.d",
- "/run/udev/rules.d",
- UDEVLIBEXECDIR "/rules.d",
- NULL
-};
-
-struct udev_rules {
- struct udev *udev;
- usec_t dirs_ts_usec;
- int resolve_names;
-
- /* every key in the rules file becomes a token */
- struct token *tokens;
- unsigned int token_cur;
- unsigned int token_max;
-
- /* all key strings are copied and de-duplicated in a single continuous string buffer */
- struct strbuf *strbuf;
-
- /* during rule parsing, uid/gid lookup results are cached */
- struct uid_gid *uids;
- unsigned int uids_cur;
- unsigned int uids_max;
- struct uid_gid *gids;
- unsigned int gids_cur;
- unsigned int gids_max;
-};
-
-static char *rules_str(struct udev_rules *rules, unsigned int off) {
- return rules->strbuf->buf + off;
-}
-
-static unsigned int rules_add_string(struct udev_rules *rules, const char *s) {
- return strbuf_add_string(rules->strbuf, s, strlen(s));
-}
-
-/* KEY=="", KEY!="", KEY+="", KEY-="", KEY="", KEY:="" */
-enum operation_type {
- OP_UNSET,
-
- OP_MATCH,
- OP_NOMATCH,
- OP_MATCH_MAX,
-
- OP_ADD,
- OP_REMOVE,
- OP_ASSIGN,
- OP_ASSIGN_FINAL,
-};
-
-enum string_glob_type {
- GL_UNSET,
- GL_PLAIN, /* no special chars */
- GL_GLOB, /* shell globs ?,*,[] */
- GL_SPLIT, /* multi-value A|B */
- GL_SPLIT_GLOB, /* multi-value with glob A*|B* */
- GL_SOMETHING, /* commonly used "?*" */
-};
-
-enum string_subst_type {
- SB_UNSET,
- SB_NONE,
- SB_FORMAT,
- SB_SUBSYS,
-};
-
-/* tokens of a rule are sorted/handled in this order */
-enum token_type {
- TK_UNSET,
- TK_RULE,
-
- TK_M_ACTION, /* val */
- TK_M_DEVPATH, /* val */
- TK_M_KERNEL, /* val */
- TK_M_DEVLINK, /* val */
- TK_M_NAME, /* val */
- TK_M_ENV, /* val, attr */
- TK_M_TAG, /* val */
- TK_M_SUBSYSTEM, /* val */
- TK_M_DRIVER, /* val */
- TK_M_WAITFOR, /* val */
- TK_M_ATTR, /* val, attr */
- TK_M_SYSCTL, /* val, attr */
-
- TK_M_PARENTS_MIN,
- TK_M_KERNELS, /* val */
- TK_M_SUBSYSTEMS, /* val */
- TK_M_DRIVERS, /* val */
- TK_M_ATTRS, /* val, attr */
- TK_M_TAGS, /* val */
- TK_M_PARENTS_MAX,
-
- TK_M_TEST, /* val, mode_t */
- TK_M_PROGRAM, /* val */
- TK_M_IMPORT_FILE, /* val */
- TK_M_IMPORT_PROG, /* val */
- TK_M_IMPORT_BUILTIN, /* val */
- TK_M_IMPORT_DB, /* val */
- TK_M_IMPORT_CMDLINE, /* val */
- TK_M_IMPORT_PARENT, /* val */
- TK_M_RESULT, /* val */
- TK_M_MAX,
-
- TK_A_STRING_ESCAPE_NONE,
- TK_A_STRING_ESCAPE_REPLACE,
- TK_A_DB_PERSIST,
- TK_A_INOTIFY_WATCH, /* int */
- TK_A_DEVLINK_PRIO, /* int */
- TK_A_OWNER, /* val */
- TK_A_GROUP, /* val */
- TK_A_MODE, /* val */
- TK_A_OWNER_ID, /* uid_t */
- TK_A_GROUP_ID, /* gid_t */
- TK_A_MODE_ID, /* mode_t */
- TK_A_TAG, /* val */
- TK_A_STATIC_NODE, /* val */
- TK_A_SECLABEL, /* val, attr */
- TK_A_ENV, /* val, attr */
- TK_A_NAME, /* val */
- TK_A_DEVLINK, /* val */
- TK_A_ATTR, /* val, attr */
- TK_A_SYSCTL, /* val, attr */
- TK_A_RUN_BUILTIN, /* val, bool */
- TK_A_RUN_PROGRAM, /* val, bool */
- TK_A_GOTO, /* size_t */
-
- TK_END,
-};
-
-/* we try to pack stuff in a way that we take only 12 bytes per token */
-struct token {
- union {
- unsigned char type; /* same in rule and key */
- struct {
- enum token_type type:8;
- bool can_set_name:1;
- bool has_static_node:1;
- unsigned int unused:6;
- unsigned short token_count;
- unsigned int label_off;
- unsigned short filename_off;
- unsigned short filename_line;
- } rule;
- struct {
- enum token_type type:8;
- enum operation_type op:8;
- enum string_glob_type glob:8;
- enum string_subst_type subst:4;
- enum string_subst_type attrsubst:4;
- unsigned int value_off;
- union {
- unsigned int attr_off;
- unsigned int rule_goto;
- mode_t mode;
- uid_t uid;
- gid_t gid;
- int devlink_prio;
- int watch;
- enum udev_builtin_cmd builtin_cmd;
- };
- } key;
- };
-};
-
-#define MAX_TK 64
-struct rule_tmp {
- struct udev_rules *rules;
- struct token rule;
- struct token token[MAX_TK];
- unsigned int token_cur;
-};
-
-#ifdef DEBUG
-static const char *operation_str(enum operation_type type) {
- static const char *operation_strs[] = {
- [OP_UNSET] = "UNSET",
- [OP_MATCH] = "match",
- [OP_NOMATCH] = "nomatch",
- [OP_MATCH_MAX] = "MATCH_MAX",
-
- [OP_ADD] = "add",
- [OP_REMOVE] = "remove",
- [OP_ASSIGN] = "assign",
- [OP_ASSIGN_FINAL] = "assign-final",
-} ;
-
- return operation_strs[type];
-}
-
-static const char *string_glob_str(enum string_glob_type type) {
- static const char *string_glob_strs[] = {
- [GL_UNSET] = "UNSET",
- [GL_PLAIN] = "plain",
- [GL_GLOB] = "glob",
- [GL_SPLIT] = "split",
- [GL_SPLIT_GLOB] = "split-glob",
- [GL_SOMETHING] = "split-glob",
- };
-
- return string_glob_strs[type];
-}
-
-static const char *token_str(enum token_type type) {
- static const char *token_strs[] = {
- [TK_UNSET] = "UNSET",
- [TK_RULE] = "RULE",
-
- [TK_M_ACTION] = "M ACTION",
- [TK_M_DEVPATH] = "M DEVPATH",
- [TK_M_KERNEL] = "M KERNEL",
- [TK_M_DEVLINK] = "M DEVLINK",
- [TK_M_NAME] = "M NAME",
- [TK_M_ENV] = "M ENV",
- [TK_M_TAG] = "M TAG",
- [TK_M_SUBSYSTEM] = "M SUBSYSTEM",
- [TK_M_DRIVER] = "M DRIVER",
- [TK_M_WAITFOR] = "M WAITFOR",
- [TK_M_ATTR] = "M ATTR",
- [TK_M_SYSCTL] = "M SYSCTL",
-
- [TK_M_PARENTS_MIN] = "M PARENTS_MIN",
- [TK_M_KERNELS] = "M KERNELS",
- [TK_M_SUBSYSTEMS] = "M SUBSYSTEMS",
- [TK_M_DRIVERS] = "M DRIVERS",
- [TK_M_ATTRS] = "M ATTRS",
- [TK_M_TAGS] = "M TAGS",
- [TK_M_PARENTS_MAX] = "M PARENTS_MAX",
-
- [TK_M_TEST] = "M TEST",
- [TK_M_PROGRAM] = "M PROGRAM",
- [TK_M_IMPORT_FILE] = "M IMPORT_FILE",
- [TK_M_IMPORT_PROG] = "M IMPORT_PROG",
- [TK_M_IMPORT_BUILTIN] = "M IMPORT_BUILTIN",
- [TK_M_IMPORT_DB] = "M IMPORT_DB",
- [TK_M_IMPORT_CMDLINE] = "M IMPORT_CMDLINE",
- [TK_M_IMPORT_PARENT] = "M IMPORT_PARENT",
- [TK_M_RESULT] = "M RESULT",
- [TK_M_MAX] = "M MAX",
-
- [TK_A_STRING_ESCAPE_NONE] = "A STRING_ESCAPE_NONE",
- [TK_A_STRING_ESCAPE_REPLACE] = "A STRING_ESCAPE_REPLACE",
- [TK_A_DB_PERSIST] = "A DB_PERSIST",
- [TK_A_INOTIFY_WATCH] = "A INOTIFY_WATCH",
- [TK_A_DEVLINK_PRIO] = "A DEVLINK_PRIO",
- [TK_A_OWNER] = "A OWNER",
- [TK_A_GROUP] = "A GROUP",
- [TK_A_MODE] = "A MODE",
- [TK_A_OWNER_ID] = "A OWNER_ID",
- [TK_A_GROUP_ID] = "A GROUP_ID",
- [TK_A_STATIC_NODE] = "A STATIC_NODE",
- [TK_A_SECLABEL] = "A SECLABEL",
- [TK_A_MODE_ID] = "A MODE_ID",
- [TK_A_ENV] = "A ENV",
- [TK_A_TAG] = "A ENV",
- [TK_A_NAME] = "A NAME",
- [TK_A_DEVLINK] = "A DEVLINK",
- [TK_A_ATTR] = "A ATTR",
- [TK_A_SYSCTL] = "A SYSCTL",
- [TK_A_RUN_BUILTIN] = "A RUN_BUILTIN",
- [TK_A_RUN_PROGRAM] = "A RUN_PROGRAM",
- [TK_A_GOTO] = "A GOTO",
-
- [TK_END] = "END",
- };
-
- return token_strs[type];
-}
-
-static void dump_token(struct udev_rules *rules, struct token *token) {
- enum token_type type = token->type;
- enum operation_type op = token->key.op;
- enum string_glob_type glob = token->key.glob;
- const char *value = rules_str(rules, token->key.value_off);
- const char *attr = &rules->strbuf->buf[token->key.attr_off];
-
- switch (type) {
- case TK_RULE:
- {
- const char *tks_ptr = (char *)rules->tokens;
- const char *tk_ptr = (char *)token;
- unsigned int idx = (tk_ptr - tks_ptr) / sizeof(struct token);
-
- log_debug("* RULE %s:%u, token: %u, count: %u, label: '%s'",
- &rules->strbuf->buf[token->rule.filename_off], token->rule.filename_line,
- idx, token->rule.token_count,
- &rules->strbuf->buf[token->rule.label_off]);
- break;
- }
- case TK_M_ACTION:
- case TK_M_DEVPATH:
- case TK_M_KERNEL:
- case TK_M_SUBSYSTEM:
- case TK_M_DRIVER:
- case TK_M_WAITFOR:
- case TK_M_DEVLINK:
- case TK_M_NAME:
- case TK_M_KERNELS:
- case TK_M_SUBSYSTEMS:
- case TK_M_DRIVERS:
- case TK_M_TAGS:
- case TK_M_PROGRAM:
- case TK_M_IMPORT_FILE:
- case TK_M_IMPORT_PROG:
- case TK_M_IMPORT_DB:
- case TK_M_IMPORT_CMDLINE:
- case TK_M_IMPORT_PARENT:
- case TK_M_RESULT:
- case TK_A_NAME:
- case TK_A_DEVLINK:
- case TK_A_OWNER:
- case TK_A_GROUP:
- case TK_A_MODE:
- case TK_A_RUN_BUILTIN:
- case TK_A_RUN_PROGRAM:
- log_debug("%s %s '%s'(%s)",
- token_str(type), operation_str(op), value, string_glob_str(glob));
- break;
- case TK_M_IMPORT_BUILTIN:
- log_debug("%s %i '%s'", token_str(type), token->key.builtin_cmd, value);
- break;
- case TK_M_ATTR:
- case TK_M_SYSCTL:
- case TK_M_ATTRS:
- case TK_M_ENV:
- case TK_A_ATTR:
- case TK_A_SYSCTL:
- case TK_A_ENV:
- log_debug("%s %s '%s' '%s'(%s)",
- token_str(type), operation_str(op), attr, value, string_glob_str(glob));
- break;
- case TK_M_TAG:
- case TK_A_TAG:
- log_debug("%s %s '%s'", token_str(type), operation_str(op), value);
- break;
- case TK_A_STRING_ESCAPE_NONE:
- case TK_A_STRING_ESCAPE_REPLACE:
- case TK_A_DB_PERSIST:
- log_debug("%s", token_str(type));
- break;
- case TK_M_TEST:
- log_debug("%s %s '%s'(%s) %#o",
- token_str(type), operation_str(op), value, string_glob_str(glob), token->key.mode);
- break;
- case TK_A_INOTIFY_WATCH:
- log_debug("%s %u", token_str(type), token->key.watch);
- break;
- case TK_A_DEVLINK_PRIO:
- log_debug("%s %u", token_str(type), token->key.devlink_prio);
- break;
- case TK_A_OWNER_ID:
- log_debug("%s %s %u", token_str(type), operation_str(op), token->key.uid);
- break;
- case TK_A_GROUP_ID:
- log_debug("%s %s %u", token_str(type), operation_str(op), token->key.gid);
- break;
- case TK_A_MODE_ID:
- log_debug("%s %s %#o", token_str(type), operation_str(op), token->key.mode);
- break;
- case TK_A_STATIC_NODE:
- log_debug("%s '%s'", token_str(type), value);
- break;
- case TK_A_SECLABEL:
- log_debug("%s %s '%s' '%s'", token_str(type), operation_str(op), attr, value);
- break;
- case TK_A_GOTO:
- log_debug("%s '%s' %u", token_str(type), value, token->key.rule_goto);
- break;
- case TK_END:
- log_debug("* %s", token_str(type));
- break;
- case TK_M_PARENTS_MIN:
- case TK_M_PARENTS_MAX:
- case TK_M_MAX:
- case TK_UNSET:
- log_debug("unknown type %u", type);
- break;
- }
-}
-
-static void dump_rules(struct udev_rules *rules) {
- unsigned int i;
-
- log_debug("dumping %u (%zu bytes) tokens, %zu (%zu bytes) strings",
- rules->token_cur,
- rules->token_cur * sizeof(struct token),
- rules->strbuf->nodes_count,
- rules->strbuf->len);
- for (i = 0; i < rules->token_cur; i++)
- dump_token(rules, &rules->tokens[i]);
-}
-#else
-static inline void dump_token(struct udev_rules *rules, struct token *token) {}
-static inline void dump_rules(struct udev_rules *rules) {}
-#endif /* DEBUG */
-
-static int add_token(struct udev_rules *rules, struct token *token) {
- /* grow buffer if needed */
- if (rules->token_cur+1 >= rules->token_max) {
- struct token *tokens;
- unsigned int add;
-
- /* double the buffer size */
- add = rules->token_max;
- if (add < 8)
- add = 8;
-
- tokens = realloc(rules->tokens, (rules->token_max + add ) * sizeof(struct token));
- if (tokens == NULL)
- return -1;
- rules->tokens = tokens;
- rules->token_max += add;
- }
- memcpy(&rules->tokens[rules->token_cur], token, sizeof(struct token));
- rules->token_cur++;
- return 0;
-}
-
-static uid_t add_uid(struct udev_rules *rules, const char *owner) {
- unsigned int i;
- uid_t uid = 0;
- unsigned int off;
- int r;
-
- /* lookup, if we know it already */
- for (i = 0; i < rules->uids_cur; i++) {
- off = rules->uids[i].name_off;
- if (streq(rules_str(rules, off), owner)) {
- uid = rules->uids[i].uid;
- return uid;
- }
- }
- r = get_user_creds(&owner, &uid, NULL, NULL, NULL);
- if (r < 0) {
- if (r == -ENOENT || r == -ESRCH)
- log_error("specified user '%s' unknown", owner);
- else
- log_error_errno(r, "error resolving user '%s': %m", owner);
- }
-
- /* grow buffer if needed */
- if (rules->uids_cur+1 >= rules->uids_max) {
- struct uid_gid *uids;
- unsigned int add;
-
- /* double the buffer size */
- add = rules->uids_max;
- if (add < 1)
- add = 8;
-
- uids = realloc(rules->uids, (rules->uids_max + add ) * sizeof(struct uid_gid));
- if (uids == NULL)
- return uid;
- rules->uids = uids;
- rules->uids_max += add;
- }
- rules->uids[rules->uids_cur].uid = uid;
- off = rules_add_string(rules, owner);
- if (off <= 0)
- return uid;
- rules->uids[rules->uids_cur].name_off = off;
- rules->uids_cur++;
- return uid;
-}
-
-static gid_t add_gid(struct udev_rules *rules, const char *group) {
- unsigned int i;
- gid_t gid = 0;
- unsigned int off;
- int r;
-
- /* lookup, if we know it already */
- for (i = 0; i < rules->gids_cur; i++) {
- off = rules->gids[i].name_off;
- if (streq(rules_str(rules, off), group)) {
- gid = rules->gids[i].gid;
- return gid;
- }
- }
- r = get_group_creds(&group, &gid);
- if (r < 0) {
- if (r == -ENOENT || r == -ESRCH)
- log_error("specified group '%s' unknown", group);
- else
- log_error_errno(r, "error resolving group '%s': %m", group);
- }
-
- /* grow buffer if needed */
- if (rules->gids_cur+1 >= rules->gids_max) {
- struct uid_gid *gids;
- unsigned int add;
-
- /* double the buffer size */
- add = rules->gids_max;
- if (add < 1)
- add = 8;
-
- gids = realloc(rules->gids, (rules->gids_max + add ) * sizeof(struct uid_gid));
- if (gids == NULL)
- return gid;
- rules->gids = gids;
- rules->gids_max += add;
- }
- rules->gids[rules->gids_cur].gid = gid;
- off = rules_add_string(rules, group);
- if (off <= 0)
- return gid;
- rules->gids[rules->gids_cur].name_off = off;
- rules->gids_cur++;
- return gid;
-}
-
-static int import_property_from_string(struct udev_device *dev, char *line) {
- char *key;
- char *val;
- size_t len;
-
- /* find key */
- key = line;
- while (isspace(key[0]))
- key++;
-
- /* comment or empty line */
- if (key[0] == '#' || key[0] == '\0')
- return -1;
-
- /* split key/value */
- val = strchr(key, '=');
- if (val == NULL)
- return -1;
- val[0] = '\0';
- val++;
-
- /* find value */
- while (isspace(val[0]))
- val++;
-
- /* terminate key */
- len = strlen(key);
- if (len == 0)
- return -1;
- while (isspace(key[len-1]))
- len--;
- key[len] = '\0';
-
- /* terminate value */
- len = strlen(val);
- if (len == 0)
- return -1;
- while (isspace(val[len-1]))
- len--;
- val[len] = '\0';
-
- if (len == 0)
- return -1;
-
- /* unquote */
- if (val[0] == '"' || val[0] == '\'') {
- if (val[len-1] != val[0]) {
- log_debug("inconsistent quoting: '%s', skip", line);
- return -1;
- }
- val[len-1] = '\0';
- val++;
- }
-
- udev_device_add_property(dev, key, val);
-
- return 0;
-}
-
-static int import_file_into_properties(struct udev_device *dev, const char *filename) {
- FILE *f;
- char line[UTIL_LINE_SIZE];
-
- f = fopen(filename, "re");
- if (f == NULL)
- return -1;
- while (fgets(line, sizeof(line), f) != NULL)
- import_property_from_string(dev, line);
- fclose(f);
- return 0;
-}
-
-static int import_program_into_properties(struct udev_event *event,
- usec_t timeout_usec,
- usec_t timeout_warn_usec,
- const char *program) {
- char result[UTIL_LINE_SIZE];
- char *line;
- int err;
-
- err = udev_event_spawn(event, timeout_usec, timeout_warn_usec, true, program, result, sizeof(result));
- if (err < 0)
- return err;
-
- line = result;
- while (line != NULL) {
- char *pos;
-
- pos = strchr(line, '\n');
- if (pos != NULL) {
- pos[0] = '\0';
- pos = &pos[1];
- }
- import_property_from_string(event->dev, line);
- line = pos;
- }
- return 0;
-}
-
-static int import_parent_into_properties(struct udev_device *dev, const char *filter) {
- struct udev_device *dev_parent;
- struct udev_list_entry *list_entry;
-
- assert(dev);
- assert(filter);
-
- dev_parent = udev_device_get_parent(dev);
- if (dev_parent == NULL)
- return -1;
-
- udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(dev_parent)) {
- const char *key = udev_list_entry_get_name(list_entry);
- const char *val = udev_list_entry_get_value(list_entry);
-
- if (fnmatch(filter, key, 0) == 0)
- udev_device_add_property(dev, key, val);
- }
- return 0;
-}
-
-static void attr_subst_subdir(char *attr, size_t len) {
- const char *pos, *tail, *path;
- _cleanup_closedir_ DIR *dir = NULL;
- struct dirent *dent;
-
- pos = strstr(attr, "/*/");
- if (!pos)
- return;
-
- tail = pos + 2;
- path = strndupa(attr, pos - attr + 1); /* include slash at end */
- dir = opendir(path);
- if (dir == NULL)
- return;
-
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir))
- if (dent->d_name[0] != '.') {
- char n[strlen(dent->d_name) + strlen(tail) + 1];
-
- strscpyl(n, sizeof n, dent->d_name, tail, NULL);
- if (faccessat(dirfd(dir), n, F_OK, 0) == 0) {
- strscpyl(attr, len, path, n, NULL);
- break;
- }
- }
-}
-
-static int get_key(struct udev *udev, char **line, char **key, enum operation_type *op, char **value) {
- char *linepos;
- char *temp;
-
- linepos = *line;
- if (linepos == NULL || linepos[0] == '\0')
- return -1;
-
- /* skip whitespace */
- while (isspace(linepos[0]) || linepos[0] == ',')
- linepos++;
-
- /* get the key */
- if (linepos[0] == '\0')
- return -1;
- *key = linepos;
-
- for (;;) {
- linepos++;
- if (linepos[0] == '\0')
- return -1;
- if (isspace(linepos[0]))
- break;
- if (linepos[0] == '=')
- break;
- if ((linepos[0] == '+') || (linepos[0] == '-') || (linepos[0] == '!') || (linepos[0] == ':'))
- if (linepos[1] == '=')
- break;
- }
-
- /* remember end of key */
- temp = linepos;
-
- /* skip whitespace after key */
- while (isspace(linepos[0]))
- linepos++;
- if (linepos[0] == '\0')
- return -1;
-
- /* get operation type */
- if (linepos[0] == '=' && linepos[1] == '=') {
- *op = OP_MATCH;
- linepos += 2;
- } else if (linepos[0] == '!' && linepos[1] == '=') {
- *op = OP_NOMATCH;
- linepos += 2;
- } else if (linepos[0] == '+' && linepos[1] == '=') {
- *op = OP_ADD;
- linepos += 2;
- } else if (linepos[0] == '-' && linepos[1] == '=') {
- *op = OP_REMOVE;
- linepos += 2;
- } else if (linepos[0] == '=') {
- *op = OP_ASSIGN;
- linepos++;
- } else if (linepos[0] == ':' && linepos[1] == '=') {
- *op = OP_ASSIGN_FINAL;
- linepos += 2;
- } else
- return -1;
-
- /* terminate key */
- temp[0] = '\0';
-
- /* skip whitespace after operator */
- while (isspace(linepos[0]))
- linepos++;
- if (linepos[0] == '\0')
- return -1;
-
- /* get the value */
- if (linepos[0] == '"')
- linepos++;
- else
- return -1;
- *value = linepos;
-
- /* terminate */
- temp = strchr(linepos, '"');
- if (!temp)
- return -1;
- temp[0] = '\0';
- temp++;
-
- /* move line to next key */
- *line = temp;
- return 0;
-}
-
-/* extract possible KEY{attr} */
-static const char *get_key_attribute(struct udev *udev, char *str) {
- char *pos;
- char *attr;
-
- attr = strchr(str, '{');
- if (attr != NULL) {
- attr++;
- pos = strchr(attr, '}');
- if (pos == NULL) {
- log_error("missing closing brace for format");
- return NULL;
- }
- pos[0] = '\0';
- return attr;
- }
- return NULL;
-}
-
-static void rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
- enum operation_type op,
- const char *value, const void *data) {
- struct token *token = rule_tmp->token + rule_tmp->token_cur;
- const char *attr = NULL;
-
- assert(rule_tmp->token_cur < ELEMENTSOF(rule_tmp->token));
- memzero(token, sizeof(struct token));
-
- switch (type) {
- case TK_M_ACTION:
- case TK_M_DEVPATH:
- case TK_M_KERNEL:
- case TK_M_SUBSYSTEM:
- case TK_M_DRIVER:
- case TK_M_WAITFOR:
- case TK_M_DEVLINK:
- case TK_M_NAME:
- case TK_M_KERNELS:
- case TK_M_SUBSYSTEMS:
- case TK_M_DRIVERS:
- case TK_M_TAGS:
- case TK_M_PROGRAM:
- case TK_M_IMPORT_FILE:
- case TK_M_IMPORT_PROG:
- case TK_M_IMPORT_DB:
- case TK_M_IMPORT_CMDLINE:
- case TK_M_IMPORT_PARENT:
- case TK_M_RESULT:
- case TK_A_OWNER:
- case TK_A_GROUP:
- case TK_A_MODE:
- case TK_A_DEVLINK:
- case TK_A_NAME:
- case TK_A_GOTO:
- case TK_M_TAG:
- case TK_A_TAG:
- case TK_A_STATIC_NODE:
- token->key.value_off = rules_add_string(rule_tmp->rules, value);
- break;
- case TK_M_IMPORT_BUILTIN:
- token->key.value_off = rules_add_string(rule_tmp->rules, value);
- token->key.builtin_cmd = *(enum udev_builtin_cmd *)data;
- break;
- case TK_M_ENV:
- case TK_M_ATTR:
- case TK_M_SYSCTL:
- case TK_M_ATTRS:
- case TK_A_ATTR:
- case TK_A_SYSCTL:
- case TK_A_ENV:
- case TK_A_SECLABEL:
- attr = data;
- token->key.value_off = rules_add_string(rule_tmp->rules, value);
- token->key.attr_off = rules_add_string(rule_tmp->rules, attr);
- break;
- case TK_M_TEST:
- token->key.value_off = rules_add_string(rule_tmp->rules, value);
- if (data != NULL)
- token->key.mode = *(mode_t *)data;
- break;
- case TK_A_STRING_ESCAPE_NONE:
- case TK_A_STRING_ESCAPE_REPLACE:
- case TK_A_DB_PERSIST:
- break;
- case TK_A_RUN_BUILTIN:
- case TK_A_RUN_PROGRAM:
- token->key.builtin_cmd = *(enum udev_builtin_cmd *)data;
- token->key.value_off = rules_add_string(rule_tmp->rules, value);
- break;
- case TK_A_INOTIFY_WATCH:
- case TK_A_DEVLINK_PRIO:
- token->key.devlink_prio = *(int *)data;
- break;
- case TK_A_OWNER_ID:
- token->key.uid = *(uid_t *)data;
- break;
- case TK_A_GROUP_ID:
- token->key.gid = *(gid_t *)data;
- break;
- case TK_A_MODE_ID:
- token->key.mode = *(mode_t *)data;
- break;
- case TK_RULE:
- case TK_M_PARENTS_MIN:
- case TK_M_PARENTS_MAX:
- case TK_M_MAX:
- case TK_END:
- case TK_UNSET:
- assert_not_reached("wrong type");
- }
-
- if (value != NULL && type < TK_M_MAX) {
- /* check if we need to split or call fnmatch() while matching rules */
- enum string_glob_type glob;
- int has_split;
- int has_glob;
-
- has_split = (strchr(value, '|') != NULL);
- has_glob = string_is_glob(value);
- if (has_split && has_glob) {
- glob = GL_SPLIT_GLOB;
- } else if (has_split) {
- glob = GL_SPLIT;
- } else if (has_glob) {
- if (streq(value, "?*"))
- glob = GL_SOMETHING;
- else
- glob = GL_GLOB;
- } else {
- glob = GL_PLAIN;
- }
- token->key.glob = glob;
- }
-
- if (value != NULL && type > TK_M_MAX) {
- /* check if assigned value has substitution chars */
- if (value[0] == '[')
- token->key.subst = SB_SUBSYS;
- else if (strchr(value, '%') != NULL || strchr(value, '$') != NULL)
- token->key.subst = SB_FORMAT;
- else
- token->key.subst = SB_NONE;
- }
-
- if (attr != NULL) {
- /* check if property/attribute name has substitution chars */
- if (attr[0] == '[')
- token->key.attrsubst = SB_SUBSYS;
- else if (strchr(attr, '%') != NULL || strchr(attr, '$') != NULL)
- token->key.attrsubst = SB_FORMAT;
- else
- token->key.attrsubst = SB_NONE;
- }
-
- token->key.type = type;
- token->key.op = op;
- rule_tmp->token_cur++;
-}
-
-static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp) {
- unsigned int i;
- unsigned int start = 0;
- unsigned int end = rule_tmp->token_cur;
-
- for (i = 0; i < rule_tmp->token_cur; i++) {
- enum token_type next_val = TK_UNSET;
- unsigned int next_idx = 0;
- unsigned int j;
-
- /* find smallest value */
- for (j = start; j < end; j++) {
- if (rule_tmp->token[j].type == TK_UNSET)
- continue;
- if (next_val == TK_UNSET || rule_tmp->token[j].type < next_val) {
- next_val = rule_tmp->token[j].type;
- next_idx = j;
- }
- }
-
- /* add token and mark done */
- if (add_token(rules, &rule_tmp->token[next_idx]) != 0)
- return -1;
- rule_tmp->token[next_idx].type = TK_UNSET;
-
- /* shrink range */
- if (next_idx == start)
- start++;
- if (next_idx+1 == end)
- end--;
- }
- return 0;
-}
-
-#define LOG_RULE_ERROR(fmt, ...) log_error("Invalid rule %s:%u: " fmt, filename, lineno, ##__VA_ARGS__)
-#define LOG_RULE_WARNING(fmt, ...) log_warning("%s:%u: " fmt, filename, lineno, ##__VA_ARGS__)
-#define LOG_RULE_DEBUG(fmt, ...) log_debug("%s:%u: " fmt, filename, lineno, ##__VA_ARGS__)
-#define LOG_AND_RETURN(fmt, ...) { LOG_RULE_ERROR(fmt, __VA_ARGS__); return; }
-
-static void add_rule(struct udev_rules *rules, char *line,
- const char *filename, unsigned int filename_off, unsigned int lineno) {
- char *linepos;
- const char *attr;
- struct rule_tmp rule_tmp = {
- .rules = rules,
- .rule.type = TK_RULE,
- };
-
- /* the offset in the rule is limited to unsigned short */
- if (filename_off < USHRT_MAX)
- rule_tmp.rule.rule.filename_off = filename_off;
- rule_tmp.rule.rule.filename_line = lineno;
-
- linepos = line;
- for (;;) {
- char *key;
- char *value;
- enum operation_type op;
-
- if (get_key(rules->udev, &linepos, &key, &op, &value) != 0) {
- /* Avoid erroring on trailing whitespace. This is probably rare
- * so save the work for the error case instead of always trying
- * to strip the trailing whitespace with strstrip(). */
- while (isblank(*linepos))
- linepos++;
-
- /* If we aren't at the end of the line, this is a parsing error.
- * Make a best effort to describe where the problem is. */
- if (!strchr(NEWLINE, *linepos)) {
- char buf[2] = {*linepos};
- _cleanup_free_ char *tmp;
-
- tmp = cescape(buf);
- log_error("invalid key/value pair in file %s on line %u, starting at character %tu ('%s')",
- filename, lineno, linepos - line + 1, tmp);
- if (*linepos == '#')
- log_error("hint: comments can only start at beginning of line");
- }
- break;
- }
-
- if (rule_tmp.token_cur >= ELEMENTSOF(rule_tmp.token))
- LOG_AND_RETURN("temporary rule array too small, aborting event processing with %u items", rule_tmp.token_cur);
-
- if (streq(key, "ACTION")) {
- if (op > OP_MATCH_MAX)
- LOG_AND_RETURN("invalid %s operation", key);
-
- rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL);
-
- } else if (streq(key, "DEVPATH")) {
- if (op > OP_MATCH_MAX)
- LOG_AND_RETURN("invalid %s operation", key);
-
- rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL);
-
- } else if (streq(key, "KERNEL")) {
- if (op > OP_MATCH_MAX)
- LOG_AND_RETURN("invalid %s operation", key);
-
- rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL);
-
- } else if (streq(key, "SUBSYSTEM")) {
- if (op > OP_MATCH_MAX)
- LOG_AND_RETURN("invalid %s operation", key);
-
- /* bus, class, subsystem events should all be the same */
- if (STR_IN_SET(value, "subsystem", "bus", "class")) {
- if (!streq(value, "subsystem"))
- LOG_RULE_WARNING("'%s' must be specified as 'subsystem'; please fix", value);
-
- rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL);
- } else
- rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL);
-
- } else if (streq(key, "DRIVER")) {
- if (op > OP_MATCH_MAX)
- LOG_AND_RETURN("invalid %s operation", key);
-
- rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL);
-
- } else if (startswith(key, "ATTR{")) {
- attr = get_key_attribute(rules->udev, key + strlen("ATTR"));
- if (attr == NULL)
- LOG_AND_RETURN("error parsing %s attribute", "ATTR");
-
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", "ATTR");
-
- if (op < OP_MATCH_MAX)
- rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr);
- else
- rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr);
-
- } else if (startswith(key, "SYSCTL{")) {
- attr = get_key_attribute(rules->udev, key + strlen("SYSCTL"));
- if (attr == NULL)
- LOG_AND_RETURN("error parsing %s attribute", "ATTR");
-
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", "ATTR");
-
- if (op < OP_MATCH_MAX)
- rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr);
- else
- rule_add_key(&rule_tmp, TK_A_SYSCTL, op, value, attr);
-
- } else if (startswith(key, "SECLABEL{")) {
- attr = get_key_attribute(rules->udev, key + strlen("SECLABEL"));
- if (attr == NULL)
- LOG_AND_RETURN("error parsing %s attribute", "SECLABEL");
-
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", "SECLABEL");
-
- rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr);
-
- } else if (streq(key, "KERNELS")) {
- if (op > OP_MATCH_MAX)
- LOG_AND_RETURN("invalid %s operation", key);
-
- rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL);
-
- } else if (streq(key, "SUBSYSTEMS")) {
- if (op > OP_MATCH_MAX)
- LOG_AND_RETURN("invalid %s operation", key);
-
- rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL);
-
- } else if (streq(key, "DRIVERS")) {
- if (op > OP_MATCH_MAX)
- LOG_AND_RETURN("invalid %s operation", key);
-
- rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL);
-
- } else if (startswith(key, "ATTRS{")) {
- if (op > OP_MATCH_MAX)
- LOG_AND_RETURN("invalid %s operation", "ATTRS");
-
- attr = get_key_attribute(rules->udev, key + strlen("ATTRS"));
- if (attr == NULL)
- LOG_AND_RETURN("error parsing %s attribute", "ATTRS");
-
- if (startswith(attr, "device/"))
- LOG_RULE_WARNING("'device' link may not be available in future kernels; please fix");
- if (strstr(attr, "../") != NULL)
- LOG_RULE_WARNING("direct reference to parent sysfs directory, may break in future kernels; please fix");
- rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr);
-
- } else if (streq(key, "TAGS")) {
- if (op > OP_MATCH_MAX)
- LOG_AND_RETURN("invalid %s operation", key);
-
- rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL);
-
- } else if (startswith(key, "ENV{")) {
- attr = get_key_attribute(rules->udev, key + strlen("ENV"));
- if (attr == NULL)
- LOG_AND_RETURN("error parsing %s attribute", "ENV");
-
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", "ENV");
-
- if (op < OP_MATCH_MAX)
- rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr);
- else {
- if (STR_IN_SET(attr,
- "ACTION",
- "SUBSYSTEM",
- "DEVTYPE",
- "MAJOR",
- "MINOR",
- "DRIVER",
- "IFINDEX",
- "DEVNAME",
- "DEVLINKS",
- "DEVPATH",
- "TAGS"))
- LOG_AND_RETURN("invalid ENV attribute, '%s' cannot be set", attr);
-
- rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr);
- }
-
- } else if (streq(key, "TAG")) {
- if (op < OP_MATCH_MAX)
- rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL);
- else
- rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL);
-
- } else if (streq(key, "PROGRAM")) {
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", key);
-
- rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL);
-
- } else if (streq(key, "RESULT")) {
- if (op > OP_MATCH_MAX)
- LOG_AND_RETURN("invalid %s operation", key);
-
- rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL);
-
- } else if (startswith(key, "IMPORT")) {
- attr = get_key_attribute(rules->udev, key + strlen("IMPORT"));
- if (attr == NULL) {
- LOG_RULE_WARNING("ignoring IMPORT{} with missing type");
- continue;
- }
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", "IMPORT");
-
- if (streq(attr, "program")) {
- /* find known built-in command */
- if (value[0] != '/') {
- const enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
-
- if (cmd < UDEV_BUILTIN_MAX) {
- LOG_RULE_DEBUG("IMPORT found builtin '%s', replacing", value);
- rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
- continue;
- }
- }
- rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
- } else if (streq(attr, "builtin")) {
- const enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
-
- if (cmd >= UDEV_BUILTIN_MAX)
- LOG_RULE_WARNING("IMPORT{builtin} '%s' unknown", value);
- else
- rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
- } else if (streq(attr, "file"))
- rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
- else if (streq(attr, "db"))
- rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL);
- else if (streq(attr, "cmdline"))
- rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL);
- else if (streq(attr, "parent"))
- rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL);
- else
- LOG_RULE_ERROR("ignoring unknown %s{} type '%s'", "IMPORT", attr);
-
- } else if (startswith(key, "TEST")) {
- mode_t mode = 0;
-
- if (op > OP_MATCH_MAX)
- LOG_AND_RETURN("invalid %s operation", "TEST");
-
- attr = get_key_attribute(rules->udev, key + strlen("TEST"));
- if (attr != NULL) {
- mode = strtol(attr, NULL, 8);
- rule_add_key(&rule_tmp, TK_M_TEST, op, value, &mode);
- } else
- rule_add_key(&rule_tmp, TK_M_TEST, op, value, NULL);
-
- } else if (startswith(key, "RUN")) {
- attr = get_key_attribute(rules->udev, key + strlen("RUN"));
- if (attr == NULL)
- attr = "program";
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", "RUN");
-
- if (streq(attr, "builtin")) {
- const enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
-
- if (cmd < UDEV_BUILTIN_MAX)
- rule_add_key(&rule_tmp, TK_A_RUN_BUILTIN, op, value, &cmd);
- else
- LOG_RULE_ERROR("RUN{builtin}: '%s' unknown", value);
- } else if (streq(attr, "program")) {
- const enum udev_builtin_cmd cmd = UDEV_BUILTIN_MAX;
-
- rule_add_key(&rule_tmp, TK_A_RUN_PROGRAM, op, value, &cmd);
- } else
- LOG_RULE_ERROR("ignoring unknown %s{} type '%s'", "RUN", attr);
-
- } else if (streq(key, "LABEL")) {
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", key);
-
- rule_tmp.rule.rule.label_off = rules_add_string(rules, value);
-
- } else if (streq(key, "GOTO")) {
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", key);
-
- rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL);
-
- } else if (startswith(key, "NAME")) {
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", key);
-
- if (op < OP_MATCH_MAX)
- rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL);
- else {
- if (streq(value, "%k")) {
- LOG_RULE_WARNING("NAME=\"%%k\" is ignored, because it breaks kernel supplied names; please remove");
- continue;
- }
- if (isempty(value)) {
- LOG_RULE_DEBUG("NAME=\"\" is ignored, because udev will not delete any device nodes; please remove");
- continue;
- }
- rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL);
- }
- rule_tmp.rule.rule.can_set_name = true;
-
- } else if (streq(key, "SYMLINK")) {
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", key);
-
- if (op < OP_MATCH_MAX)
- rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL);
- else
- rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, NULL);
- rule_tmp.rule.rule.can_set_name = true;
-
- } else if (streq(key, "OWNER")) {
- uid_t uid;
- char *endptr;
-
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", key);
-
- uid = strtoul(value, &endptr, 10);
- if (endptr[0] == '\0')
- rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
- else if (rules->resolve_names > 0 && strchr("$%", value[0]) == NULL) {
- uid = add_uid(rules, value);
- rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
- } else if (rules->resolve_names >= 0)
- rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL);
-
- rule_tmp.rule.rule.can_set_name = true;
-
- } else if (streq(key, "GROUP")) {
- gid_t gid;
- char *endptr;
-
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", key);
-
- gid = strtoul(value, &endptr, 10);
- if (endptr[0] == '\0')
- rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
- else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) {
- gid = add_gid(rules, value);
- rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
- } else if (rules->resolve_names >= 0)
- rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL);
-
- rule_tmp.rule.rule.can_set_name = true;
-
- } else if (streq(key, "MODE")) {
- mode_t mode;
- char *endptr;
-
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", key);
-
- mode = strtol(value, &endptr, 8);
- if (endptr[0] == '\0')
- rule_add_key(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode);
- else
- rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL);
- rule_tmp.rule.rule.can_set_name = true;
-
- } else if (streq(key, "OPTIONS")) {
- const char *pos;
-
- if (op == OP_REMOVE)
- LOG_AND_RETURN("invalid %s operation", key);
-
- pos = strstr(value, "link_priority=");
- if (pos != NULL) {
- int prio = atoi(pos + strlen("link_priority="));
-
- rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio);
- }
-
- pos = strstr(value, "string_escape=");
- if (pos != NULL) {
- pos += strlen("string_escape=");
- if (startswith(pos, "none"))
- rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL);
- else if (startswith(pos, "replace"))
- rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, op, NULL, NULL);
- }
-
- pos = strstr(value, "db_persist");
- if (pos != NULL)
- rule_add_key(&rule_tmp, TK_A_DB_PERSIST, op, NULL, NULL);
-
- pos = strstr(value, "nowatch");
- if (pos != NULL) {
- const int off = 0;
-
- rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &off);
- } else {
- pos = strstr(value, "watch");
- if (pos != NULL) {
- const int on = 1;
-
- rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &on);
- }
- }
-
- pos = strstr(value, "static_node=");
- if (pos != NULL) {
- pos += strlen("static_node=");
- rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, pos, NULL);
- rule_tmp.rule.rule.has_static_node = true;
- }
-
- } else
- LOG_AND_RETURN("unknown key '%s'", key);
- }
-
- /* add rule token and sort tokens */
- rule_tmp.rule.rule.token_count = 1 + rule_tmp.token_cur;
- if (add_token(rules, &rule_tmp.rule) != 0 || sort_token(rules, &rule_tmp) != 0)
- LOG_RULE_ERROR("failed to add rule token");
-}
-
-static int parse_file(struct udev_rules *rules, const char *filename) {
- _cleanup_fclose_ FILE *f = NULL;
- unsigned int first_token;
- unsigned int filename_off;
- char line[UTIL_LINE_SIZE];
- int line_nr = 0;
- unsigned int i;
-
- f = fopen(filename, "re");
- if (!f) {
- if (errno == ENOENT)
- return 0;
- else
- return -errno;
- }
-
- if (null_or_empty_fd(fileno(f))) {
- log_debug("Skipping empty file: %s", filename);
- return 0;
- } else
- log_debug("Reading rules file: %s", filename);
-
- first_token = rules->token_cur;
- filename_off = rules_add_string(rules, filename);
-
- while (fgets(line, sizeof(line), f) != NULL) {
- char *key;
- size_t len;
-
- /* skip whitespace */
- line_nr++;
- key = line;
- while (isspace(key[0]))
- key++;
-
- /* comment */
- if (key[0] == '#')
- continue;
-
- len = strlen(line);
- if (len < 3)
- continue;
-
- /* continue reading if backslash+newline is found */
- while (line[len-2] == '\\') {
- if (fgets(&line[len-2], (sizeof(line)-len)+2, f) == NULL)
- break;
- if (strlen(&line[len-2]) < 2)
- break;
- line_nr++;
- len = strlen(line);
- }
-
- if (len+1 >= sizeof(line)) {
- log_error("line too long '%s':%u, ignored", filename, line_nr);
- continue;
- }
- add_rule(rules, key, filename, filename_off, line_nr);
- }
-
- /* link GOTOs to LABEL rules in this file to be able to fast-forward */
- for (i = first_token+1; i < rules->token_cur; i++) {
- if (rules->tokens[i].type == TK_A_GOTO) {
- char *label = rules_str(rules, rules->tokens[i].key.value_off);
- unsigned int j;
-
- for (j = i+1; j < rules->token_cur; j++) {
- if (rules->tokens[j].type != TK_RULE)
- continue;
- if (rules->tokens[j].rule.label_off == 0)
- continue;
- if (!streq(label, rules_str(rules, rules->tokens[j].rule.label_off)))
- continue;
- rules->tokens[i].key.rule_goto = j;
- break;
- }
- if (rules->tokens[i].key.rule_goto == 0)
- log_error("GOTO '%s' has no matching label in: '%s'", label, filename);
- }
- }
- return 0;
-}
-
-struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names) {
- struct udev_rules *rules;
- struct udev_list file_list;
- struct token end_token;
- char **files, **f;
- int r;
-
- rules = new0(struct udev_rules, 1);
- if (rules == NULL)
- return NULL;
- rules->udev = udev;
- rules->resolve_names = resolve_names;
- udev_list_init(udev, &file_list, true);
-
- /* init token array and string buffer */
- rules->tokens = malloc(PREALLOC_TOKEN * sizeof(struct token));
- if (rules->tokens == NULL)
- return udev_rules_unref(rules);
- rules->token_max = PREALLOC_TOKEN;
-
- rules->strbuf = strbuf_new();
- if (!rules->strbuf)
- return udev_rules_unref(rules);
-
- udev_rules_check_timestamp(rules);
-
- r = conf_files_list_strv(&files, ".rules", NULL, rules_dirs);
- if (r < 0) {
- log_error_errno(r, "failed to enumerate rules files: %m");
- return udev_rules_unref(rules);
- }
-
- /*
- * The offset value in the rules strct is limited; add all
- * rules file names to the beginning of the string buffer.
- */
- STRV_FOREACH(f, files)
- rules_add_string(rules, *f);
-
- STRV_FOREACH(f, files)
- parse_file(rules, *f);
-
- strv_free(files);
-
- memzero(&end_token, sizeof(struct token));
- end_token.type = TK_END;
- add_token(rules, &end_token);
- log_debug("rules contain %zu bytes tokens (%u * %zu bytes), %zu bytes strings",
- rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->strbuf->len);
-
- /* cleanup temporary strbuf data */
- log_debug("%zu strings (%zu bytes), %zu de-duplicated (%zu bytes), %zu trie nodes used",
- rules->strbuf->in_count, rules->strbuf->in_len,
- rules->strbuf->dedup_count, rules->strbuf->dedup_len, rules->strbuf->nodes_count);
- strbuf_complete(rules->strbuf);
-
- /* cleanup uid/gid cache */
- rules->uids = mfree(rules->uids);
- rules->uids_cur = 0;
- rules->uids_max = 0;
- rules->gids = mfree(rules->gids);
- rules->gids_cur = 0;
- rules->gids_max = 0;
-
- dump_rules(rules);
- return rules;
-}
-
-struct udev_rules *udev_rules_unref(struct udev_rules *rules) {
- if (rules == NULL)
- return NULL;
- free(rules->tokens);
- strbuf_cleanup(rules->strbuf);
- free(rules->uids);
- free(rules->gids);
- return mfree(rules);
-}
-
-bool udev_rules_check_timestamp(struct udev_rules *rules) {
- if (!rules)
- return false;
-
- return paths_check_timestamp(rules_dirs, &rules->dirs_ts_usec, true);
-}
-
-static int match_key(struct udev_rules *rules, struct token *token, const char *val) {
- char *key_value = rules_str(rules, token->key.value_off);
- char *pos;
- bool match = false;
-
- if (val == NULL)
- val = "";
-
- switch (token->key.glob) {
- case GL_PLAIN:
- match = (streq(key_value, val));
- break;
- case GL_GLOB:
- match = (fnmatch(key_value, val, 0) == 0);
- break;
- case GL_SPLIT:
- {
- const char *s;
- size_t len;
-
- s = rules_str(rules, token->key.value_off);
- len = strlen(val);
- for (;;) {
- const char *next;
-
- next = strchr(s, '|');
- if (next != NULL) {
- size_t matchlen = (size_t)(next - s);
-
- match = (matchlen == len && strneq(s, val, matchlen));
- if (match)
- break;
- } else {
- match = (streq(s, val));
- break;
- }
- s = &next[1];
- }
- break;
- }
- case GL_SPLIT_GLOB:
- {
- char value[UTIL_PATH_SIZE];
-
- strscpy(value, sizeof(value), rules_str(rules, token->key.value_off));
- key_value = value;
- while (key_value != NULL) {
- pos = strchr(key_value, '|');
- if (pos != NULL) {
- pos[0] = '\0';
- pos = &pos[1];
- }
- match = (fnmatch(key_value, val, 0) == 0);
- if (match)
- break;
- key_value = pos;
- }
- break;
- }
- case GL_SOMETHING:
- match = (val[0] != '\0');
- break;
- case GL_UNSET:
- return -1;
- }
-
- if (match && (token->key.op == OP_MATCH))
- return 0;
- if (!match && (token->key.op == OP_NOMATCH))
- return 0;
- return -1;
-}
-
-static int match_attr(struct udev_rules *rules, struct udev_device *dev, struct udev_event *event, struct token *cur) {
- const char *name;
- char nbuf[UTIL_NAME_SIZE];
- const char *value;
- char vbuf[UTIL_NAME_SIZE];
- size_t len;
-
- name = rules_str(rules, cur->key.attr_off);
- switch (cur->key.attrsubst) {
- case SB_FORMAT:
- udev_event_apply_format(event, name, nbuf, sizeof(nbuf));
- name = nbuf;
- /* fall through */
- case SB_NONE:
- value = udev_device_get_sysattr_value(dev, name);
- if (value == NULL)
- return -1;
- break;
- case SB_SUBSYS:
- if (util_resolve_subsys_kernel(event->udev, name, vbuf, sizeof(vbuf), 1) != 0)
- return -1;
- value = vbuf;
- break;
- default:
- return -1;
- }
-
- /* remove trailing whitespace, if not asked to match for it */
- len = strlen(value);
- if (len > 0 && isspace(value[len-1])) {
- const char *key_value;
- size_t klen;
-
- key_value = rules_str(rules, cur->key.value_off);
- klen = strlen(key_value);
- if (klen > 0 && !isspace(key_value[klen-1])) {
- if (value != vbuf) {
- strscpy(vbuf, sizeof(vbuf), value);
- value = vbuf;
- }
- while (len > 0 && isspace(vbuf[--len]))
- vbuf[len] = '\0';
- }
- }
-
- return match_key(rules, cur, value);
-}
-
-enum escape_type {
- ESCAPE_UNSET,
- ESCAPE_NONE,
- ESCAPE_REPLACE,
-};
-
-void udev_rules_apply_to_event(struct udev_rules *rules,
- struct udev_event *event,
- usec_t timeout_usec,
- usec_t timeout_warn_usec,
- struct udev_list *properties_list) {
- struct token *cur;
- struct token *rule;
- enum escape_type esc = ESCAPE_UNSET;
- bool can_set_name;
-
- if (rules->tokens == NULL)
- return;
-
- can_set_name = ((!streq(udev_device_get_action(event->dev), "remove")) &&
- (major(udev_device_get_devnum(event->dev)) > 0 ||
- udev_device_get_ifindex(event->dev) > 0));
-
- /* loop through token list, match, run actions or forward to next rule */
- cur = &rules->tokens[0];
- rule = cur;
- for (;;) {
- dump_token(rules, cur);
- switch (cur->type) {
- case TK_RULE:
- /* current rule */
- rule = cur;
- /* possibly skip rules which want to set NAME, SYMLINK, OWNER, GROUP, MODE */
- if (!can_set_name && rule->rule.can_set_name)
- goto nomatch;
- esc = ESCAPE_UNSET;
- break;
- case TK_M_ACTION:
- if (match_key(rules, cur, udev_device_get_action(event->dev)) != 0)
- goto nomatch;
- break;
- case TK_M_DEVPATH:
- if (match_key(rules, cur, udev_device_get_devpath(event->dev)) != 0)
- goto nomatch;
- break;
- case TK_M_KERNEL:
- if (match_key(rules, cur, udev_device_get_sysname(event->dev)) != 0)
- goto nomatch;
- break;
- case TK_M_DEVLINK: {
- struct udev_list_entry *list_entry;
- bool match = false;
-
- udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(event->dev)) {
- const char *devlink;
-
- devlink = udev_list_entry_get_name(list_entry) + strlen("/dev/");
- if (match_key(rules, cur, devlink) == 0) {
- match = true;
- break;
- }
- }
- if (!match)
- goto nomatch;
- break;
- }
- case TK_M_NAME:
- if (match_key(rules, cur, event->name) != 0)
- goto nomatch;
- break;
- case TK_M_ENV: {
- const char *key_name = rules_str(rules, cur->key.attr_off);
- const char *value;
-
- value = udev_device_get_property_value(event->dev, key_name);
-
- /* check global properties */
- if (!value && properties_list) {
- struct udev_list_entry *list_entry;
-
- list_entry = udev_list_get_entry(properties_list);
- list_entry = udev_list_entry_get_by_name(list_entry, key_name);
- if (list_entry != NULL)
- value = udev_list_entry_get_value(list_entry);
- }
-
- if (!value)
- value = "";
- if (match_key(rules, cur, value))
- goto nomatch;
- break;
- }
- case TK_M_TAG: {
- struct udev_list_entry *list_entry;
- bool match = false;
-
- udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(event->dev)) {
- if (streq(rules_str(rules, cur->key.value_off), udev_list_entry_get_name(list_entry))) {
- match = true;
- break;
- }
- }
- if ((!match && (cur->key.op != OP_NOMATCH)) ||
- (match && (cur->key.op == OP_NOMATCH)))
- goto nomatch;
- break;
- }
- case TK_M_SUBSYSTEM:
- if (match_key(rules, cur, udev_device_get_subsystem(event->dev)) != 0)
- goto nomatch;
- break;
- case TK_M_DRIVER:
- if (match_key(rules, cur, udev_device_get_driver(event->dev)) != 0)
- goto nomatch;
- break;
- case TK_M_ATTR:
- if (match_attr(rules, event->dev, event, cur) != 0)
- goto nomatch;
- break;
- case TK_M_SYSCTL: {
- char filename[UTIL_PATH_SIZE];
- _cleanup_free_ char *value = NULL;
- size_t len;
-
- udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename));
- sysctl_normalize(filename);
- if (sysctl_read(filename, &value) < 0)
- goto nomatch;
-
- len = strlen(value);
- while (len > 0 && isspace(value[--len]))
- value[len] = '\0';
- if (match_key(rules, cur, value) != 0)
- goto nomatch;
- break;
- }
- case TK_M_KERNELS:
- case TK_M_SUBSYSTEMS:
- case TK_M_DRIVERS:
- case TK_M_ATTRS:
- case TK_M_TAGS: {
- struct token *next;
-
- /* get whole sequence of parent matches */
- next = cur;
- while (next->type > TK_M_PARENTS_MIN && next->type < TK_M_PARENTS_MAX)
- next++;
-
- /* loop over parents */
- event->dev_parent = event->dev;
- for (;;) {
- struct token *key;
-
- /* loop over sequence of parent match keys */
- for (key = cur; key < next; key++ ) {
- dump_token(rules, key);
- switch(key->type) {
- case TK_M_KERNELS:
- if (match_key(rules, key, udev_device_get_sysname(event->dev_parent)) != 0)
- goto try_parent;
- break;
- case TK_M_SUBSYSTEMS:
- if (match_key(rules, key, udev_device_get_subsystem(event->dev_parent)) != 0)
- goto try_parent;
- break;
- case TK_M_DRIVERS:
- if (match_key(rules, key, udev_device_get_driver(event->dev_parent)) != 0)
- goto try_parent;
- break;
- case TK_M_ATTRS:
- if (match_attr(rules, event->dev_parent, event, key) != 0)
- goto try_parent;
- break;
- case TK_M_TAGS: {
- bool match = udev_device_has_tag(event->dev_parent, rules_str(rules, cur->key.value_off));
-
- if (match && key->key.op == OP_NOMATCH)
- goto try_parent;
- if (!match && key->key.op == OP_MATCH)
- goto try_parent;
- break;
- }
- default:
- goto nomatch;
- }
- }
- break;
-
- try_parent:
- event->dev_parent = udev_device_get_parent(event->dev_parent);
- if (event->dev_parent == NULL)
- goto nomatch;
- }
- /* move behind our sequence of parent match keys */
- cur = next;
- continue;
- }
- case TK_M_TEST: {
- char filename[UTIL_PATH_SIZE];
- struct stat statbuf;
- int match;
-
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), filename, sizeof(filename));
- if (util_resolve_subsys_kernel(event->udev, filename, filename, sizeof(filename), 0) != 0) {
- if (filename[0] != '/') {
- char tmp[UTIL_PATH_SIZE];
-
- strscpy(tmp, sizeof(tmp), filename);
- strscpyl(filename, sizeof(filename),
- udev_device_get_syspath(event->dev), "/", tmp, NULL);
- }
- }
- attr_subst_subdir(filename, sizeof(filename));
-
- match = (stat(filename, &statbuf) == 0);
- if (match && cur->key.mode > 0)
- match = ((statbuf.st_mode & cur->key.mode) > 0);
- if (match && cur->key.op == OP_NOMATCH)
- goto nomatch;
- if (!match && cur->key.op == OP_MATCH)
- goto nomatch;
- break;
- }
- case TK_M_PROGRAM: {
- char program[UTIL_PATH_SIZE];
- char result[UTIL_LINE_SIZE];
-
- event->program_result = mfree(event->program_result);
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), program, sizeof(program));
- log_debug("PROGRAM '%s' %s:%u",
- program,
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
-
- if (udev_event_spawn(event, timeout_usec, timeout_warn_usec, true, program, result, sizeof(result)) < 0) {
- if (cur->key.op != OP_NOMATCH)
- goto nomatch;
- } else {
- int count;
-
- util_remove_trailing_chars(result, '\n');
- if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
- count = util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT);
- if (count > 0)
- log_debug("%i character(s) replaced" , count);
- }
- event->program_result = strdup(result);
- if (cur->key.op == OP_NOMATCH)
- goto nomatch;
- }
- break;
- }
- case TK_M_IMPORT_FILE: {
- char import[UTIL_PATH_SIZE];
-
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import));
- if (import_file_into_properties(event->dev, import) != 0)
- if (cur->key.op != OP_NOMATCH)
- goto nomatch;
- break;
- }
- case TK_M_IMPORT_PROG: {
- char import[UTIL_PATH_SIZE];
-
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import));
- log_debug("IMPORT '%s' %s:%u",
- import,
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
-
- if (import_program_into_properties(event, timeout_usec, timeout_warn_usec, import) != 0)
- if (cur->key.op != OP_NOMATCH)
- goto nomatch;
- break;
- }
- case TK_M_IMPORT_BUILTIN: {
- char command[UTIL_PATH_SIZE];
-
- if (udev_builtin_run_once(cur->key.builtin_cmd)) {
- /* check if we ran already */
- if (event->builtin_run & (1 << cur->key.builtin_cmd)) {
- log_debug("IMPORT builtin skip '%s' %s:%u",
- udev_builtin_name(cur->key.builtin_cmd),
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
- /* return the result from earlier run */
- if (event->builtin_ret & (1 << cur->key.builtin_cmd))
- if (cur->key.op != OP_NOMATCH)
- goto nomatch;
- break;
- }
- /* mark as ran */
- event->builtin_run |= (1 << cur->key.builtin_cmd);
- }
-
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), command, sizeof(command));
- log_debug("IMPORT builtin '%s' %s:%u",
- udev_builtin_name(cur->key.builtin_cmd),
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
-
- if (udev_builtin_run(event->dev, cur->key.builtin_cmd, command, false) != 0) {
- /* remember failure */
- log_debug("IMPORT builtin '%s' returned non-zero",
- udev_builtin_name(cur->key.builtin_cmd));
- event->builtin_ret |= (1 << cur->key.builtin_cmd);
- if (cur->key.op != OP_NOMATCH)
- goto nomatch;
- }
- break;
- }
- case TK_M_IMPORT_DB: {
- const char *key = rules_str(rules, cur->key.value_off);
- const char *value;
-
- value = udev_device_get_property_value(event->dev_db, key);
- if (value != NULL)
- udev_device_add_property(event->dev, key, value);
- else {
- if (cur->key.op != OP_NOMATCH)
- goto nomatch;
- }
- break;
- }
- case TK_M_IMPORT_CMDLINE: {
- _cleanup_fclose_ FILE *f = NULL;
- bool imported = false;
-
- f = fopen("/proc/cmdline", "re");
- if (f != NULL) {
- char cmdline[4096];
-
- if (fgets(cmdline, sizeof(cmdline), f) != NULL) {
- const char *key = rules_str(rules, cur->key.value_off);
- char *pos;
-
- pos = strstr(cmdline, key);
- if (pos != NULL) {
- imported = true;
- pos += strlen(key);
- if (pos[0] == '\0' || isspace(pos[0]))
- /* we import simple flags as 'FLAG=1' */
- udev_device_add_property(event->dev, key, "1");
- else if (pos[0] == '=') {
- const char *value;
-
- pos++;
- value = pos;
- while (pos[0] != '\0' && !isspace(pos[0]))
- pos++;
- pos[0] = '\0';
- udev_device_add_property(event->dev, key, value);
- }
- }
- }
- }
- if (!imported && cur->key.op != OP_NOMATCH)
- goto nomatch;
- break;
- }
- case TK_M_IMPORT_PARENT: {
- char import[UTIL_PATH_SIZE];
-
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import));
- if (import_parent_into_properties(event->dev, import) != 0)
- if (cur->key.op != OP_NOMATCH)
- goto nomatch;
- break;
- }
- case TK_M_RESULT:
- if (match_key(rules, cur, event->program_result) != 0)
- goto nomatch;
- break;
- case TK_A_STRING_ESCAPE_NONE:
- esc = ESCAPE_NONE;
- break;
- case TK_A_STRING_ESCAPE_REPLACE:
- esc = ESCAPE_REPLACE;
- break;
- case TK_A_DB_PERSIST:
- udev_device_set_db_persist(event->dev);
- break;
- case TK_A_INOTIFY_WATCH:
- if (event->inotify_watch_final)
- break;
- if (cur->key.op == OP_ASSIGN_FINAL)
- event->inotify_watch_final = true;
- event->inotify_watch = cur->key.watch;
- break;
- case TK_A_DEVLINK_PRIO:
- udev_device_set_devlink_priority(event->dev, cur->key.devlink_prio);
- break;
- case TK_A_OWNER: {
- char owner[UTIL_NAME_SIZE];
- const char *ow = owner;
- int r;
-
- if (event->owner_final)
- break;
- if (cur->key.op == OP_ASSIGN_FINAL)
- event->owner_final = true;
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), owner, sizeof(owner));
- event->owner_set = true;
- r = get_user_creds(&ow, &event->uid, NULL, NULL, NULL);
- if (r < 0) {
- if (r == -ENOENT || r == -ESRCH)
- log_error("specified user '%s' unknown", owner);
- else
- log_error_errno(r, "error resolving user '%s': %m", owner);
-
- event->uid = 0;
- }
- log_debug("OWNER %u %s:%u",
- event->uid,
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
- break;
- }
- case TK_A_GROUP: {
- char group[UTIL_NAME_SIZE];
- const char *gr = group;
- int r;
-
- if (event->group_final)
- break;
- if (cur->key.op == OP_ASSIGN_FINAL)
- event->group_final = true;
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), group, sizeof(group));
- event->group_set = true;
- r = get_group_creds(&gr, &event->gid);
- if (r < 0) {
- if (r == -ENOENT || r == -ESRCH)
- log_error("specified group '%s' unknown", group);
- else
- log_error_errno(r, "error resolving group '%s': %m", group);
-
- event->gid = 0;
- }
- log_debug("GROUP %u %s:%u",
- event->gid,
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
- break;
- }
- case TK_A_MODE: {
- char mode_str[UTIL_NAME_SIZE];
- mode_t mode;
- char *endptr;
-
- if (event->mode_final)
- break;
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), mode_str, sizeof(mode_str));
- mode = strtol(mode_str, &endptr, 8);
- if (endptr[0] != '\0') {
- log_error("ignoring invalid mode '%s'", mode_str);
- break;
- }
- if (cur->key.op == OP_ASSIGN_FINAL)
- event->mode_final = true;
- event->mode_set = true;
- event->mode = mode;
- log_debug("MODE %#o %s:%u",
- event->mode,
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
- break;
- }
- case TK_A_OWNER_ID:
- if (event->owner_final)
- break;
- if (cur->key.op == OP_ASSIGN_FINAL)
- event->owner_final = true;
- event->owner_set = true;
- event->uid = cur->key.uid;
- log_debug("OWNER %u %s:%u",
- event->uid,
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
- break;
- case TK_A_GROUP_ID:
- if (event->group_final)
- break;
- if (cur->key.op == OP_ASSIGN_FINAL)
- event->group_final = true;
- event->group_set = true;
- event->gid = cur->key.gid;
- log_debug("GROUP %u %s:%u",
- event->gid,
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
- break;
- case TK_A_MODE_ID:
- if (event->mode_final)
- break;
- if (cur->key.op == OP_ASSIGN_FINAL)
- event->mode_final = true;
- event->mode_set = true;
- event->mode = cur->key.mode;
- log_debug("MODE %#o %s:%u",
- event->mode,
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
- break;
- case TK_A_SECLABEL: {
- char label_str[UTIL_LINE_SIZE] = {};
- const char *name, *label;
-
- name = rules_str(rules, cur->key.attr_off);
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), label_str, sizeof(label_str));
- if (label_str[0] != '\0')
- label = label_str;
- else
- label = rules_str(rules, cur->key.value_off);
-
- if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
- udev_list_cleanup(&event->seclabel_list);
- udev_list_entry_add(&event->seclabel_list, name, label);
- log_debug("SECLABEL{%s}='%s' %s:%u",
- name, label,
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
- break;
- }
- case TK_A_ENV: {
- const char *name = rules_str(rules, cur->key.attr_off);
- char *value = rules_str(rules, cur->key.value_off);
- char value_new[UTIL_NAME_SIZE];
- const char *value_old = NULL;
-
- if (value[0] == '\0') {
- if (cur->key.op == OP_ADD)
- break;
- udev_device_add_property(event->dev, name, NULL);
- break;
- }
-
- if (cur->key.op == OP_ADD)
- value_old = udev_device_get_property_value(event->dev, name);
- if (value_old) {
- char temp[UTIL_NAME_SIZE];
-
- /* append value separated by space */
- udev_event_apply_format(event, value, temp, sizeof(temp));
- strscpyl(value_new, sizeof(value_new), value_old, " ", temp, NULL);
- } else
- udev_event_apply_format(event, value, value_new, sizeof(value_new));
-
- udev_device_add_property(event->dev, name, value_new);
- break;
- }
- case TK_A_TAG: {
- char tag[UTIL_PATH_SIZE];
- const char *p;
-
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), tag, sizeof(tag));
- if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
- udev_device_cleanup_tags_list(event->dev);
- for (p = tag; *p != '\0'; p++) {
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9') ||
- *p == '-' || *p == '_')
- continue;
- log_error("ignoring invalid tag name '%s'", tag);
- break;
- }
- if (cur->key.op == OP_REMOVE)
- udev_device_remove_tag(event->dev, tag);
- else
- udev_device_add_tag(event->dev, tag);
- break;
- }
- case TK_A_NAME: {
- const char *name = rules_str(rules, cur->key.value_off);
-
- char name_str[UTIL_PATH_SIZE];
- int count;
-
- if (event->name_final)
- break;
- if (cur->key.op == OP_ASSIGN_FINAL)
- event->name_final = true;
- udev_event_apply_format(event, name, name_str, sizeof(name_str));
- if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
- count = util_replace_chars(name_str, "/");
- if (count > 0)
- log_debug("%i character(s) replaced", count);
- }
- if (major(udev_device_get_devnum(event->dev)) &&
- !streq(name_str, udev_device_get_devnode(event->dev) + strlen("/dev/"))) {
- log_error("NAME=\"%s\" ignored, kernel device nodes cannot be renamed; please fix it in %s:%u\n",
- name,
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
- break;
- }
- if (free_and_strdup(&event->name, name_str) < 0) {
- log_oom();
- return;
- }
- log_debug("NAME '%s' %s:%u",
- event->name,
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
- break;
- }
- case TK_A_DEVLINK: {
- char temp[UTIL_PATH_SIZE];
- char filename[UTIL_PATH_SIZE];
- char *pos, *next;
- int count = 0;
-
- if (event->devlink_final)
- break;
- if (major(udev_device_get_devnum(event->dev)) == 0)
- break;
- if (cur->key.op == OP_ASSIGN_FINAL)
- event->devlink_final = true;
- if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
- udev_device_cleanup_devlinks_list(event->dev);
-
- /* allow multiple symlinks separated by spaces */
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), temp, sizeof(temp));
- if (esc == ESCAPE_UNSET)
- count = util_replace_chars(temp, "/ ");
- else if (esc == ESCAPE_REPLACE)
- count = util_replace_chars(temp, "/");
- if (count > 0)
- log_debug("%i character(s) replaced" , count);
- pos = temp;
- while (isspace(pos[0]))
- pos++;
- next = strchr(pos, ' ');
- while (next != NULL) {
- next[0] = '\0';
- log_debug("LINK '%s' %s:%u", pos,
- rules_str(rules, rule->rule.filename_off), rule->rule.filename_line);
- strscpyl(filename, sizeof(filename), "/dev/", pos, NULL);
- udev_device_add_devlink(event->dev, filename);
- while (isspace(next[1]))
- next++;
- pos = &next[1];
- next = strchr(pos, ' ');
- }
- if (pos[0] != '\0') {
- log_debug("LINK '%s' %s:%u", pos,
- rules_str(rules, rule->rule.filename_off), rule->rule.filename_line);
- strscpyl(filename, sizeof(filename), "/dev/", pos, NULL);
- udev_device_add_devlink(event->dev, filename);
- }
- break;
- }
- case TK_A_ATTR: {
- const char *key_name = rules_str(rules, cur->key.attr_off);
- char attr[UTIL_PATH_SIZE];
- char value[UTIL_NAME_SIZE];
- _cleanup_fclose_ FILE *f = NULL;
-
- if (util_resolve_subsys_kernel(event->udev, key_name, attr, sizeof(attr), 0) != 0)
- strscpyl(attr, sizeof(attr), udev_device_get_syspath(event->dev), "/", key_name, NULL);
- attr_subst_subdir(attr, sizeof(attr));
-
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value));
- log_debug("ATTR '%s' writing '%s' %s:%u", attr, value,
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
- f = fopen(attr, "we");
- if (f == NULL)
- log_error_errno(errno, "error opening ATTR{%s} for writing: %m", attr);
- else if (fprintf(f, "%s", value) <= 0)
- log_error_errno(errno, "error writing ATTR{%s}: %m", attr);
- break;
- }
- case TK_A_SYSCTL: {
- char filename[UTIL_PATH_SIZE];
- char value[UTIL_NAME_SIZE];
- int r;
-
- udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename));
- sysctl_normalize(filename);
- udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value));
- log_debug("SYSCTL '%s' writing '%s' %s:%u", filename, value,
- rules_str(rules, rule->rule.filename_off), rule->rule.filename_line);
- r = sysctl_write(filename, value);
- if (r < 0)
- log_error_errno(r, "error writing SYSCTL{%s}='%s': %m", filename, value);
- break;
- }
- case TK_A_RUN_BUILTIN:
- case TK_A_RUN_PROGRAM: {
- struct udev_list_entry *entry;
-
- if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
- udev_list_cleanup(&event->run_list);
- log_debug("RUN '%s' %s:%u",
- rules_str(rules, cur->key.value_off),
- rules_str(rules, rule->rule.filename_off),
- rule->rule.filename_line);
- entry = udev_list_entry_add(&event->run_list, rules_str(rules, cur->key.value_off), NULL);
- udev_list_entry_set_num(entry, cur->key.builtin_cmd);
- break;
- }
- case TK_A_GOTO:
- if (cur->key.rule_goto == 0)
- break;
- cur = &rules->tokens[cur->key.rule_goto];
- continue;
- case TK_END:
- return;
-
- case TK_M_PARENTS_MIN:
- case TK_M_PARENTS_MAX:
- case TK_M_MAX:
- case TK_UNSET:
- log_error("wrong type %u", cur->type);
- goto nomatch;
- }
-
- cur++;
- continue;
- nomatch:
- /* fast-forward to next rule */
- cur = rule + rule->rule.token_count;
- }
-}
-
-int udev_rules_apply_static_dev_perms(struct udev_rules *rules) {
- struct token *cur;
- struct token *rule;
- uid_t uid = 0;
- gid_t gid = 0;
- mode_t mode = 0;
- _cleanup_strv_free_ char **tags = NULL;
- char **t;
- FILE *f = NULL;
- _cleanup_free_ char *path = NULL;
- int r;
-
- if (rules->tokens == NULL)
- return 0;
-
- cur = &rules->tokens[0];
- rule = cur;
- for (;;) {
- switch (cur->type) {
- case TK_RULE:
- /* current rule */
- rule = cur;
-
- /* skip rules without a static_node tag */
- if (!rule->rule.has_static_node)
- goto next;
-
- uid = 0;
- gid = 0;
- mode = 0;
- tags = strv_free(tags);
- break;
- case TK_A_OWNER_ID:
- uid = cur->key.uid;
- break;
- case TK_A_GROUP_ID:
- gid = cur->key.gid;
- break;
- case TK_A_MODE_ID:
- mode = cur->key.mode;
- break;
- case TK_A_TAG:
- r = strv_extend(&tags, rules_str(rules, cur->key.value_off));
- if (r < 0)
- goto finish;
-
- break;
- case TK_A_STATIC_NODE: {
- char device_node[UTIL_PATH_SIZE];
- char tags_dir[UTIL_PATH_SIZE];
- char tag_symlink[UTIL_PATH_SIZE];
- struct stat stats;
-
- /* we assure, that the permissions tokens are sorted before the static token */
-
- if (mode == 0 && uid == 0 && gid == 0 && tags == NULL)
- goto next;
-
- strscpyl(device_node, sizeof(device_node), "/dev/", rules_str(rules, cur->key.value_off), NULL);
- if (stat(device_node, &stats) != 0)
- break;
- if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode))
- break;
-
- /* export the tags to a directory as symlinks, allowing otherwise dead nodes to be tagged */
- if (tags) {
- STRV_FOREACH(t, tags) {
- _cleanup_free_ char *unescaped_filename = NULL;
-
- strscpyl(tags_dir, sizeof(tags_dir), "/run/udev/static_node-tags/", *t, "/", NULL);
- r = mkdir_p(tags_dir, 0755);
- if (r < 0)
- return log_error_errno(r, "failed to create %s: %m", tags_dir);
-
- unescaped_filename = xescape(rules_str(rules, cur->key.value_off), "/.");
-
- strscpyl(tag_symlink, sizeof(tag_symlink), tags_dir, unescaped_filename, NULL);
- r = symlink(device_node, tag_symlink);
- if (r < 0 && errno != EEXIST)
- return log_error_errno(errno, "failed to create symlink %s -> %s: %m",
- tag_symlink, device_node);
- }
- }
-
- /* don't touch the permissions if only the tags were set */
- if (mode == 0 && uid == 0 && gid == 0)
- break;
-
- if (mode == 0) {
- if (gid > 0)
- mode = 0660;
- else
- mode = 0600;
- }
- if (mode != (stats.st_mode & 01777)) {
- r = chmod(device_node, mode);
- if (r < 0) {
- log_error("failed to chmod '%s' %#o", device_node, mode);
- return -errno;
- } else
- log_debug("chmod '%s' %#o", device_node, mode);
- }
-
- if ((uid != 0 && uid != stats.st_uid) || (gid != 0 && gid != stats.st_gid)) {
- r = chown(device_node, uid, gid);
- if (r < 0) {
- log_error("failed to chown '%s' %u %u ", device_node, uid, gid);
- return -errno;
- } else
- log_debug("chown '%s' %u %u", device_node, uid, gid);
- }
-
- utimensat(AT_FDCWD, device_node, NULL, 0);
- break;
- }
- case TK_END:
- goto finish;
- }
-
- cur++;
- continue;
-next:
- /* fast-forward to next rule */
- cur = rule + rule->rule.token_count;
- continue;
- }
-
-finish:
- if (f) {
- fflush(f);
- fchmod(fileno(f), 0644);
- if (ferror(f) || rename(path, "/run/udev/static_node-tags") < 0) {
- unlink_noerrno("/run/udev/static_node-tags");
- unlink_noerrno(path);
- return -errno;
- }
- }
-
- return 0;
-}
diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c
deleted file mode 100644
index bc9096ed0c..0000000000
--- a/src/udev/udev-watch.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2004-2012 Kay Sievers <kay@vrfy.org>
- * Copyright (C) 2009 Canonical Ltd.
- * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <dirent.h>
-#include <errno.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <sys/inotify.h>
-#include <unistd.h>
-
-#include "stdio-util.h"
-#include "udev.h"
-
-static int inotify_fd = -1;
-
-/* inotify descriptor, will be shared with rules directory;
- * set to cloexec since we need our children to be able to add
- * watches for us
- */
-int udev_watch_init(struct udev *udev) {
- inotify_fd = inotify_init1(IN_CLOEXEC);
- if (inotify_fd < 0)
- log_error_errno(errno, "inotify_init failed: %m");
- return inotify_fd;
-}
-
-/* move any old watches directory out of the way, and then restore
- * the watches
- */
-void udev_watch_restore(struct udev *udev) {
- if (inotify_fd < 0)
- return;
-
- if (rename("/run/udev/watch", "/run/udev/watch.old") == 0) {
- DIR *dir;
- struct dirent *ent;
-
- dir = opendir("/run/udev/watch.old");
- if (dir == NULL) {
- log_error_errno(errno, "unable to open old watches dir /run/udev/watch.old; old watches will not be restored: %m");
- return;
- }
-
- for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) {
- char device[UTIL_PATH_SIZE];
- ssize_t len;
- struct udev_device *dev;
-
- if (ent->d_name[0] == '.')
- continue;
-
- len = readlinkat(dirfd(dir), ent->d_name, device, sizeof(device));
- if (len <= 0 || len == (ssize_t)sizeof(device))
- goto unlink;
- device[len] = '\0';
-
- dev = udev_device_new_from_device_id(udev, device);
- if (dev == NULL)
- goto unlink;
-
- log_debug("restoring old watch on '%s'", udev_device_get_devnode(dev));
- udev_watch_begin(udev, dev);
- udev_device_unref(dev);
-unlink:
- unlinkat(dirfd(dir), ent->d_name, 0);
- }
-
- closedir(dir);
- rmdir("/run/udev/watch.old");
-
- } else if (errno != ENOENT)
- log_error_errno(errno, "unable to move watches dir /run/udev/watch; old watches will not be restored: %m");
-}
-
-void udev_watch_begin(struct udev *udev, struct udev_device *dev) {
- char filename[sizeof("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
- int wd;
- int r;
-
- if (inotify_fd < 0)
- return;
-
- log_debug("adding watch on '%s'", udev_device_get_devnode(dev));
- wd = inotify_add_watch(inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
- if (wd < 0) {
- log_error_errno(errno, "inotify_add_watch(%d, %s, %o) failed: %m",
- inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
- return;
- }
-
- xsprintf(filename, "/run/udev/watch/%d", wd);
- mkdir_parents(filename, 0755);
- unlink(filename);
- r = symlink(udev_device_get_id_filename(dev), filename);
- if (r < 0)
- log_error_errno(errno, "Failed to create symlink %s: %m", filename);
-
- udev_device_set_watch_handle(dev, wd);
-}
-
-void udev_watch_end(struct udev *udev, struct udev_device *dev) {
- int wd;
- char filename[sizeof("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
-
- if (inotify_fd < 0)
- return;
-
- wd = udev_device_get_watch_handle(dev);
- if (wd < 0)
- return;
-
- log_debug("removing watch on '%s'", udev_device_get_devnode(dev));
- inotify_rm_watch(inotify_fd, wd);
-
- xsprintf(filename, "/run/udev/watch/%d", wd);
- unlink(filename);
-
- udev_device_set_watch_handle(dev, -1);
-}
-
-struct udev_device *udev_watch_lookup(struct udev *udev, int wd) {
- char filename[sizeof("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
- char device[UTIL_NAME_SIZE];
- ssize_t len;
-
- if (inotify_fd < 0 || wd < 0)
- return NULL;
-
- xsprintf(filename, "/run/udev/watch/%d", wd);
- len = readlink(filename, device, sizeof(device));
- if (len <= 0 || (size_t)len == sizeof(device))
- return NULL;
- device[len] = '\0';
-
- return udev_device_new_from_device_id(udev, device);
-}
diff --git a/src/udev/udev.conf b/src/udev/udev.conf
deleted file mode 100644
index 47d1433002..0000000000
--- a/src/udev/udev.conf
+++ /dev/null
@@ -1,3 +0,0 @@
-# see udev.conf(5) for details
-
-#udev_log="info"
diff --git a/src/udev/udev.h b/src/udev/udev.h
deleted file mode 100644
index 8433e8d9f2..0000000000
--- a/src/udev/udev.h
+++ /dev/null
@@ -1,216 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2003-2010 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <sys/param.h>
-#include <sys/sysmacros.h>
-#include <sys/types.h>
-
-#include "libudev.h"
-#include "sd-netlink.h"
-
-#include "label.h"
-#include "libudev-private.h"
-#include "macro.h"
-#include "strv.h"
-#include "util.h"
-
-struct udev_event {
- struct udev *udev;
- struct udev_device *dev;
- struct udev_device *dev_parent;
- struct udev_device *dev_db;
- char *name;
- char *program_result;
- mode_t mode;
- uid_t uid;
- gid_t gid;
- struct udev_list seclabel_list;
- struct udev_list run_list;
- int exec_delay;
- usec_t birth_usec;
- sd_netlink *rtnl;
- unsigned int builtin_run;
- unsigned int builtin_ret;
- bool inotify_watch;
- bool inotify_watch_final;
- bool group_set;
- bool group_final;
- bool owner_set;
- bool owner_final;
- bool mode_set;
- bool mode_final;
- bool name_final;
- bool devlink_final;
- bool run_final;
-};
-
-struct udev_watch {
- struct udev_list_node node;
- int handle;
- char *name;
-};
-
-/* udev-rules.c */
-struct udev_rules;
-struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names);
-struct udev_rules *udev_rules_unref(struct udev_rules *rules);
-bool udev_rules_check_timestamp(struct udev_rules *rules);
-void udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event,
- usec_t timeout_usec, usec_t timeout_warn_usec,
- struct udev_list *properties_list);
-int udev_rules_apply_static_dev_perms(struct udev_rules *rules);
-
-/* udev-event.c */
-struct udev_event *udev_event_new(struct udev_device *dev);
-void udev_event_unref(struct udev_event *event);
-size_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size);
-int udev_event_apply_subsys_kernel(struct udev_event *event, const char *string,
- char *result, size_t maxsize, int read_value);
-int udev_event_spawn(struct udev_event *event,
- usec_t timeout_usec,
- usec_t timeout_warn_usec,
- bool accept_failure,
- const char *cmd, char *result, size_t ressize);
-void udev_event_execute_rules(struct udev_event *event,
- usec_t timeout_usec, usec_t timeout_warn_usec,
- struct udev_list *properties_list,
- struct udev_rules *rules);
-void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec);
-int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]);
-
-/* udev-watch.c */
-int udev_watch_init(struct udev *udev);
-void udev_watch_restore(struct udev *udev);
-void udev_watch_begin(struct udev *udev, struct udev_device *dev);
-void udev_watch_end(struct udev *udev, struct udev_device *dev);
-struct udev_device *udev_watch_lookup(struct udev *udev, int wd);
-
-/* udev-node.c */
-void udev_node_add(struct udev_device *dev, bool apply,
- mode_t mode, uid_t uid, gid_t gid,
- struct udev_list *seclabel_list);
-void udev_node_remove(struct udev_device *dev);
-void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old);
-
-/* udev-ctrl.c */
-struct udev_ctrl;
-struct udev_ctrl *udev_ctrl_new(struct udev *udev);
-struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd);
-int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl);
-struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl);
-int udev_ctrl_cleanup(struct udev_ctrl *uctrl);
-struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl);
-int udev_ctrl_get_fd(struct udev_ctrl *uctrl);
-int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout);
-int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout);
-int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout);
-int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout);
-int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout);
-int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout);
-int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout);
-int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout);
-struct udev_ctrl_connection;
-struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl);
-struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn);
-struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn);
-struct udev_ctrl_msg;
-struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn);
-struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg);
-const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg);
-
-/* built-in commands */
-enum udev_builtin_cmd {
-#ifdef HAVE_BLKID
- UDEV_BUILTIN_BLKID,
-#endif
- UDEV_BUILTIN_BTRFS,
- UDEV_BUILTIN_HWDB,
- UDEV_BUILTIN_INPUT_ID,
- UDEV_BUILTIN_KEYBOARD,
-#ifdef HAVE_KMOD
- UDEV_BUILTIN_KMOD,
-#endif
- UDEV_BUILTIN_NET_ID,
- UDEV_BUILTIN_NET_LINK,
- UDEV_BUILTIN_PATH_ID,
- UDEV_BUILTIN_USB_ID,
-#ifdef HAVE_ACL
- UDEV_BUILTIN_UACCESS,
-#endif
- UDEV_BUILTIN_MAX
-};
-struct udev_builtin {
- const char *name;
- int (*cmd)(struct udev_device *dev, int argc, char *argv[], bool test);
- const char *help;
- int (*init)(struct udev *udev);
- void (*exit)(struct udev *udev);
- bool (*validate)(struct udev *udev);
- bool run_once;
-};
-#ifdef HAVE_BLKID
-extern const struct udev_builtin udev_builtin_blkid;
-#endif
-extern const struct udev_builtin udev_builtin_btrfs;
-extern const struct udev_builtin udev_builtin_hwdb;
-extern const struct udev_builtin udev_builtin_input_id;
-extern const struct udev_builtin udev_builtin_keyboard;
-#ifdef HAVE_KMOD
-extern const struct udev_builtin udev_builtin_kmod;
-#endif
-extern const struct udev_builtin udev_builtin_net_id;
-extern const struct udev_builtin udev_builtin_net_setup_link;
-extern const struct udev_builtin udev_builtin_path_id;
-extern const struct udev_builtin udev_builtin_usb_id;
-extern const struct udev_builtin udev_builtin_uaccess;
-void udev_builtin_init(struct udev *udev);
-void udev_builtin_exit(struct udev *udev);
-enum udev_builtin_cmd udev_builtin_lookup(const char *command);
-const char *udev_builtin_name(enum udev_builtin_cmd cmd);
-bool udev_builtin_run_once(enum udev_builtin_cmd cmd);
-int udev_builtin_run(struct udev_device *dev, enum udev_builtin_cmd cmd, const char *command, bool test);
-void udev_builtin_list(struct udev *udev);
-bool udev_builtin_validate(struct udev *udev);
-int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val);
-int udev_builtin_hwdb_lookup(struct udev_device *dev, const char *prefix, const char *modalias,
- const char *filter, bool test);
-
-/* udevadm commands */
-struct udevadm_cmd {
- const char *name;
- int (*cmd)(struct udev *udev, int argc, char *argv[]);
- const char *help;
- int debug;
-};
-extern const struct udevadm_cmd udevadm_info;
-extern const struct udevadm_cmd udevadm_trigger;
-extern const struct udevadm_cmd udevadm_settle;
-extern const struct udevadm_cmd udevadm_control;
-extern const struct udevadm_cmd udevadm_monitor;
-extern const struct udevadm_cmd udevadm_hwdb;
-extern const struct udevadm_cmd udevadm_test;
-extern const struct udevadm_cmd udevadm_test_builtin;
diff --git a/src/udev/udev.pc.in b/src/udev/udev.pc.in
deleted file mode 100644
index a0c2e82d47..0000000000
--- a/src/udev/udev.pc.in
+++ /dev/null
@@ -1,5 +0,0 @@
-Name: udev
-Description: udev
-Version: @VERSION@
-
-udevdir=@udevlibexecdir@
diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c
deleted file mode 100644
index 6f8e96a123..0000000000
--- a/src/udev/udevadm-control.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2005-2011 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "time-util.h"
-#include "udev-util.h"
-#include "udev.h"
-
-static void print_help(void) {
- printf("%s control COMMAND\n\n"
- "Control the udev daemon.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " -e --exit Instruct the daemon to cleanup and exit\n"
- " -l --log-priority=LEVEL Set the udev log level for the daemon\n"
- " -s --stop-exec-queue Do not execute events, queue only\n"
- " -S --start-exec-queue Execute events, flush queue\n"
- " -R --reload Reload rules and databases\n"
- " -p --property=KEY=VALUE Set a global property for all events\n"
- " -m --children-max=N Maximum number of children\n"
- " --timeout=SECONDS Maximum time to block for a reply\n"
- , program_invocation_short_name);
-}
-
-static int adm_control(struct udev *udev, int argc, char *argv[]) {
- _cleanup_udev_ctrl_unref_ struct udev_ctrl *uctrl = NULL;
- int timeout = 60;
- int rc = 1, c;
-
- static const struct option options[] = {
- { "exit", no_argument, NULL, 'e' },
- { "log-priority", required_argument, NULL, 'l' },
- { "stop-exec-queue", no_argument, NULL, 's' },
- { "start-exec-queue", no_argument, NULL, 'S' },
- { "reload", no_argument, NULL, 'R' },
- { "reload-rules", no_argument, NULL, 'R' }, /* alias for -R */
- { "property", required_argument, NULL, 'p' },
- { "env", required_argument, NULL, 'p' }, /* alias for -p */
- { "children-max", required_argument, NULL, 'm' },
- { "timeout", required_argument, NULL, 't' },
- { "help", no_argument, NULL, 'h' },
- {}
- };
-
- if (getuid() != 0) {
- log_error("root privileges required");
- return 1;
- }
-
- uctrl = udev_ctrl_new(udev);
- if (uctrl == NULL)
- return 2;
-
- while ((c = getopt_long(argc, argv, "el:sSRp:m:h", options, NULL)) >= 0)
- switch (c) {
- case 'e':
- if (udev_ctrl_send_exit(uctrl, timeout) < 0)
- rc = 2;
- else
- rc = 0;
- break;
- case 'l': {
- int i;
-
- i = util_log_priority(optarg);
- if (i < 0) {
- log_error("invalid number '%s'", optarg);
- return rc;
- }
- if (udev_ctrl_send_set_log_level(uctrl, util_log_priority(optarg), timeout) < 0)
- rc = 2;
- else
- rc = 0;
- break;
- }
- case 's':
- if (udev_ctrl_send_stop_exec_queue(uctrl, timeout) < 0)
- rc = 2;
- else
- rc = 0;
- break;
- case 'S':
- if (udev_ctrl_send_start_exec_queue(uctrl, timeout) < 0)
- rc = 2;
- else
- rc = 0;
- break;
- case 'R':
- if (udev_ctrl_send_reload(uctrl, timeout) < 0)
- rc = 2;
- else
- rc = 0;
- break;
- case 'p':
- if (strchr(optarg, '=') == NULL) {
- log_error("expect <KEY>=<value> instead of '%s'", optarg);
- return rc;
- }
- if (udev_ctrl_send_set_env(uctrl, optarg, timeout) < 0)
- rc = 2;
- else
- rc = 0;
- break;
- case 'm': {
- char *endp;
- int i;
-
- i = strtoul(optarg, &endp, 0);
- if (endp[0] != '\0' || i < 1) {
- log_error("invalid number '%s'", optarg);
- return rc;
- }
- if (udev_ctrl_send_set_children_max(uctrl, i, timeout) < 0)
- rc = 2;
- else
- rc = 0;
- break;
- }
- case 't': {
- usec_t s;
- int seconds;
- int r;
-
- r = parse_sec(optarg, &s);
- if (r < 0)
- return log_error_errno(r, "Failed to parse timeout value '%s'.", optarg);
-
- if (((s + USEC_PER_SEC - 1) / USEC_PER_SEC) > INT_MAX)
- log_error("Timeout value is out of range.");
- else {
- seconds = s != USEC_INFINITY ? (int) ((s + USEC_PER_SEC - 1) / USEC_PER_SEC) : INT_MAX;
- timeout = seconds;
- rc = 0;
- }
- break;
- }
- case 'h':
- print_help();
- rc = 0;
- break;
- }
-
- if (optind < argc)
- log_error("Extraneous argument: %s", argv[optind]);
- else if (optind == 1)
- log_error("Option missing");
- return rc;
-}
-
-const struct udevadm_cmd udevadm_control = {
- .name = "control",
- .cmd = adm_control,
- .help = "Control the udev daemon",
-};
diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c
deleted file mode 100644
index 1bffe8e8ab..0000000000
--- a/src/udev/udevadm-hwdb.c
+++ /dev/null
@@ -1,698 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2012 Kay Sievers <kay@vrfy.org>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <ctype.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "alloc-util.h"
-#include "conf-files.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "hwdb-internal.h"
-#include "hwdb-util.h"
-#include "label.h"
-#include "mkdir.h"
-#include "strbuf.h"
-#include "string-util.h"
-#include "udev.h"
-#include "util.h"
-
-/*
- * Generic udev properties, key/value database based on modalias strings.
- * Uses a Patricia/radix trie to index all matches for efficient lookup.
- */
-
-static const char * const conf_file_dirs[] = {
- "/etc/udev/hwdb.d",
- UDEVLIBEXECDIR "/hwdb.d",
- NULL
-};
-
-/* in-memory trie objects */
-struct trie {
- struct trie_node *root;
- struct strbuf *strings;
-
- size_t nodes_count;
- size_t children_count;
- size_t values_count;
-};
-
-struct trie_node {
- /* prefix, common part for all children of this node */
- size_t prefix_off;
-
- /* sorted array of pointers to children nodes */
- struct trie_child_entry *children;
- uint8_t children_count;
-
- /* sorted array of key/value pairs */
- struct trie_value_entry *values;
- size_t values_count;
-};
-
-/* children array item with char (0-255) index */
-struct trie_child_entry {
- uint8_t c;
- struct trie_node *child;
-};
-
-/* value array item with key/value pairs */
-struct trie_value_entry {
- size_t key_off;
- size_t value_off;
-};
-
-static int trie_children_cmp(const void *v1, const void *v2) {
- const struct trie_child_entry *n1 = v1;
- const struct trie_child_entry *n2 = v2;
-
- return n1->c - n2->c;
-}
-
-static int node_add_child(struct trie *trie, struct trie_node *node, struct trie_node *node_child, uint8_t c) {
- struct trie_child_entry *child;
-
- /* extend array, add new entry, sort for bisection */
- child = realloc(node->children, (node->children_count + 1) * sizeof(struct trie_child_entry));
- if (!child)
- return -ENOMEM;
-
- node->children = child;
- trie->children_count++;
- node->children[node->children_count].c = c;
- node->children[node->children_count].child = node_child;
- node->children_count++;
- qsort(node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
- trie->nodes_count++;
-
- return 0;
-}
-
-static struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) {
- struct trie_child_entry *child;
- struct trie_child_entry search;
-
- search.c = c;
- child = bsearch(&search, node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
- if (child)
- return child->child;
- return NULL;
-}
-
-static void trie_node_cleanup(struct trie_node *node) {
- size_t i;
-
- for (i = 0; i < node->children_count; i++)
- trie_node_cleanup(node->children[i].child);
- free(node->children);
- free(node->values);
- free(node);
-}
-
-static int trie_values_cmp(const void *v1, const void *v2, void *arg) {
- const struct trie_value_entry *val1 = v1;
- const struct trie_value_entry *val2 = v2;
- struct trie *trie = arg;
-
- return strcmp(trie->strings->buf + val1->key_off,
- trie->strings->buf + val2->key_off);
-}
-
-static int trie_node_add_value(struct trie *trie, struct trie_node *node,
- const char *key, const char *value) {
- ssize_t k, v;
- struct trie_value_entry *val;
-
- k = strbuf_add_string(trie->strings, key, strlen(key));
- if (k < 0)
- return k;
- v = strbuf_add_string(trie->strings, value, strlen(value));
- if (v < 0)
- return v;
-
- if (node->values_count) {
- struct trie_value_entry search = {
- .key_off = k,
- .value_off = v,
- };
-
- val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
- if (val) {
- /* replace existing earlier key with new value */
- val->value_off = v;
- return 0;
- }
- }
-
- /* extend array, add new entry, sort for bisection */
- val = realloc(node->values, (node->values_count + 1) * sizeof(struct trie_value_entry));
- if (!val)
- return -ENOMEM;
- trie->values_count++;
- node->values = val;
- node->values[node->values_count].key_off = k;
- node->values[node->values_count].value_off = v;
- node->values_count++;
- qsort_r(node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
- return 0;
-}
-
-static int trie_insert(struct trie *trie, struct trie_node *node, const char *search,
- const char *key, const char *value) {
- size_t i = 0;
- int err = 0;
-
- for (;;) {
- size_t p;
- uint8_t c;
- struct trie_node *child;
-
- for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) {
- _cleanup_free_ char *s = NULL;
- ssize_t off;
- _cleanup_free_ struct trie_node *new_child = NULL;
-
- if (c == search[i + p])
- continue;
-
- /* split node */
- new_child = new0(struct trie_node, 1);
- if (!new_child)
- return -ENOMEM;
-
- /* move values from parent to child */
- new_child->prefix_off = node->prefix_off + p+1;
- new_child->children = node->children;
- new_child->children_count = node->children_count;
- new_child->values = node->values;
- new_child->values_count = node->values_count;
-
- /* update parent; use strdup() because the source gets realloc()d */
- s = strndup(trie->strings->buf + node->prefix_off, p);
- if (!s)
- return -ENOMEM;
-
- off = strbuf_add_string(trie->strings, s, p);
- if (off < 0)
- return off;
-
- node->prefix_off = off;
- node->children = NULL;
- node->children_count = 0;
- node->values = NULL;
- node->values_count = 0;
- err = node_add_child(trie, node, new_child, c);
- if (err)
- return err;
-
- new_child = NULL; /* avoid cleanup */
- break;
- }
- i += p;
-
- c = search[i];
- if (c == '\0')
- return trie_node_add_value(trie, node, key, value);
-
- child = node_lookup(node, c);
- if (!child) {
- ssize_t off;
-
- /* new child */
- child = new0(struct trie_node, 1);
- if (!child)
- return -ENOMEM;
-
- off = strbuf_add_string(trie->strings, search + i+1, strlen(search + i+1));
- if (off < 0) {
- free(child);
- return off;
- }
-
- child->prefix_off = off;
- err = node_add_child(trie, node, child, c);
- if (err) {
- free(child);
- return err;
- }
-
- return trie_node_add_value(trie, child, key, value);
- }
-
- node = child;
- i++;
- }
-}
-
-struct trie_f {
- FILE *f;
- struct trie *trie;
- uint64_t strings_off;
-
- uint64_t nodes_count;
- uint64_t children_count;
- uint64_t values_count;
-};
-
-/* calculate the storage space for the nodes, children arrays, value arrays */
-static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node) {
- uint64_t i;
-
- for (i = 0; i < node->children_count; i++)
- trie_store_nodes_size(trie, node->children[i].child);
-
- trie->strings_off += sizeof(struct trie_node_f);
- for (i = 0; i < node->children_count; i++)
- trie->strings_off += sizeof(struct trie_child_entry_f);
- for (i = 0; i < node->values_count; i++)
- trie->strings_off += sizeof(struct trie_value_entry_f);
-}
-
-static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) {
- uint64_t i;
- struct trie_node_f n = {
- .prefix_off = htole64(trie->strings_off + node->prefix_off),
- .children_count = node->children_count,
- .values_count = htole64(node->values_count),
- };
- struct trie_child_entry_f *children = NULL;
- int64_t node_off;
-
- if (node->children_count) {
- children = new0(struct trie_child_entry_f, node->children_count);
- if (!children)
- return -ENOMEM;
- }
-
- /* post-order recursion */
- for (i = 0; i < node->children_count; i++) {
- int64_t child_off;
-
- child_off = trie_store_nodes(trie, node->children[i].child);
- if (child_off < 0) {
- free(children);
- return child_off;
- }
- children[i].c = node->children[i].c;
- children[i].child_off = htole64(child_off);
- }
-
- /* write node */
- node_off = ftello(trie->f);
- fwrite(&n, sizeof(struct trie_node_f), 1, trie->f);
- trie->nodes_count++;
-
- /* append children array */
- if (node->children_count) {
- fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, trie->f);
- trie->children_count += node->children_count;
- free(children);
- }
-
- /* append values array */
- for (i = 0; i < node->values_count; i++) {
- struct trie_value_entry_f v = {
- .key_off = htole64(trie->strings_off + node->values[i].key_off),
- .value_off = htole64(trie->strings_off + node->values[i].value_off),
- };
-
- fwrite(&v, sizeof(struct trie_value_entry_f), 1, trie->f);
- trie->values_count++;
- }
-
- return node_off;
-}
-
-static int trie_store(struct trie *trie, const char *filename) {
- struct trie_f t = {
- .trie = trie,
- };
- _cleanup_free_ char *filename_tmp = NULL;
- int64_t pos;
- int64_t root_off;
- int64_t size;
- struct trie_header_f h = {
- .signature = HWDB_SIG,
- .tool_version = htole64(atoi(VERSION)),
- .header_size = htole64(sizeof(struct trie_header_f)),
- .node_size = htole64(sizeof(struct trie_node_f)),
- .child_entry_size = htole64(sizeof(struct trie_child_entry_f)),
- .value_entry_size = htole64(sizeof(struct trie_value_entry_f)),
- };
- int err;
-
- /* calculate size of header, nodes, children entries, value entries */
- t.strings_off = sizeof(struct trie_header_f);
- trie_store_nodes_size(&t, trie->root);
-
- err = fopen_temporary(filename , &t.f, &filename_tmp);
- if (err < 0)
- return err;
- fchmod(fileno(t.f), 0444);
-
- /* write nodes */
- err = fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET);
- if (err < 0) {
- fclose(t.f);
- unlink_noerrno(filename_tmp);
- return -errno;
- }
- root_off = trie_store_nodes(&t, trie->root);
- h.nodes_root_off = htole64(root_off);
- pos = ftello(t.f);
- h.nodes_len = htole64(pos - sizeof(struct trie_header_f));
-
- /* write string buffer */
- fwrite(trie->strings->buf, trie->strings->len, 1, t.f);
- h.strings_len = htole64(trie->strings->len);
-
- /* write header */
- size = ftello(t.f);
- h.file_size = htole64(size);
- err = fseeko(t.f, 0, SEEK_SET);
- if (err < 0) {
- fclose(t.f);
- unlink_noerrno(filename_tmp);
- return -errno;
- }
- fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
- err = ferror(t.f);
- if (err)
- err = -errno;
- fclose(t.f);
- if (err < 0 || rename(filename_tmp, filename) < 0) {
- unlink_noerrno(filename_tmp);
- return err < 0 ? err : -errno;
- }
-
- log_debug("=== trie on-disk ===");
- log_debug("size: %8"PRIi64" bytes", size);
- log_debug("header: %8zu bytes", sizeof(struct trie_header_f));
- log_debug("nodes: %8"PRIu64" bytes (%8"PRIu64")",
- t.nodes_count * sizeof(struct trie_node_f), t.nodes_count);
- log_debug("child pointers: %8"PRIu64" bytes (%8"PRIu64")",
- t.children_count * sizeof(struct trie_child_entry_f), t.children_count);
- log_debug("value pointers: %8"PRIu64" bytes (%8"PRIu64")",
- t.values_count * sizeof(struct trie_value_entry_f), t.values_count);
- log_debug("string store: %8zu bytes", trie->strings->len);
- log_debug("strings start: %8"PRIu64, t.strings_off);
-
- return 0;
-}
-
-static int insert_data(struct trie *trie, struct udev_list *match_list,
- char *line, const char *filename) {
- char *value;
- struct udev_list_entry *entry;
-
- value = strchr(line, '=');
- if (!value) {
- log_error("Error, key/value pair expected but got '%s' in '%s':", line, filename);
- return -EINVAL;
- }
-
- value[0] = '\0';
- value++;
-
- /* libudev requires properties to start with a space */
- while (isblank(line[0]) && isblank(line[1]))
- line++;
-
- if (line[0] == '\0' || value[0] == '\0') {
- log_error("Error, empty key or value '%s' in '%s':", line, filename);
- return -EINVAL;
- }
-
- udev_list_entry_foreach(entry, udev_list_get_entry(match_list))
- trie_insert(trie, trie->root, udev_list_entry_get_name(entry), line, value);
-
- return 0;
-}
-
-static int import_file(struct udev *udev, struct trie *trie, const char *filename) {
- enum {
- HW_MATCH,
- HW_DATA,
- HW_NONE,
- } state = HW_NONE;
- FILE *f;
- char line[LINE_MAX];
- struct udev_list match_list;
-
- udev_list_init(udev, &match_list, false);
-
- f = fopen(filename, "re");
- if (f == NULL)
- return -errno;
-
- while (fgets(line, sizeof(line), f)) {
- size_t len;
- char *pos;
-
- /* comment line */
- if (line[0] == '#')
- continue;
-
- /* strip trailing comment */
- pos = strchr(line, '#');
- if (pos)
- pos[0] = '\0';
-
- /* strip trailing whitespace */
- len = strlen(line);
- while (len > 0 && isspace(line[len-1]))
- len--;
- line[len] = '\0';
-
- switch (state) {
- case HW_NONE:
- if (len == 0)
- break;
-
- if (line[0] == ' ') {
- log_error("Error, MATCH expected but got '%s' in '%s':", line, filename);
- break;
- }
-
- /* start of record, first match */
- state = HW_MATCH;
- udev_list_entry_add(&match_list, line, NULL);
- break;
-
- case HW_MATCH:
- if (len == 0) {
- log_error("Error, DATA expected but got empty line in '%s':", filename);
- state = HW_NONE;
- udev_list_cleanup(&match_list);
- break;
- }
-
- /* another match */
- if (line[0] != ' ') {
- udev_list_entry_add(&match_list, line, NULL);
- break;
- }
-
- /* first data */
- state = HW_DATA;
- insert_data(trie, &match_list, line, filename);
- break;
-
- case HW_DATA:
- /* end of record */
- if (len == 0) {
- state = HW_NONE;
- udev_list_cleanup(&match_list);
- break;
- }
-
- if (line[0] != ' ') {
- log_error("Error, DATA expected but got '%s' in '%s':", line, filename);
- state = HW_NONE;
- udev_list_cleanup(&match_list);
- break;
- }
-
- insert_data(trie, &match_list, line, filename);
- break;
- };
- }
-
- fclose(f);
- udev_list_cleanup(&match_list);
- return 0;
-}
-
-static void help(void) {
- printf("Usage: udevadm hwdb OPTIONS\n"
- " -u,--update update the hardware database\n"
- " --usr generate in " UDEVLIBEXECDIR " instead of /etc/udev\n"
- " -t,--test=MODALIAS query database and print result\n"
- " -r,--root=PATH alternative root path in the filesystem\n"
- " -h,--help\n\n");
-}
-
-static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
- enum {
- ARG_USR = 0x100,
- };
-
- static const struct option options[] = {
- { "update", no_argument, NULL, 'u' },
- { "usr", no_argument, NULL, ARG_USR },
- { "test", required_argument, NULL, 't' },
- { "root", required_argument, NULL, 'r' },
- { "help", no_argument, NULL, 'h' },
- {}
- };
- const char *test = NULL;
- const char *root = "";
- const char *hwdb_bin_dir = "/etc/udev";
- bool update = false;
- struct trie *trie = NULL;
- int err, c;
- int rc = EXIT_SUCCESS;
-
- while ((c = getopt_long(argc, argv, "ut:r:h", options, NULL)) >= 0)
- switch(c) {
- case 'u':
- update = true;
- break;
- case ARG_USR:
- hwdb_bin_dir = UDEVLIBEXECDIR;
- break;
- case 't':
- test = optarg;
- break;
- case 'r':
- root = optarg;
- break;
- case 'h':
- help();
- return EXIT_SUCCESS;
- case '?':
- return EXIT_FAILURE;
- default:
- assert_not_reached("Unknown option");
- }
-
- if (!update && !test) {
- log_error("Either --update or --test must be used");
- return EXIT_FAILURE;
- }
-
- if (update) {
- char **files, **f;
- _cleanup_free_ char *hwdb_bin = NULL;
-
- trie = new0(struct trie, 1);
- if (!trie) {
- rc = EXIT_FAILURE;
- goto out;
- }
-
- /* string store */
- trie->strings = strbuf_new();
- if (!trie->strings) {
- rc = EXIT_FAILURE;
- goto out;
- }
-
- /* index */
- trie->root = new0(struct trie_node, 1);
- if (!trie->root) {
- rc = EXIT_FAILURE;
- goto out;
- }
- trie->nodes_count++;
-
- err = conf_files_list_strv(&files, ".hwdb", root, conf_file_dirs);
- if (err < 0) {
- log_error_errno(err, "failed to enumerate hwdb files: %m");
- rc = EXIT_FAILURE;
- goto out;
- }
- STRV_FOREACH(f, files) {
- log_debug("reading file '%s'", *f);
- import_file(udev, trie, *f);
- }
- strv_free(files);
-
- strbuf_complete(trie->strings);
-
- log_debug("=== trie in-memory ===");
- log_debug("nodes: %8zu bytes (%8zu)",
- trie->nodes_count * sizeof(struct trie_node), trie->nodes_count);
- log_debug("children arrays: %8zu bytes (%8zu)",
- trie->children_count * sizeof(struct trie_child_entry), trie->children_count);
- log_debug("values arrays: %8zu bytes (%8zu)",
- trie->values_count * sizeof(struct trie_value_entry), trie->values_count);
- log_debug("strings: %8zu bytes",
- trie->strings->len);
- log_debug("strings incoming: %8zu bytes (%8zu)",
- trie->strings->in_len, trie->strings->in_count);
- log_debug("strings dedup'ed: %8zu bytes (%8zu)",
- trie->strings->dedup_len, trie->strings->dedup_count);
-
- hwdb_bin = strjoin(root, "/", hwdb_bin_dir, "/hwdb.bin", NULL);
- if (!hwdb_bin) {
- rc = EXIT_FAILURE;
- goto out;
- }
-
- mkdir_parents_label(hwdb_bin, 0755);
-
- err = trie_store(trie, hwdb_bin);
- if (err < 0) {
- log_error_errno(err, "Failure writing database %s: %m", hwdb_bin);
- rc = EXIT_FAILURE;
- }
-
- label_fix(hwdb_bin, false, false);
- }
-
- if (test) {
- _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
- int r;
-
- r = sd_hwdb_new(&hwdb);
- if (r >= 0) {
- const char *key, *value;
-
- SD_HWDB_FOREACH_PROPERTY(hwdb, test, key, value)
- printf("%s=%s\n", key, value);
- }
- }
-out:
- if (trie) {
- if (trie->root)
- trie_node_cleanup(trie->root);
- strbuf_cleanup(trie->strings);
- free(trie);
- }
- return rc;
-}
-
-const struct udevadm_cmd udevadm_hwdb = {
- .name = "hwdb",
- .cmd = adm_hwdb,
-};
diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c
deleted file mode 100644
index 6753c52005..0000000000
--- a/src/udev/udevadm-info.c
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * Copyright (C) 2004-2009 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "fd-util.h"
-#include "string-util.h"
-#include "udev-util.h"
-#include "udev.h"
-#include "udevadm-util.h"
-
-static bool skip_attribute(const char *name) {
- static const char* const skip[] = {
- "uevent",
- "dev",
- "modalias",
- "resource",
- "driver",
- "subsystem",
- "module",
- };
- unsigned int i;
-
- for (i = 0; i < ELEMENTSOF(skip); i++)
- if (streq(name, skip[i]))
- return true;
- return false;
-}
-
-static void print_all_attributes(struct udev_device *device, const char *key) {
- struct udev_list_entry *sysattr;
-
- udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) {
- const char *name;
- const char *value;
- size_t len;
-
- name = udev_list_entry_get_name(sysattr);
- if (skip_attribute(name))
- continue;
-
- value = udev_device_get_sysattr_value(device, name);
- if (value == NULL)
- continue;
-
- /* skip any values that look like a path */
- if (value[0] == '/')
- continue;
-
- /* skip nonprintable attributes */
- len = strlen(value);
- while (len > 0 && isprint(value[len-1]))
- len--;
- if (len > 0)
- continue;
-
- printf(" %s{%s}==\"%s\"\n", key, name, value);
- }
- printf("\n");
-}
-
-static int print_device_chain(struct udev_device *device) {
- struct udev_device *device_parent;
- const char *str;
-
- printf("\n"
- "Udevadm info starts with the device specified by the devpath and then\n"
- "walks up the chain of parent devices. It prints for every device\n"
- "found, all possible attributes in the udev rules key format.\n"
- "A rule to match, can be composed by the attributes of the device\n"
- "and the attributes from one single parent device.\n"
- "\n");
-
- printf(" looking at device '%s':\n", udev_device_get_devpath(device));
- printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
- str = udev_device_get_subsystem(device);
- if (str == NULL)
- str = "";
- printf(" SUBSYSTEM==\"%s\"\n", str);
- str = udev_device_get_driver(device);
- if (str == NULL)
- str = "";
- printf(" DRIVER==\"%s\"\n", str);
- print_all_attributes(device, "ATTR");
-
- device_parent = device;
- do {
- device_parent = udev_device_get_parent(device_parent);
- if (device_parent == NULL)
- break;
- printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
- printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
- str = udev_device_get_subsystem(device_parent);
- if (str == NULL)
- str = "";
- printf(" SUBSYSTEMS==\"%s\"\n", str);
- str = udev_device_get_driver(device_parent);
- if (str == NULL)
- str = "";
- printf(" DRIVERS==\"%s\"\n", str);
- print_all_attributes(device_parent, "ATTRS");
- } while (device_parent != NULL);
-
- return 0;
-}
-
-static void print_record(struct udev_device *device) {
- const char *str;
- int i;
- struct udev_list_entry *list_entry;
-
- printf("P: %s\n", udev_device_get_devpath(device));
-
- str = udev_device_get_devnode(device);
- if (str != NULL)
- printf("N: %s\n", str + strlen("/dev/"));
-
- i = udev_device_get_devlink_priority(device);
- if (i != 0)
- printf("L: %i\n", i);
-
- udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device))
- printf("S: %s\n", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
-
- udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
- printf("E: %s=%s\n",
- udev_list_entry_get_name(list_entry),
- udev_list_entry_get_value(list_entry));
- printf("\n");
-}
-
-static int stat_device(const char *name, bool export, const char *prefix) {
- struct stat statbuf;
-
- if (stat(name, &statbuf) != 0)
- return -errno;
-
- if (export) {
- if (prefix == NULL)
- prefix = "INFO_";
- printf("%sMAJOR=%u\n"
- "%sMINOR=%u\n",
- prefix, major(statbuf.st_dev),
- prefix, minor(statbuf.st_dev));
- } else
- printf("%u:%u\n", major(statbuf.st_dev), minor(statbuf.st_dev));
- return 0;
-}
-
-static int export_devices(struct udev *udev) {
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *udev_enumerate;
- struct udev_list_entry *list_entry;
-
- udev_enumerate = udev_enumerate_new(udev);
- if (udev_enumerate == NULL)
- return -ENOMEM;
-
- udev_enumerate_scan_devices(udev_enumerate);
- udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
- _cleanup_udev_device_unref_ struct udev_device *device;
-
- device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
- if (device != NULL)
- print_record(device);
- }
-
- return 0;
-}
-
-static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
- struct dirent *dent;
-
- if (depth <= 0)
- return;
-
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
- struct stat stats;
-
- if (dent->d_name[0] == '.')
- continue;
- if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
- continue;
- if ((stats.st_mode & mask) != 0)
- continue;
- if (S_ISDIR(stats.st_mode)) {
- _cleanup_closedir_ DIR *dir2;
-
- dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
- if (dir2 != NULL)
- cleanup_dir(dir2, mask, depth-1);
-
- (void) unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
- } else
- (void) unlinkat(dirfd(dir), dent->d_name, 0);
- }
-}
-
-static void cleanup_db(struct udev *udev) {
- _cleanup_closedir_ DIR *dir1 = NULL, *dir2 = NULL, *dir3 = NULL, *dir4 = NULL, *dir5 = NULL;
-
- (void) unlink("/run/udev/queue.bin");
-
- dir1 = opendir("/run/udev/data");
- if (dir1 != NULL)
- cleanup_dir(dir1, S_ISVTX, 1);
-
- dir2 = opendir("/run/udev/links");
- if (dir2 != NULL)
- cleanup_dir(dir2, 0, 2);
-
- dir3 = opendir("/run/udev/tags");
- if (dir3 != NULL)
- cleanup_dir(dir3, 0, 2);
-
- dir4 = opendir("/run/udev/static_node-tags");
- if (dir4 != NULL)
- cleanup_dir(dir4, 0, 2);
-
- dir5 = opendir("/run/udev/watch");
- if (dir5 != NULL)
- cleanup_dir(dir5, 0, 1);
-}
-
-static void help(void) {
-
- printf("%s info [OPTIONS] [DEVPATH|FILE]\n\n"
- "Query sysfs or the udev database.\n\n"
- " -h --help Print this message\n"
- " --version Print version of the program\n"
- " -q --query=TYPE Query device information:\n"
- " name Name of device node\n"
- " symlink Pointing to node\n"
- " path sysfs device path\n"
- " property The device properties\n"
- " all All values\n"
- " -p --path=SYSPATH sysfs device path used for query or attribute walk\n"
- " -n --name=NAME Node or symlink name used for query or attribute walk\n"
- " -r --root Prepend dev directory to path names\n"
- " -a --attribute-walk Print all key matches walking along the chain\n"
- " of parent devices\n"
- " -d --device-id-of-file=FILE Print major:minor of device containing this file\n"
- " -x --export Export key/value pairs\n"
- " -P --export-prefix Export the key name with a prefix\n"
- " -e --export-db Export the content of the udev database\n"
- " -c --cleanup-db Clean up the udev database\n"
- , program_invocation_short_name);
-}
-
-static int uinfo(struct udev *udev, int argc, char *argv[]) {
- _cleanup_udev_device_unref_ struct udev_device *device = NULL;
- bool root = 0;
- bool export = 0;
- const char *export_prefix = NULL;
- char name[UTIL_PATH_SIZE];
- struct udev_list_entry *list_entry;
- int c;
-
- static const struct option options[] = {
- { "name", required_argument, NULL, 'n' },
- { "path", required_argument, NULL, 'p' },
- { "query", required_argument, NULL, 'q' },
- { "attribute-walk", no_argument, NULL, 'a' },
- { "cleanup-db", no_argument, NULL, 'c' },
- { "export-db", no_argument, NULL, 'e' },
- { "root", no_argument, NULL, 'r' },
- { "device-id-of-file", required_argument, NULL, 'd' },
- { "export", no_argument, NULL, 'x' },
- { "export-prefix", required_argument, NULL, 'P' },
- { "version", no_argument, NULL, 'V' },
- { "help", no_argument, NULL, 'h' },
- {}
- };
-
- enum action_type {
- ACTION_QUERY,
- ACTION_ATTRIBUTE_WALK,
- ACTION_DEVICE_ID_FILE,
- } action = ACTION_QUERY;
-
- enum query_type {
- QUERY_NAME,
- QUERY_PATH,
- QUERY_SYMLINK,
- QUERY_PROPERTY,
- QUERY_ALL,
- } query = QUERY_ALL;
-
- while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL)) >= 0)
- switch (c) {
- case 'n': {
- if (device != NULL) {
- fprintf(stderr, "device already specified\n");
- return 2;
- }
-
- device = find_device(udev, optarg, "/dev/");
- if (device == NULL) {
- fprintf(stderr, "device node not found\n");
- return 2;
- }
- break;
- }
- case 'p':
- if (device != NULL) {
- fprintf(stderr, "device already specified\n");
- return 2;
- }
-
- device = find_device(udev, optarg, "/sys");
- if (device == NULL) {
- fprintf(stderr, "syspath not found\n");
- return 2;
- }
- break;
- case 'q':
- action = ACTION_QUERY;
- if (streq(optarg, "property") || streq(optarg, "env"))
- query = QUERY_PROPERTY;
- else if (streq(optarg, "name"))
- query = QUERY_NAME;
- else if (streq(optarg, "symlink"))
- query = QUERY_SYMLINK;
- else if (streq(optarg, "path"))
- query = QUERY_PATH;
- else if (streq(optarg, "all"))
- query = QUERY_ALL;
- else {
- fprintf(stderr, "unknown query type\n");
- return 3;
- }
- break;
- case 'r':
- root = true;
- break;
- case 'd':
- action = ACTION_DEVICE_ID_FILE;
- strscpy(name, sizeof(name), optarg);
- break;
- case 'a':
- action = ACTION_ATTRIBUTE_WALK;
- break;
- case 'e':
- if (export_devices(udev) < 0)
- return 1;
- return 0;
- case 'c':
- cleanup_db(udev);
- return 0;
- case 'x':
- export = true;
- break;
- case 'P':
- export_prefix = optarg;
- break;
- case 'V':
- printf("%s\n", VERSION);
- return 0;
- case 'h':
- help();
- return 0;
- default:
- return 1;
- }
-
- switch (action) {
- case ACTION_QUERY:
- if (!device) {
- if (!argv[optind]) {
- help();
- return 2;
- }
- device = find_device(udev, argv[optind], NULL);
- if (!device) {
- fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
- return 4;
- }
- }
-
- switch(query) {
- case QUERY_NAME: {
- const char *node = udev_device_get_devnode(device);
-
- if (node == NULL) {
- fprintf(stderr, "no device node found\n");
- return 5;
- }
-
- if (root)
- printf("%s\n", udev_device_get_devnode(device));
- else
- printf("%s\n", udev_device_get_devnode(device) + strlen("/dev/"));
- break;
- }
- case QUERY_SYMLINK:
- list_entry = udev_device_get_devlinks_list_entry(device);
- while (list_entry != NULL) {
- if (root)
- printf("%s", udev_list_entry_get_name(list_entry));
- else
- printf("%s", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
- list_entry = udev_list_entry_get_next(list_entry);
- if (list_entry != NULL)
- printf(" ");
- }
- printf("\n");
- break;
- case QUERY_PATH:
- printf("%s\n", udev_device_get_devpath(device));
- return 0;
- case QUERY_PROPERTY:
- list_entry = udev_device_get_properties_list_entry(device);
- while (list_entry != NULL) {
- if (export)
- printf("%s%s='%s'\n", strempty(export_prefix),
- udev_list_entry_get_name(list_entry),
- udev_list_entry_get_value(list_entry));
- else
- printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
-
- list_entry = udev_list_entry_get_next(list_entry);
- }
- break;
- case QUERY_ALL:
- print_record(device);
- break;
- default:
- assert_not_reached("unknown query type");
- }
- break;
- case ACTION_ATTRIBUTE_WALK:
- if (!device && argv[optind]) {
- device = find_device(udev, argv[optind], NULL);
- if (!device) {
- fprintf(stderr, "Unknown device, absolute path in /dev/ or /sys expected.\n");
- return 4;
- }
- }
- if (!device) {
- fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
- return 4;
- }
- print_device_chain(device);
- break;
- case ACTION_DEVICE_ID_FILE:
- if (stat_device(name, export, export_prefix) != 0)
- return 1;
- break;
- }
-
- return 0;
-}
-
-const struct udevadm_cmd udevadm_info = {
- .name = "info",
- .cmd = uinfo,
- .help = "Query sysfs or the udev database",
-};
diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c
deleted file mode 100644
index f656c2198e..0000000000
--- a/src/udev/udevadm-monitor.c
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (C) 2004-2010 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/time.h>
-#include <time.h>
-
-#include "fd-util.h"
-#include "formats-util.h"
-#include "udev-util.h"
-#include "udev.h"
-
-static bool udev_exit;
-
-static void sig_handler(int signum) {
- if (signum == SIGINT || signum == SIGTERM)
- udev_exit = true;
-}
-
-static void print_device(struct udev_device *device, const char *source, int prop) {
- struct timespec ts;
-
- assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
- printf("%-6s[%"PRI_TIME".%06ld] %-8s %s (%s)\n",
- source,
- ts.tv_sec, ts.tv_nsec/1000,
- udev_device_get_action(device),
- udev_device_get_devpath(device),
- udev_device_get_subsystem(device));
- if (prop) {
- struct udev_list_entry *list_entry;
-
- udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
- printf("%s=%s\n",
- udev_list_entry_get_name(list_entry),
- udev_list_entry_get_value(list_entry));
- printf("\n");
- }
-}
-
-static void help(void) {
- printf("%s monitor [--property] [--kernel] [--udev] [--help]\n\n"
- "Listen to kernel and udev events.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " -p --property Print the event properties\n"
- " -k --kernel Print kernel uevents\n"
- " -u --udev Print udev events\n"
- " -s --subsystem-match=SUBSYSTEM[/DEVTYPE] Filter events by subsystem\n"
- " -t --tag-match=TAG Filter events by tag\n"
- , program_invocation_short_name);
-}
-
-static int adm_monitor(struct udev *udev, int argc, char *argv[]) {
- struct sigaction act = {};
- sigset_t mask;
- bool prop = false;
- bool print_kernel = false;
- bool print_udev = false;
- _cleanup_udev_list_cleanup_ struct udev_list subsystem_match_list;
- _cleanup_udev_list_cleanup_ struct udev_list tag_match_list;
- _cleanup_udev_monitor_unref_ struct udev_monitor *udev_monitor = NULL;
- _cleanup_udev_monitor_unref_ struct udev_monitor *kernel_monitor = NULL;
- _cleanup_close_ int fd_ep = -1;
- int fd_kernel = -1, fd_udev = -1;
- struct epoll_event ep_kernel, ep_udev;
- int c;
-
- static const struct option options[] = {
- { "property", no_argument, NULL, 'p' },
- { "environment", no_argument, NULL, 'e' }, /* alias for -p */
- { "kernel", no_argument, NULL, 'k' },
- { "udev", no_argument, NULL, 'u' },
- { "subsystem-match", required_argument, NULL, 's' },
- { "tag-match", required_argument, NULL, 't' },
- { "help", no_argument, NULL, 'h' },
- {}
- };
-
- udev_list_init(udev, &subsystem_match_list, true);
- udev_list_init(udev, &tag_match_list, true);
-
- while ((c = getopt_long(argc, argv, "pekus:t:h", options, NULL)) >= 0)
- switch (c) {
- case 'p':
- case 'e':
- prop = true;
- break;
- case 'k':
- print_kernel = true;
- break;
- case 'u':
- print_udev = true;
- break;
- case 's':
- {
- char subsys[UTIL_NAME_SIZE];
- char *devtype;
-
- strscpy(subsys, sizeof(subsys), optarg);
- devtype = strchr(subsys, '/');
- if (devtype != NULL) {
- devtype[0] = '\0';
- devtype++;
- }
- udev_list_entry_add(&subsystem_match_list, subsys, devtype);
- break;
- }
- case 't':
- udev_list_entry_add(&tag_match_list, optarg, NULL);
- break;
- case 'h':
- help();
- return 0;
- default:
- return 1;
- }
-
- if (!print_kernel && !print_udev) {
- print_kernel = true;
- print_udev = true;
- }
-
- /* set signal handlers */
- act.sa_handler = sig_handler;
- act.sa_flags = SA_RESTART;
- sigaction(SIGINT, &act, NULL);
- sigaction(SIGTERM, &act, NULL);
- sigemptyset(&mask);
- sigaddset(&mask, SIGINT);
- sigaddset(&mask, SIGTERM);
- sigprocmask(SIG_UNBLOCK, &mask, NULL);
-
- /* Callers are expecting to see events as they happen: Line buffering */
- setlinebuf(stdout);
-
- fd_ep = epoll_create1(EPOLL_CLOEXEC);
- if (fd_ep < 0) {
- log_error_errno(errno, "error creating epoll fd: %m");
- return 1;
- }
-
- printf("monitor will print the received events for:\n");
- if (print_udev) {
- struct udev_list_entry *entry;
-
- udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
- if (udev_monitor == NULL) {
- fprintf(stderr, "error: unable to create netlink socket\n");
- return 1;
- }
- udev_monitor_set_receive_buffer_size(udev_monitor, 128*1024*1024);
- fd_udev = udev_monitor_get_fd(udev_monitor);
-
- udev_list_entry_foreach(entry, udev_list_get_entry(&subsystem_match_list)) {
- const char *subsys = udev_list_entry_get_name(entry);
- const char *devtype = udev_list_entry_get_value(entry);
-
- if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, subsys, devtype) < 0)
- fprintf(stderr, "error: unable to apply subsystem filter '%s'\n", subsys);
- }
-
- udev_list_entry_foreach(entry, udev_list_get_entry(&tag_match_list)) {
- const char *tag = udev_list_entry_get_name(entry);
-
- if (udev_monitor_filter_add_match_tag(udev_monitor, tag) < 0)
- fprintf(stderr, "error: unable to apply tag filter '%s'\n", tag);
- }
-
- if (udev_monitor_enable_receiving(udev_monitor) < 0) {
- fprintf(stderr, "error: unable to subscribe to udev events\n");
- return 2;
- }
-
- memzero(&ep_udev, sizeof(struct epoll_event));
- ep_udev.events = EPOLLIN;
- ep_udev.data.fd = fd_udev;
- if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) {
- log_error_errno(errno, "fail to add fd to epoll: %m");
- return 2;
- }
-
- printf("UDEV - the event which udev sends out after rule processing\n");
- }
-
- if (print_kernel) {
- struct udev_list_entry *entry;
-
- kernel_monitor = udev_monitor_new_from_netlink(udev, "kernel");
- if (kernel_monitor == NULL) {
- fprintf(stderr, "error: unable to create netlink socket\n");
- return 3;
- }
- udev_monitor_set_receive_buffer_size(kernel_monitor, 128*1024*1024);
- fd_kernel = udev_monitor_get_fd(kernel_monitor);
-
- udev_list_entry_foreach(entry, udev_list_get_entry(&subsystem_match_list)) {
- const char *subsys = udev_list_entry_get_name(entry);
-
- if (udev_monitor_filter_add_match_subsystem_devtype(kernel_monitor, subsys, NULL) < 0)
- fprintf(stderr, "error: unable to apply subsystem filter '%s'\n", subsys);
- }
-
- if (udev_monitor_enable_receiving(kernel_monitor) < 0) {
- fprintf(stderr, "error: unable to subscribe to kernel events\n");
- return 4;
- }
-
- memzero(&ep_kernel, sizeof(struct epoll_event));
- ep_kernel.events = EPOLLIN;
- ep_kernel.data.fd = fd_kernel;
- if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_kernel, &ep_kernel) < 0) {
- log_error_errno(errno, "fail to add fd to epoll: %m");
- return 5;
- }
-
- printf("KERNEL - the kernel uevent\n");
- }
- printf("\n");
-
- while (!udev_exit) {
- int fdcount;
- struct epoll_event ev[4];
- int i;
-
- fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1);
- if (fdcount < 0) {
- if (errno != EINTR)
- fprintf(stderr, "error receiving uevent message: %m\n");
- continue;
- }
-
- for (i = 0; i < fdcount; i++) {
- if (ev[i].data.fd == fd_kernel && ev[i].events & EPOLLIN) {
- struct udev_device *device;
-
- device = udev_monitor_receive_device(kernel_monitor);
- if (device == NULL)
- continue;
- print_device(device, "KERNEL", prop);
- udev_device_unref(device);
- } else if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) {
- struct udev_device *device;
-
- device = udev_monitor_receive_device(udev_monitor);
- if (device == NULL)
- continue;
- print_device(device, "UDEV", prop);
- udev_device_unref(device);
- }
- }
- }
-
- return 0;
-}
-
-const struct udevadm_cmd udevadm_monitor = {
- .name = "monitor",
- .cmd = adm_monitor,
- .help = "Listen to kernel and udev events",
-};
diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c
deleted file mode 100644
index 6a5dc6e9e4..0000000000
--- a/src/udev/udevadm-settle.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2006-2009 Kay Sievers <kay@vrfy.org>
- * Copyright (C) 2009 Canonical Ltd.
- * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <poll.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "parse-util.h"
-#include "udev.h"
-#include "util.h"
-
-static void help(void) {
- printf("%s settle OPTIONS\n\n"
- "Wait for pending udev events.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " -t --timeout=SECONDS Maximum time to wait for events\n"
- " -E --exit-if-exists=FILE Stop waiting if file exists\n"
- , program_invocation_short_name);
-}
-
-static int adm_settle(struct udev *udev, int argc, char *argv[]) {
- static const struct option options[] = {
- { "timeout", required_argument, NULL, 't' },
- { "exit-if-exists", required_argument, NULL, 'E' },
- { "help", no_argument, NULL, 'h' },
- { "seq-start", required_argument, NULL, 's' }, /* removed */
- { "seq-end", required_argument, NULL, 'e' }, /* removed */
- { "quiet", no_argument, NULL, 'q' }, /* removed */
- {}
- };
- usec_t deadline;
- const char *exists = NULL;
- unsigned int timeout = 120;
- struct pollfd pfd[1] = { {.fd = -1}, };
- int c;
- struct udev_queue *queue;
- int rc = EXIT_FAILURE;
-
- while ((c = getopt_long(argc, argv, "t:E:hs:e:q", options, NULL)) >= 0) {
- switch (c) {
-
- case 't': {
- int r;
-
- r = safe_atou(optarg, &timeout);
- if (r < 0) {
- log_error_errno(r, "Invalid timeout value '%s': %m", optarg);
- return EXIT_FAILURE;
- }
- break;
- }
-
- case 'E':
- exists = optarg;
- break;
-
- case 'h':
- help();
- return EXIT_SUCCESS;
-
- case 's':
- case 'e':
- case 'q':
- log_info("Option -%c no longer supported.", c);
- return EXIT_FAILURE;
-
- case '?':
- return EXIT_FAILURE;
-
- default:
- assert_not_reached("Unknown argument");
- }
- }
-
- if (optind < argc) {
- fprintf(stderr, "Extraneous argument: '%s'\n", argv[optind]);
- return EXIT_FAILURE;
- }
-
- deadline = now(CLOCK_MONOTONIC) + timeout * USEC_PER_SEC;
-
- /* guarantee that the udev daemon isn't pre-processing */
- if (getuid() == 0) {
- struct udev_ctrl *uctrl;
-
- uctrl = udev_ctrl_new(udev);
- if (uctrl != NULL) {
- if (udev_ctrl_send_ping(uctrl, MAX(5U, timeout)) < 0) {
- log_debug("no connection to daemon");
- udev_ctrl_unref(uctrl);
- return EXIT_SUCCESS;
- }
- udev_ctrl_unref(uctrl);
- }
- }
-
- queue = udev_queue_new(udev);
- if (!queue) {
- log_error("unable to get udev queue");
- return EXIT_FAILURE;
- }
-
- pfd[0].events = POLLIN;
- pfd[0].fd = udev_queue_get_fd(queue);
- if (pfd[0].fd < 0) {
- log_debug("queue is empty, nothing to watch");
- rc = EXIT_SUCCESS;
- goto out;
- }
-
- for (;;) {
- if (exists && access(exists, F_OK) >= 0) {
- rc = EXIT_SUCCESS;
- break;
- }
-
- /* exit if queue is empty */
- if (udev_queue_get_queue_is_empty(queue)) {
- rc = EXIT_SUCCESS;
- break;
- }
-
- if (now(CLOCK_MONOTONIC) >= deadline)
- break;
-
- /* wake up when queue is empty */
- if (poll(pfd, 1, MSEC_PER_SEC) > 0 && pfd[0].revents & POLLIN)
- udev_queue_flush(queue);
- }
-
-out:
- udev_queue_unref(queue);
- return rc;
-}
-
-const struct udevadm_cmd udevadm_settle = {
- .name = "settle",
- .cmd = adm_settle,
- .help = "Wait for pending udev events",
-};
diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c
deleted file mode 100644
index 0b180d03eb..0000000000
--- a/src/udev/udevadm-test-builtin.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2011 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "string-util.h"
-#include "udev.h"
-
-static void help(struct udev *udev) {
- printf("%s builtin [--help] COMMAND SYSPATH\n\n"
- "Test a built-in command.\n\n"
- " -h --help Print this message\n"
- " --version Print version of the program\n\n"
- "Commands:\n"
- , program_invocation_short_name);
-
- udev_builtin_list(udev);
-}
-
-static int adm_builtin(struct udev *udev, int argc, char *argv[]) {
- static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- {}
- };
- char *command = NULL;
- char *syspath = NULL;
- char filename[UTIL_PATH_SIZE];
- struct udev_device *dev = NULL;
- enum udev_builtin_cmd cmd;
- int rc = EXIT_SUCCESS, c;
-
- while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
- switch (c) {
- case 'h':
- help(udev);
- goto out;
- }
-
- command = argv[optind++];
- if (command == NULL) {
- fprintf(stderr, "command missing\n");
- help(udev);
- rc = 2;
- goto out;
- }
-
- syspath = argv[optind++];
- if (syspath == NULL) {
- fprintf(stderr, "syspath missing\n");
- rc = 3;
- goto out;
- }
-
- udev_builtin_init(udev);
-
- cmd = udev_builtin_lookup(command);
- if (cmd >= UDEV_BUILTIN_MAX) {
- fprintf(stderr, "unknown command '%s'\n", command);
- help(udev);
- rc = 5;
- goto out;
- }
-
- /* add /sys if needed */
- if (!startswith(syspath, "/sys"))
- strscpyl(filename, sizeof(filename), "/sys", syspath, NULL);
- else
- strscpy(filename, sizeof(filename), syspath);
- util_remove_trailing_chars(filename, '/');
-
- dev = udev_device_new_from_syspath(udev, filename);
- if (dev == NULL) {
- fprintf(stderr, "unable to open device '%s'\n\n", filename);
- rc = 4;
- goto out;
- }
-
- rc = udev_builtin_run(dev, cmd, command, true);
- if (rc < 0) {
- fprintf(stderr, "error executing '%s', exit code %i\n\n", command, rc);
- rc = 6;
- }
-out:
- udev_device_unref(dev);
- udev_builtin_exit(udev);
- return rc;
-}
-
-const struct udevadm_cmd udevadm_test_builtin = {
- .name = "test-builtin",
- .cmd = adm_builtin,
- .help = "Test a built-in command",
- .debug = true,
-};
diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c
deleted file mode 100644
index 702dbe5282..0000000000
--- a/src/udev/udevadm-test.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2004-2008 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/signalfd.h>
-#include <unistd.h>
-
-#include "string-util.h"
-#include "udev-util.h"
-#include "udev.h"
-
-static void help(void) {
-
- printf("%s test OPTIONS <syspath>\n\n"
- "Test an event run.\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " -a --action=ACTION Set action string\n"
- " -N --resolve-names=early|late|never When to resolve names\n"
- , program_invocation_short_name);
-}
-
-static int adm_test(struct udev *udev, int argc, char *argv[]) {
- int resolve_names = 1;
- char filename[UTIL_PATH_SIZE];
- const char *action = "add";
- const char *syspath = NULL;
- struct udev_list_entry *entry;
- _cleanup_udev_rules_unref_ struct udev_rules *rules = NULL;
- _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
- _cleanup_udev_event_unref_ struct udev_event *event = NULL;
- sigset_t mask, sigmask_orig;
- int rc = 0, c;
-
- static const struct option options[] = {
- { "action", required_argument, NULL, 'a' },
- { "resolve-names", required_argument, NULL, 'N' },
- { "help", no_argument, NULL, 'h' },
- {}
- };
-
- log_debug("version %s", VERSION);
-
- while ((c = getopt_long(argc, argv, "a:N:h", options, NULL)) >= 0)
- switch (c) {
- case 'a':
- action = optarg;
- break;
- case 'N':
- if (streq (optarg, "early")) {
- resolve_names = 1;
- } else if (streq (optarg, "late")) {
- resolve_names = 0;
- } else if (streq (optarg, "never")) {
- resolve_names = -1;
- } else {
- fprintf(stderr, "resolve-names must be early, late or never\n");
- log_error("resolve-names must be early, late or never");
- exit(EXIT_FAILURE);
- }
- break;
- case 'h':
- help();
- exit(EXIT_SUCCESS);
- case '?':
- exit(EXIT_FAILURE);
- default:
- assert_not_reached("Unknown option");
- }
-
- syspath = argv[optind];
- if (syspath == NULL) {
- fprintf(stderr, "syspath parameter missing\n");
- rc = 2;
- goto out;
- }
-
- printf("This program is for debugging only, it does not run any program\n"
- "specified by a RUN key. It may show incorrect results, because\n"
- "some values may be different, or not available at a simulation run.\n"
- "\n");
-
- sigprocmask(SIG_SETMASK, NULL, &sigmask_orig);
-
- udev_builtin_init(udev);
-
- rules = udev_rules_new(udev, resolve_names);
- if (rules == NULL) {
- fprintf(stderr, "error reading rules\n");
- rc = 3;
- goto out;
- }
-
- /* add /sys if needed */
- if (!startswith(syspath, "/sys"))
- strscpyl(filename, sizeof(filename), "/sys", syspath, NULL);
- else
- strscpy(filename, sizeof(filename), syspath);
- util_remove_trailing_chars(filename, '/');
-
- dev = udev_device_new_from_synthetic_event(udev, filename, action);
- if (dev == NULL) {
- fprintf(stderr, "unable to open device '%s'\n", filename);
- rc = 4;
- goto out;
- }
-
- /* don't read info from the db */
- udev_device_set_info_loaded(dev);
-
- event = udev_event_new(dev);
-
- sigfillset(&mask);
- sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
-
- udev_event_execute_rules(event,
- 60 * USEC_PER_SEC, 20 * USEC_PER_SEC,
- NULL,
- rules);
-
- udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev))
- printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
-
- udev_list_entry_foreach(entry, udev_list_get_entry(&event->run_list)) {
- char program[UTIL_PATH_SIZE];
-
- udev_event_apply_format(event, udev_list_entry_get_name(entry), program, sizeof(program));
- printf("run: '%s'\n", program);
- }
-out:
- udev_builtin_exit(udev);
- return rc;
-}
-
-const struct udevadm_cmd udevadm_test = {
- .name = "test",
- .cmd = adm_test,
- .help = "Test an event run",
- .debug = true,
-};
diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c
deleted file mode 100644
index 9d52345d92..0000000000
--- a/src/udev/udevadm-trigger.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright (C) 2008-2009 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "string-util.h"
-#include "udev-util.h"
-#include "udev.h"
-#include "udevadm-util.h"
-#include "util.h"
-
-static int verbose;
-static int dry_run;
-
-static void exec_list(struct udev_enumerate *udev_enumerate, const char *action) {
- struct udev_list_entry *entry;
-
- udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(udev_enumerate)) {
- char filename[UTIL_PATH_SIZE];
- int fd;
-
- if (verbose)
- printf("%s\n", udev_list_entry_get_name(entry));
- if (dry_run)
- continue;
- strscpyl(filename, sizeof(filename), udev_list_entry_get_name(entry), "/uevent", NULL);
- fd = open(filename, O_WRONLY|O_CLOEXEC);
- if (fd < 0)
- continue;
- if (write(fd, action, strlen(action)) < 0)
- log_debug_errno(errno, "error writing '%s' to '%s': %m", action, filename);
- close(fd);
- }
-}
-
-static const char *keyval(const char *str, const char **val, char *buf, size_t size) {
- char *pos;
-
- strscpy(buf, size,str);
- pos = strchr(buf, '=');
- if (pos != NULL) {
- pos[0] = 0;
- pos++;
- }
- *val = pos;
- return buf;
-}
-
-static void help(void) {
- printf("%s trigger OPTIONS\n\n"
- "Request events from the kernel.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " -v --verbose Print the list of devices while running\n"
- " -n --dry-run Do not actually trigger the events\n"
- " -t --type= Type of events to trigger\n"
- " devices sysfs devices (default)\n"
- " subsystems sysfs subsystems and drivers\n"
- " -c --action=ACTION Event action value, default is \"change\"\n"
- " -s --subsystem-match=SUBSYSTEM Trigger devices from a matching subsystem\n"
- " -S --subsystem-nomatch=SUBSYSTEM Exclude devices from a matching subsystem\n"
- " -a --attr-match=FILE[=VALUE] Trigger devices with a matching attribute\n"
- " -A --attr-nomatch=FILE[=VALUE] Exclude devices with a matching attribute\n"
- " -p --property-match=KEY=VALUE Trigger devices with a matching property\n"
- " -g --tag-match=KEY=VALUE Trigger devices with a matching property\n"
- " -y --sysname-match=NAME Trigger devices with this /sys path\n"
- " --name-match=NAME Trigger devices with this /dev name\n"
- " -b --parent-match=NAME Trigger devices with that parent device\n"
- , program_invocation_short_name);
-}
-
-static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
- enum {
- ARG_NAME = 0x100,
- };
-
- static const struct option options[] = {
- { "verbose", no_argument, NULL, 'v' },
- { "dry-run", no_argument, NULL, 'n' },
- { "type", required_argument, NULL, 't' },
- { "action", required_argument, NULL, 'c' },
- { "subsystem-match", required_argument, NULL, 's' },
- { "subsystem-nomatch", required_argument, NULL, 'S' },
- { "attr-match", required_argument, NULL, 'a' },
- { "attr-nomatch", required_argument, NULL, 'A' },
- { "property-match", required_argument, NULL, 'p' },
- { "tag-match", required_argument, NULL, 'g' },
- { "sysname-match", required_argument, NULL, 'y' },
- { "name-match", required_argument, NULL, ARG_NAME },
- { "parent-match", required_argument, NULL, 'b' },
- { "help", no_argument, NULL, 'h' },
- {}
- };
- enum {
- TYPE_DEVICES,
- TYPE_SUBSYSTEMS,
- } device_type = TYPE_DEVICES;
- const char *action = "change";
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *udev_enumerate = NULL;
- int c, r;
-
- udev_enumerate = udev_enumerate_new(udev);
- if (udev_enumerate == NULL)
- return 1;
-
- while ((c = getopt_long(argc, argv, "vno:t:c:s:S:a:A:p:g:y:b:h", options, NULL)) >= 0) {
- const char *key;
- const char *val;
- char buf[UTIL_PATH_SIZE];
-
- switch (c) {
- case 'v':
- verbose = 1;
- break;
- case 'n':
- dry_run = 1;
- break;
- case 't':
- if (streq(optarg, "devices"))
- device_type = TYPE_DEVICES;
- else if (streq(optarg, "subsystems"))
- device_type = TYPE_SUBSYSTEMS;
- else {
- log_error("unknown type --type=%s", optarg);
- return 2;
- }
- break;
- case 'c':
- if (!nulstr_contains("add\0" "remove\0" "change\0", optarg)) {
- log_error("unknown action '%s'", optarg);
- return 2;
- } else
- action = optarg;
-
- break;
- case 's':
- r = udev_enumerate_add_match_subsystem(udev_enumerate, optarg);
- if (r < 0) {
- log_error_errno(r, "could not add subsystem match '%s': %m", optarg);
- return 2;
- }
- break;
- case 'S':
- r = udev_enumerate_add_nomatch_subsystem(udev_enumerate, optarg);
- if (r < 0) {
- log_error_errno(r, "could not add negative subsystem match '%s': %m", optarg);
- return 2;
- }
- break;
- case 'a':
- key = keyval(optarg, &val, buf, sizeof(buf));
- r = udev_enumerate_add_match_sysattr(udev_enumerate, key, val);
- if (r < 0) {
- log_error_errno(r, "could not add sysattr match '%s=%s': %m", key, val);
- return 2;
- }
- break;
- case 'A':
- key = keyval(optarg, &val, buf, sizeof(buf));
- r = udev_enumerate_add_nomatch_sysattr(udev_enumerate, key, val);
- if (r < 0) {
- log_error_errno(r, "could not add negative sysattr match '%s=%s': %m", key, val);
- return 2;
- }
- break;
- case 'p':
- key = keyval(optarg, &val, buf, sizeof(buf));
- r = udev_enumerate_add_match_property(udev_enumerate, key, val);
- if (r < 0) {
- log_error_errno(r, "could not add property match '%s=%s': %m", key, val);
- return 2;
- }
- break;
- case 'g':
- r = udev_enumerate_add_match_tag(udev_enumerate, optarg);
- if (r < 0) {
- log_error_errno(r, "could not add tag match '%s': %m", optarg);
- return 2;
- }
- break;
- case 'y':
- r = udev_enumerate_add_match_sysname(udev_enumerate, optarg);
- if (r < 0) {
- log_error_errno(r, "could not add sysname match '%s': %m", optarg);
- return 2;
- }
- break;
- case 'b': {
- _cleanup_udev_device_unref_ struct udev_device *dev;
-
- dev = find_device(udev, optarg, "/sys");
- if (dev == NULL) {
- log_error("unable to open the device '%s'", optarg);
- return 2;
- }
-
- r = udev_enumerate_add_match_parent(udev_enumerate, dev);
- if (r < 0) {
- log_error_errno(r, "could not add parent match '%s': %m", optarg);
- return 2;
- }
- break;
- }
-
- case ARG_NAME: {
- _cleanup_udev_device_unref_ struct udev_device *dev;
-
- dev = find_device(udev, optarg, "/dev/");
- if (dev == NULL) {
- log_error("unable to open the device '%s'", optarg);
- return 2;
- }
-
- r = udev_enumerate_add_match_parent(udev_enumerate, dev);
- if (r < 0) {
- log_error_errno(r, "could not add parent match '%s': %m", optarg);
- return 2;
- }
- break;
- }
-
- case 'h':
- help();
- return 0;
- case '?':
- return 1;
- default:
- assert_not_reached("Unknown option");
- }
- }
-
- for (; optind < argc; optind++) {
- _cleanup_udev_device_unref_ struct udev_device *dev;
-
- dev = find_device(udev, argv[optind], NULL);
- if (dev == NULL) {
- log_error("unable to open the device '%s'", argv[optind]);
- return 2;
- }
-
- r = udev_enumerate_add_match_parent(udev_enumerate, dev);
- if (r < 0) {
- log_error_errno(r, "could not add tag match '%s': %m", optarg);
- return 2;
- }
- }
-
- switch (device_type) {
- case TYPE_SUBSYSTEMS:
- udev_enumerate_scan_subsystems(udev_enumerate);
- exec_list(udev_enumerate, action);
- return 0;
- case TYPE_DEVICES:
- udev_enumerate_scan_devices(udev_enumerate);
- exec_list(udev_enumerate, action);
- return 0;
- default:
- assert_not_reached("device_type");
- }
-}
-
-const struct udevadm_cmd udevadm_trigger = {
- .name = "trigger",
- .cmd = adm_trigger,
- .help = "Request events from the kernel",
-};
diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c
deleted file mode 100644
index 3539c1d6ab..0000000000
--- a/src/udev/udevadm-util.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2008-2009 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "string-util.h"
-#include "udevadm-util.h"
-
-struct udev_device *find_device(struct udev *udev,
- const char *id,
- const char *prefix) {
-
- assert(udev);
- assert(id);
-
- if (prefix && !startswith(id, prefix))
- id = strjoina(prefix, id);
-
- if (startswith(id, "/dev/")) {
- struct stat statbuf;
- char type;
-
- if (stat(id, &statbuf) < 0)
- return NULL;
-
- if (S_ISBLK(statbuf.st_mode))
- type = 'b';
- else if (S_ISCHR(statbuf.st_mode))
- type = 'c';
- else
- return NULL;
-
- return udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
- } else if (startswith(id, "/sys/"))
- return udev_device_new_from_syspath(udev, id);
- else
- return NULL;
-}
diff --git a/src/udev/udevadm-util.h b/src/udev/udevadm-util.h
deleted file mode 100644
index dc712b0d93..0000000000
--- a/src/udev/udevadm-util.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2014 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "udev.h"
-
-struct udev_device *find_device(struct udev *udev,
- const char *id,
- const char *prefix);
diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c
deleted file mode 100644
index a6a873e5de..0000000000
--- a/src/udev/udevadm.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Kay Sievers <kay@vrfy.org>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <stddef.h>
-#include <stdio.h>
-
-#include "selinux-util.h"
-#include "string-util.h"
-#include "udev.h"
-
-static int adm_version(struct udev *udev, int argc, char *argv[]) {
- printf("%s\n", VERSION);
- return 0;
-}
-
-static const struct udevadm_cmd udevadm_version = {
- .name = "version",
- .cmd = adm_version,
-};
-
-static int adm_help(struct udev *udev, int argc, char *argv[]);
-
-static const struct udevadm_cmd udevadm_help = {
- .name = "help",
- .cmd = adm_help,
-};
-
-static const struct udevadm_cmd *udevadm_cmds[] = {
- &udevadm_info,
- &udevadm_trigger,
- &udevadm_settle,
- &udevadm_control,
- &udevadm_monitor,
- &udevadm_hwdb,
- &udevadm_test,
- &udevadm_test_builtin,
- &udevadm_version,
- &udevadm_help,
-};
-
-static int adm_help(struct udev *udev, int argc, char *argv[]) {
- unsigned int i;
-
- printf("%s [--help] [--version] [--debug] COMMAND [COMMAND OPTIONS]\n\n"
- "Send control commands or test the device manager.\n\n"
- "Commands:\n"
- , program_invocation_short_name);
-
- for (i = 0; i < ELEMENTSOF(udevadm_cmds); i++)
- if (udevadm_cmds[i]->help != NULL)
- printf(" %-12s %s\n", udevadm_cmds[i]->name, udevadm_cmds[i]->help);
- return 0;
-}
-
-static int run_command(struct udev *udev, const struct udevadm_cmd *cmd, int argc, char *argv[]) {
- if (cmd->debug)
- log_set_max_level(LOG_DEBUG);
- log_debug("calling: %s", cmd->name);
- return cmd->cmd(udev, argc, argv);
-}
-
-int main(int argc, char *argv[]) {
- struct udev *udev;
- static const struct option options[] = {
- { "debug", no_argument, NULL, 'd' },
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, 'V' },
- {}
- };
- const char *command;
- unsigned int i;
- int rc = 1, c;
-
- udev = udev_new();
- if (udev == NULL)
- goto out;
-
- log_parse_environment();
- log_open();
- mac_selinux_init();
-
- while ((c = getopt_long(argc, argv, "+dhV", options, NULL)) >= 0)
- switch (c) {
-
- case 'd':
- log_set_max_level(LOG_DEBUG);
- break;
-
- case 'h':
- rc = adm_help(udev, argc, argv);
- goto out;
-
- case 'V':
- rc = adm_version(udev, argc, argv);
- goto out;
-
- default:
- goto out;
- }
-
- command = argv[optind];
-
- if (command != NULL)
- for (i = 0; i < ELEMENTSOF(udevadm_cmds); i++)
- if (streq(udevadm_cmds[i]->name, command)) {
- argc -= optind;
- argv += optind;
- /* we need '0' here to reset the internal state */
- optind = 0;
- rc = run_command(udev, udevadm_cmds[i], argc, argv);
- goto out;
- }
-
- fprintf(stderr, "%s: missing or unknown command\n", program_invocation_short_name);
- rc = 2;
-out:
- mac_selinux_finish();
- udev_unref(udev);
- log_close();
- return rc;
-}
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
deleted file mode 100644
index badbab6205..0000000000
--- a/src/udev/udevd.c
+++ /dev/null
@@ -1,1757 +0,0 @@
-/*
- * Copyright (C) 2004-2012 Kay Sievers <kay@vrfy.org>
- * Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
- * Copyright (C) 2009 Canonical Ltd.
- * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/file.h>
-#include <sys/inotify.h>
-#include <sys/ioctl.h>
-#include <sys/mount.h>
-#include <sys/prctl.h>
-#include <sys/signalfd.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "sd-daemon.h"
-#include "sd-event.h"
-
-#include "alloc-util.h"
-#include "cgroup-util.h"
-#include "cpu-set-util.h"
-#include "dev-setup.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "formats-util.h"
-#include "fs-util.h"
-#include "hashmap.h"
-#include "io-util.h"
-#include "netlink-util.h"
-#include "parse-util.h"
-#include "proc-cmdline.h"
-#include "process-util.h"
-#include "selinux-util.h"
-#include "signal-util.h"
-#include "socket-util.h"
-#include "string-util.h"
-#include "terminal-util.h"
-#include "udev-util.h"
-#include "udev.h"
-#include "user-util.h"
-
-static bool arg_debug = false;
-static int arg_daemonize = false;
-static int arg_resolve_names = 1;
-static unsigned arg_children_max;
-static int arg_exec_delay;
-static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
-static usec_t arg_event_timeout_warn_usec = 180 * USEC_PER_SEC / 3;
-
-typedef struct Manager {
- struct udev *udev;
- sd_event *event;
- Hashmap *workers;
- struct udev_list_node events;
- const char *cgroup;
- pid_t pid; /* the process that originally allocated the manager object */
-
- struct udev_rules *rules;
- struct udev_list properties;
-
- struct udev_monitor *monitor;
- struct udev_ctrl *ctrl;
- struct udev_ctrl_connection *ctrl_conn_blocking;
- int fd_inotify;
- int worker_watch[2];
-
- sd_event_source *ctrl_event;
- sd_event_source *uevent_event;
- sd_event_source *inotify_event;
-
- usec_t last_usec;
-
- bool stop_exec_queue:1;
- bool exit:1;
-} Manager;
-
-enum event_state {
- EVENT_UNDEF,
- EVENT_QUEUED,
- EVENT_RUNNING,
-};
-
-struct event {
- struct udev_list_node node;
- Manager *manager;
- struct udev *udev;
- struct udev_device *dev;
- struct udev_device *dev_kernel;
- struct worker *worker;
- enum event_state state;
- unsigned long long int delaying_seqnum;
- unsigned long long int seqnum;
- const char *devpath;
- size_t devpath_len;
- const char *devpath_old;
- dev_t devnum;
- int ifindex;
- bool is_block;
- sd_event_source *timeout_warning;
- sd_event_source *timeout;
-};
-
-static inline struct event *node_to_event(struct udev_list_node *node) {
- return container_of(node, struct event, node);
-}
-
-static void event_queue_cleanup(Manager *manager, enum event_state type);
-
-enum worker_state {
- WORKER_UNDEF,
- WORKER_RUNNING,
- WORKER_IDLE,
- WORKER_KILLED,
-};
-
-struct worker {
- Manager *manager;
- struct udev_list_node node;
- int refcount;
- pid_t pid;
- struct udev_monitor *monitor;
- enum worker_state state;
- struct event *event;
-};
-
-/* passed from worker to main process */
-struct worker_message {
-};
-
-static void event_free(struct event *event) {
- int r;
-
- if (!event)
- return;
-
- udev_list_node_remove(&event->node);
- udev_device_unref(event->dev);
- udev_device_unref(event->dev_kernel);
-
- sd_event_source_unref(event->timeout_warning);
- sd_event_source_unref(event->timeout);
-
- if (event->worker)
- event->worker->event = NULL;
-
- assert(event->manager);
-
- if (udev_list_node_is_empty(&event->manager->events)) {
- /* only clean up the queue from the process that created it */
- if (event->manager->pid == getpid()) {
- r = unlink("/run/udev/queue");
- if (r < 0)
- log_warning_errno(errno, "could not unlink /run/udev/queue: %m");
- }
- }
-
- free(event);
-}
-
-static void worker_free(struct worker *worker) {
- if (!worker)
- return;
-
- assert(worker->manager);
-
- hashmap_remove(worker->manager->workers, PID_TO_PTR(worker->pid));
- udev_monitor_unref(worker->monitor);
- event_free(worker->event);
-
- free(worker);
-}
-
-static void manager_workers_free(Manager *manager) {
- struct worker *worker;
- Iterator i;
-
- assert(manager);
-
- HASHMAP_FOREACH(worker, manager->workers, i)
- worker_free(worker);
-
- manager->workers = hashmap_free(manager->workers);
-}
-
-static int worker_new(struct worker **ret, Manager *manager, struct udev_monitor *worker_monitor, pid_t pid) {
- _cleanup_free_ struct worker *worker = NULL;
- int r;
-
- assert(ret);
- assert(manager);
- assert(worker_monitor);
- assert(pid > 1);
-
- worker = new0(struct worker, 1);
- if (!worker)
- return -ENOMEM;
-
- worker->refcount = 1;
- worker->manager = manager;
- /* close monitor, but keep address around */
- udev_monitor_disconnect(worker_monitor);
- worker->monitor = udev_monitor_ref(worker_monitor);
- worker->pid = pid;
-
- r = hashmap_ensure_allocated(&manager->workers, NULL);
- if (r < 0)
- return r;
-
- r = hashmap_put(manager->workers, PID_TO_PTR(pid), worker);
- if (r < 0)
- return r;
-
- *ret = worker;
- worker = NULL;
-
- return 0;
-}
-
-static int on_event_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
- struct event *event = userdata;
-
- assert(event);
- assert(event->worker);
-
- kill_and_sigcont(event->worker->pid, SIGKILL);
- event->worker->state = WORKER_KILLED;
-
- log_error("seq %llu '%s' killed", udev_device_get_seqnum(event->dev), event->devpath);
-
- return 1;
-}
-
-static int on_event_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
- struct event *event = userdata;
-
- assert(event);
-
- log_warning("seq %llu '%s' is taking a long time", udev_device_get_seqnum(event->dev), event->devpath);
-
- return 1;
-}
-
-static void worker_attach_event(struct worker *worker, struct event *event) {
- sd_event *e;
- uint64_t usec;
-
- assert(worker);
- assert(worker->manager);
- assert(event);
- assert(!event->worker);
- assert(!worker->event);
-
- worker->state = WORKER_RUNNING;
- worker->event = event;
- event->state = EVENT_RUNNING;
- event->worker = worker;
-
- e = worker->manager->event;
-
- assert_se(sd_event_now(e, clock_boottime_or_monotonic(), &usec) >= 0);
-
- (void) sd_event_add_time(e, &event->timeout_warning, clock_boottime_or_monotonic(),
- usec + arg_event_timeout_warn_usec, USEC_PER_SEC, on_event_timeout_warning, event);
-
- (void) sd_event_add_time(e, &event->timeout, clock_boottime_or_monotonic(),
- usec + arg_event_timeout_usec, USEC_PER_SEC, on_event_timeout, event);
-}
-
-static void manager_free(Manager *manager) {
- if (!manager)
- return;
-
- udev_builtin_exit(manager->udev);
-
- sd_event_source_unref(manager->ctrl_event);
- sd_event_source_unref(manager->uevent_event);
- sd_event_source_unref(manager->inotify_event);
-
- udev_unref(manager->udev);
- sd_event_unref(manager->event);
- manager_workers_free(manager);
- event_queue_cleanup(manager, EVENT_UNDEF);
-
- udev_monitor_unref(manager->monitor);
- udev_ctrl_unref(manager->ctrl);
- udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
-
- udev_list_cleanup(&manager->properties);
- udev_rules_unref(manager->rules);
-
- safe_close(manager->fd_inotify);
- safe_close_pair(manager->worker_watch);
-
- free(manager);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
-
-static int worker_send_message(int fd) {
- struct worker_message message = {};
-
- return loop_write(fd, &message, sizeof(message), false);
-}
-
-static void worker_spawn(Manager *manager, struct event *event) {
- struct udev *udev = event->udev;
- _cleanup_udev_monitor_unref_ struct udev_monitor *worker_monitor = NULL;
- pid_t pid;
- int r = 0;
-
- /* listen for new events */
- worker_monitor = udev_monitor_new_from_netlink(udev, NULL);
- if (worker_monitor == NULL)
- return;
- /* allow the main daemon netlink address to send devices to the worker */
- udev_monitor_allow_unicast_sender(worker_monitor, manager->monitor);
- r = udev_monitor_enable_receiving(worker_monitor);
- if (r < 0)
- log_error_errno(r, "worker: could not enable receiving of device: %m");
-
- pid = fork();
- switch (pid) {
- case 0: {
- struct udev_device *dev = NULL;
- _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
- int fd_monitor;
- _cleanup_close_ int fd_signal = -1, fd_ep = -1;
- struct epoll_event ep_signal = { .events = EPOLLIN };
- struct epoll_event ep_monitor = { .events = EPOLLIN };
- sigset_t mask;
-
- /* take initial device from queue */
- dev = event->dev;
- event->dev = NULL;
-
- unsetenv("NOTIFY_SOCKET");
-
- manager_workers_free(manager);
- event_queue_cleanup(manager, EVENT_UNDEF);
-
- manager->monitor = udev_monitor_unref(manager->monitor);
- manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
- manager->ctrl = udev_ctrl_unref(manager->ctrl);
- manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]);
-
- manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
- manager->uevent_event = sd_event_source_unref(manager->uevent_event);
- manager->inotify_event = sd_event_source_unref(manager->inotify_event);
-
- manager->event = sd_event_unref(manager->event);
-
- sigfillset(&mask);
- fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
- if (fd_signal < 0) {
- r = log_error_errno(errno, "error creating signalfd %m");
- goto out;
- }
- ep_signal.data.fd = fd_signal;
-
- fd_monitor = udev_monitor_get_fd(worker_monitor);
- ep_monitor.data.fd = fd_monitor;
-
- fd_ep = epoll_create1(EPOLL_CLOEXEC);
- if (fd_ep < 0) {
- r = log_error_errno(errno, "error creating epoll fd: %m");
- goto out;
- }
-
- if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
- epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) {
- r = log_error_errno(errno, "fail to add fds to epoll: %m");
- goto out;
- }
-
- /* Request TERM signal if parent exits.
- Ignore error, not much we can do in that case. */
- (void) prctl(PR_SET_PDEATHSIG, SIGTERM);
-
- /* Reset OOM score, we only protect the main daemon. */
- write_string_file("/proc/self/oom_score_adj", "0", 0);
-
- for (;;) {
- struct udev_event *udev_event;
- int fd_lock = -1;
-
- assert(dev);
-
- log_debug("seq %llu running", udev_device_get_seqnum(dev));
- udev_event = udev_event_new(dev);
- if (udev_event == NULL) {
- r = -ENOMEM;
- goto out;
- }
-
- if (arg_exec_delay > 0)
- udev_event->exec_delay = arg_exec_delay;
-
- /*
- * Take a shared lock on the device node; this establishes
- * a concept of device "ownership" to serialize device
- * access. External processes holding an exclusive lock will
- * cause udev to skip the event handling; in the case udev
- * acquired the lock, the external process can block until
- * udev has finished its event handling.
- */
- if (!streq_ptr(udev_device_get_action(dev), "remove") &&
- streq_ptr("block", udev_device_get_subsystem(dev)) &&
- !startswith(udev_device_get_sysname(dev), "dm-") &&
- !startswith(udev_device_get_sysname(dev), "md")) {
- struct udev_device *d = dev;
-
- if (streq_ptr("partition", udev_device_get_devtype(d)))
- d = udev_device_get_parent(d);
-
- if (d) {
- fd_lock = open(udev_device_get_devnode(d), O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
- if (fd_lock >= 0 && flock(fd_lock, LOCK_SH|LOCK_NB) < 0) {
- log_debug_errno(errno, "Unable to flock(%s), skipping event handling: %m", udev_device_get_devnode(d));
- fd_lock = safe_close(fd_lock);
- goto skip;
- }
- }
- }
-
- /* needed for renaming netifs */
- udev_event->rtnl = rtnl;
-
- /* apply rules, create node, symlinks */
- udev_event_execute_rules(udev_event,
- arg_event_timeout_usec, arg_event_timeout_warn_usec,
- &manager->properties,
- manager->rules);
-
- udev_event_execute_run(udev_event,
- arg_event_timeout_usec, arg_event_timeout_warn_usec);
-
- if (udev_event->rtnl)
- /* in case rtnl was initialized */
- rtnl = sd_netlink_ref(udev_event->rtnl);
-
- /* apply/restore inotify watch */
- if (udev_event->inotify_watch) {
- udev_watch_begin(udev, dev);
- udev_device_update_db(dev);
- }
-
- safe_close(fd_lock);
-
- /* send processed event back to libudev listeners */
- udev_monitor_send_device(worker_monitor, NULL, dev);
-
-skip:
- log_debug("seq %llu processed", udev_device_get_seqnum(dev));
-
- /* send udevd the result of the event execution */
- r = worker_send_message(manager->worker_watch[WRITE_END]);
- if (r < 0)
- log_error_errno(r, "failed to send result of seq %llu to main daemon: %m",
- udev_device_get_seqnum(dev));
-
- udev_device_unref(dev);
- dev = NULL;
-
- udev_event_unref(udev_event);
-
- /* wait for more device messages from main udevd, or term signal */
- while (dev == NULL) {
- struct epoll_event ev[4];
- int fdcount;
- int i;
-
- fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1);
- if (fdcount < 0) {
- if (errno == EINTR)
- continue;
- r = log_error_errno(errno, "failed to poll: %m");
- goto out;
- }
-
- for (i = 0; i < fdcount; i++) {
- if (ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN) {
- dev = udev_monitor_receive_device(worker_monitor);
- break;
- } else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN) {
- struct signalfd_siginfo fdsi;
- ssize_t size;
-
- size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
- if (size != sizeof(struct signalfd_siginfo))
- continue;
- switch (fdsi.ssi_signo) {
- case SIGTERM:
- goto out;
- }
- }
- }
- }
- }
-out:
- udev_device_unref(dev);
- manager_free(manager);
- log_close();
- _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
- }
- case -1:
- event->state = EVENT_QUEUED;
- log_error_errno(errno, "fork of child failed: %m");
- break;
- default:
- {
- struct worker *worker;
-
- r = worker_new(&worker, manager, worker_monitor, pid);
- if (r < 0)
- return;
-
- worker_attach_event(worker, event);
-
- log_debug("seq %llu forked new worker ["PID_FMT"]", udev_device_get_seqnum(event->dev), pid);
- break;
- }
- }
-}
-
-static void event_run(Manager *manager, struct event *event) {
- struct worker *worker;
- Iterator i;
-
- assert(manager);
- assert(event);
-
- HASHMAP_FOREACH(worker, manager->workers, i) {
- ssize_t count;
-
- if (worker->state != WORKER_IDLE)
- continue;
-
- count = udev_monitor_send_device(manager->monitor, worker->monitor, event->dev);
- if (count < 0) {
- log_error_errno(errno, "worker ["PID_FMT"] did not accept message %zi (%m), kill it",
- worker->pid, count);
- kill(worker->pid, SIGKILL);
- worker->state = WORKER_KILLED;
- continue;
- }
- worker_attach_event(worker, event);
- return;
- }
-
- if (hashmap_size(manager->workers) >= arg_children_max) {
- if (arg_children_max > 1)
- log_debug("maximum number (%i) of children reached", hashmap_size(manager->workers));
- return;
- }
-
- /* start new worker and pass initial device */
- worker_spawn(manager, event);
-}
-
-static int event_queue_insert(Manager *manager, struct udev_device *dev) {
- struct event *event;
- int r;
-
- assert(manager);
- assert(dev);
-
- /* only one process can add events to the queue */
- if (manager->pid == 0)
- manager->pid = getpid();
-
- assert(manager->pid == getpid());
-
- event = new0(struct event, 1);
- if (!event)
- return -ENOMEM;
-
- event->udev = udev_device_get_udev(dev);
- event->manager = manager;
- event->dev = dev;
- event->dev_kernel = udev_device_shallow_clone(dev);
- udev_device_copy_properties(event->dev_kernel, dev);
- event->seqnum = udev_device_get_seqnum(dev);
- event->devpath = udev_device_get_devpath(dev);
- event->devpath_len = strlen(event->devpath);
- event->devpath_old = udev_device_get_devpath_old(dev);
- event->devnum = udev_device_get_devnum(dev);
- event->is_block = streq("block", udev_device_get_subsystem(dev));
- event->ifindex = udev_device_get_ifindex(dev);
-
- log_debug("seq %llu queued, '%s' '%s'", udev_device_get_seqnum(dev),
- udev_device_get_action(dev), udev_device_get_subsystem(dev));
-
- event->state = EVENT_QUEUED;
-
- if (udev_list_node_is_empty(&manager->events)) {
- r = touch("/run/udev/queue");
- if (r < 0)
- log_warning_errno(r, "could not touch /run/udev/queue: %m");
- }
-
- udev_list_node_append(&event->node, &manager->events);
-
- return 0;
-}
-
-static void manager_kill_workers(Manager *manager) {
- struct worker *worker;
- Iterator i;
-
- assert(manager);
-
- HASHMAP_FOREACH(worker, manager->workers, i) {
- if (worker->state == WORKER_KILLED)
- continue;
-
- worker->state = WORKER_KILLED;
- kill(worker->pid, SIGTERM);
- }
-}
-
-/* lookup event for identical, parent, child device */
-static bool is_devpath_busy(Manager *manager, struct event *event) {
- struct udev_list_node *loop;
- size_t common;
-
- /* check if queue contains events we depend on */
- udev_list_node_foreach(loop, &manager->events) {
- struct event *loop_event = node_to_event(loop);
-
- /* we already found a later event, earlier can not block us, no need to check again */
- if (loop_event->seqnum < event->delaying_seqnum)
- continue;
-
- /* event we checked earlier still exists, no need to check again */
- if (loop_event->seqnum == event->delaying_seqnum)
- return true;
-
- /* found ourself, no later event can block us */
- if (loop_event->seqnum >= event->seqnum)
- break;
-
- /* check major/minor */
- if (major(event->devnum) != 0 && event->devnum == loop_event->devnum && event->is_block == loop_event->is_block)
- return true;
-
- /* check network device ifindex */
- if (event->ifindex != 0 && event->ifindex == loop_event->ifindex)
- return true;
-
- /* check our old name */
- if (event->devpath_old != NULL && streq(loop_event->devpath, event->devpath_old)) {
- event->delaying_seqnum = loop_event->seqnum;
- return true;
- }
-
- /* compare devpath */
- common = MIN(loop_event->devpath_len, event->devpath_len);
-
- /* one devpath is contained in the other? */
- if (memcmp(loop_event->devpath, event->devpath, common) != 0)
- continue;
-
- /* identical device event found */
- if (loop_event->devpath_len == event->devpath_len) {
- /* devices names might have changed/swapped in the meantime */
- if (major(event->devnum) != 0 && (event->devnum != loop_event->devnum || event->is_block != loop_event->is_block))
- continue;
- if (event->ifindex != 0 && event->ifindex != loop_event->ifindex)
- continue;
- event->delaying_seqnum = loop_event->seqnum;
- return true;
- }
-
- /* parent device event found */
- if (event->devpath[common] == '/') {
- event->delaying_seqnum = loop_event->seqnum;
- return true;
- }
-
- /* child device event found */
- if (loop_event->devpath[common] == '/') {
- event->delaying_seqnum = loop_event->seqnum;
- return true;
- }
-
- /* no matching device */
- continue;
- }
-
- return false;
-}
-
-static int on_exit_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
- Manager *manager = userdata;
-
- assert(manager);
-
- log_error_errno(ETIMEDOUT, "giving up waiting for workers to finish");
-
- sd_event_exit(manager->event, -ETIMEDOUT);
-
- return 1;
-}
-
-static void manager_exit(Manager *manager) {
- uint64_t usec;
- int r;
-
- assert(manager);
-
- manager->exit = true;
-
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Starting shutdown...");
-
- /* close sources of new events and discard buffered events */
- manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
- manager->ctrl = udev_ctrl_unref(manager->ctrl);
-
- manager->inotify_event = sd_event_source_unref(manager->inotify_event);
- manager->fd_inotify = safe_close(manager->fd_inotify);
-
- manager->uevent_event = sd_event_source_unref(manager->uevent_event);
- manager->monitor = udev_monitor_unref(manager->monitor);
-
- /* discard queued events and kill workers */
- event_queue_cleanup(manager, EVENT_QUEUED);
- manager_kill_workers(manager);
-
- assert_se(sd_event_now(manager->event, clock_boottime_or_monotonic(), &usec) >= 0);
-
- r = sd_event_add_time(manager->event, NULL, clock_boottime_or_monotonic(),
- usec + 30 * USEC_PER_SEC, USEC_PER_SEC, on_exit_timeout, manager);
- if (r < 0)
- return;
-}
-
-/* reload requested, HUP signal received, rules changed, builtin changed */
-static void manager_reload(Manager *manager) {
-
- assert(manager);
-
- sd_notify(false,
- "RELOADING=1\n"
- "STATUS=Flushing configuration...");
-
- manager_kill_workers(manager);
- manager->rules = udev_rules_unref(manager->rules);
- udev_builtin_exit(manager->udev);
-
- sd_notifyf(false,
- "READY=1\n"
- "STATUS=Processing with %u children at max", arg_children_max);
-}
-
-static void event_queue_start(Manager *manager) {
- struct udev_list_node *loop;
- usec_t usec;
-
- assert(manager);
-
- if (udev_list_node_is_empty(&manager->events) ||
- manager->exit || manager->stop_exec_queue)
- return;
-
- assert_se(sd_event_now(manager->event, clock_boottime_or_monotonic(), &usec) >= 0);
- /* check for changed config, every 3 seconds at most */
- if (manager->last_usec == 0 ||
- (usec - manager->last_usec) > 3 * USEC_PER_SEC) {
- if (udev_rules_check_timestamp(manager->rules) ||
- udev_builtin_validate(manager->udev))
- manager_reload(manager);
-
- manager->last_usec = usec;
- }
-
- udev_builtin_init(manager->udev);
-
- if (!manager->rules) {
- manager->rules = udev_rules_new(manager->udev, arg_resolve_names);
- if (!manager->rules)
- return;
- }
-
- udev_list_node_foreach(loop, &manager->events) {
- struct event *event = node_to_event(loop);
-
- if (event->state != EVENT_QUEUED)
- continue;
-
- /* do not start event if parent or child event is still running */
- if (is_devpath_busy(manager, event))
- continue;
-
- event_run(manager, event);
- }
-}
-
-static void event_queue_cleanup(Manager *manager, enum event_state match_type) {
- struct udev_list_node *loop, *tmp;
-
- udev_list_node_foreach_safe(loop, tmp, &manager->events) {
- struct event *event = node_to_event(loop);
-
- if (match_type != EVENT_UNDEF && match_type != event->state)
- continue;
-
- event_free(event);
- }
-}
-
-static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- Manager *manager = userdata;
-
- assert(manager);
-
- for (;;) {
- struct worker_message msg;
- struct iovec iovec = {
- .iov_base = &msg,
- .iov_len = sizeof(msg),
- };
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
- } control = {};
- struct msghdr msghdr = {
- .msg_iov = &iovec,
- .msg_iovlen = 1,
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
- ssize_t size;
- struct ucred *ucred = NULL;
- struct worker *worker;
-
- size = recvmsg(fd, &msghdr, MSG_DONTWAIT);
- if (size < 0) {
- if (errno == EINTR)
- continue;
- else if (errno == EAGAIN)
- /* nothing more to read */
- break;
-
- return log_error_errno(errno, "failed to receive message: %m");
- } else if (size != sizeof(struct worker_message)) {
- log_warning_errno(EIO, "ignoring worker message with invalid size %zi bytes", size);
- continue;
- }
-
- CMSG_FOREACH(cmsg, &msghdr) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
- ucred = (struct ucred*) CMSG_DATA(cmsg);
- }
-
- if (!ucred || ucred->pid <= 0) {
- log_warning_errno(EIO, "ignoring worker message without valid PID");
- continue;
- }
-
- /* lookup worker who sent the signal */
- worker = hashmap_get(manager->workers, PID_TO_PTR(ucred->pid));
- if (!worker) {
- log_debug("worker ["PID_FMT"] returned, but is no longer tracked", ucred->pid);
- continue;
- }
-
- if (worker->state != WORKER_KILLED)
- worker->state = WORKER_IDLE;
-
- /* worker returned */
- event_free(worker->event);
- }
-
- /* we have free workers, try to schedule events */
- event_queue_start(manager);
-
- return 1;
-}
-
-static int on_uevent(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- Manager *manager = userdata;
- struct udev_device *dev;
- int r;
-
- assert(manager);
-
- dev = udev_monitor_receive_device(manager->monitor);
- if (dev) {
- udev_device_ensure_usec_initialized(dev, NULL);
- r = event_queue_insert(manager, dev);
- if (r < 0)
- udev_device_unref(dev);
- else
- /* we have fresh events, try to schedule them */
- event_queue_start(manager);
- }
-
- return 1;
-}
-
-/* receive the udevd message from userspace */
-static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- Manager *manager = userdata;
- _cleanup_udev_ctrl_connection_unref_ struct udev_ctrl_connection *ctrl_conn = NULL;
- _cleanup_udev_ctrl_msg_unref_ struct udev_ctrl_msg *ctrl_msg = NULL;
- const char *str;
- int i;
-
- assert(manager);
-
- ctrl_conn = udev_ctrl_get_connection(manager->ctrl);
- if (!ctrl_conn)
- return 1;
-
- ctrl_msg = udev_ctrl_receive_msg(ctrl_conn);
- if (!ctrl_msg)
- return 1;
-
- i = udev_ctrl_get_set_log_level(ctrl_msg);
- if (i >= 0) {
- log_debug("udevd message (SET_LOG_LEVEL) received, log_priority=%i", i);
- log_set_max_level(i);
- manager_kill_workers(manager);
- }
-
- if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
- log_debug("udevd message (STOP_EXEC_QUEUE) received");
- manager->stop_exec_queue = true;
- }
-
- if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
- log_debug("udevd message (START_EXEC_QUEUE) received");
- manager->stop_exec_queue = false;
- event_queue_start(manager);
- }
-
- if (udev_ctrl_get_reload(ctrl_msg) > 0) {
- log_debug("udevd message (RELOAD) received");
- manager_reload(manager);
- }
-
- str = udev_ctrl_get_set_env(ctrl_msg);
- if (str != NULL) {
- _cleanup_free_ char *key = NULL;
-
- key = strdup(str);
- if (key) {
- char *val;
-
- val = strchr(key, '=');
- if (val != NULL) {
- val[0] = '\0';
- val = &val[1];
- if (val[0] == '\0') {
- log_debug("udevd message (ENV) received, unset '%s'", key);
- udev_list_entry_add(&manager->properties, key, NULL);
- } else {
- log_debug("udevd message (ENV) received, set '%s=%s'", key, val);
- udev_list_entry_add(&manager->properties, key, val);
- }
- } else
- log_error("wrong key format '%s'", key);
- }
- manager_kill_workers(manager);
- }
-
- i = udev_ctrl_get_set_children_max(ctrl_msg);
- if (i >= 0) {
- log_debug("udevd message (SET_MAX_CHILDREN) received, children_max=%i", i);
- arg_children_max = i;
-
- (void) sd_notifyf(false,
- "READY=1\n"
- "STATUS=Processing with %u children at max", arg_children_max);
- }
-
- if (udev_ctrl_get_ping(ctrl_msg) > 0)
- log_debug("udevd message (SYNC) received");
-
- if (udev_ctrl_get_exit(ctrl_msg) > 0) {
- log_debug("udevd message (EXIT) received");
- manager_exit(manager);
- /* keep reference to block the client until we exit
- TODO: deal with several blocking exit requests */
- manager->ctrl_conn_blocking = udev_ctrl_connection_ref(ctrl_conn);
- }
-
- return 1;
-}
-
-static int synthesize_change(struct udev_device *dev) {
- char filename[UTIL_PATH_SIZE];
- int r;
-
- if (streq_ptr("block", udev_device_get_subsystem(dev)) &&
- streq_ptr("disk", udev_device_get_devtype(dev)) &&
- !startswith(udev_device_get_sysname(dev), "dm-")) {
- bool part_table_read = false;
- bool has_partitions = false;
- int fd;
- struct udev *udev = udev_device_get_udev(dev);
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
- struct udev_list_entry *item;
-
- /*
- * Try to re-read the partition table. This only succeeds if
- * none of the devices is busy. The kernel returns 0 if no
- * partition table is found, and we will not get an event for
- * the disk.
- */
- fd = open(udev_device_get_devnode(dev), O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
- if (fd >= 0) {
- r = flock(fd, LOCK_EX|LOCK_NB);
- if (r >= 0)
- r = ioctl(fd, BLKRRPART, 0);
-
- close(fd);
- if (r >= 0)
- part_table_read = true;
- }
-
- /* search for partitions */
- e = udev_enumerate_new(udev);
- if (!e)
- return -ENOMEM;
-
- r = udev_enumerate_add_match_parent(e, dev);
- if (r < 0)
- return r;
-
- r = udev_enumerate_add_match_subsystem(e, "block");
- if (r < 0)
- return r;
-
- r = udev_enumerate_scan_devices(e);
- if (r < 0)
- return r;
-
- udev_list_entry_foreach(item, udev_enumerate_get_list_entry(e)) {
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
-
- d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
- if (!d)
- continue;
-
- if (!streq_ptr("partition", udev_device_get_devtype(d)))
- continue;
-
- has_partitions = true;
- break;
- }
-
- /*
- * We have partitions and re-read the table, the kernel already sent
- * out a "change" event for the disk, and "remove/add" for all
- * partitions.
- */
- if (part_table_read && has_partitions)
- return 0;
-
- /*
- * We have partitions but re-reading the partition table did not
- * work, synthesize "change" for the disk and all partitions.
- */
- log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev));
- strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
- write_string_file(filename, "change", WRITE_STRING_FILE_CREATE);
-
- udev_list_entry_foreach(item, udev_enumerate_get_list_entry(e)) {
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
-
- d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
- if (!d)
- continue;
-
- if (!streq_ptr("partition", udev_device_get_devtype(d)))
- continue;
-
- log_debug("device %s closed, synthesising partition '%s' 'change'",
- udev_device_get_devnode(dev), udev_device_get_devnode(d));
- strscpyl(filename, sizeof(filename), udev_device_get_syspath(d), "/uevent", NULL);
- write_string_file(filename, "change", WRITE_STRING_FILE_CREATE);
- }
-
- return 0;
- }
-
- log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev));
- strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
- write_string_file(filename, "change", WRITE_STRING_FILE_CREATE);
-
- return 0;
-}
-
-static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- Manager *manager = userdata;
- union inotify_event_buffer buffer;
- struct inotify_event *e;
- ssize_t l;
-
- assert(manager);
-
- l = read(fd, &buffer, sizeof(buffer));
- if (l < 0) {
- if (errno == EAGAIN || errno == EINTR)
- return 1;
-
- return log_error_errno(errno, "Failed to read inotify fd: %m");
- }
-
- FOREACH_INOTIFY_EVENT(e, buffer, l) {
- _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
-
- dev = udev_watch_lookup(manager->udev, e->wd);
- if (!dev)
- continue;
-
- log_debug("inotify event: %x for %s", e->mask, udev_device_get_devnode(dev));
- if (e->mask & IN_CLOSE_WRITE) {
- synthesize_change(dev);
-
- /* settle might be waiting on us to determine the queue
- * state. If we just handled an inotify event, we might have
- * generated a "change" event, but we won't have queued up
- * the resultant uevent yet. Do that.
- */
- on_uevent(NULL, -1, 0, manager);
- } else if (e->mask & IN_IGNORED)
- udev_watch_end(manager->udev, dev);
- }
-
- return 1;
-}
-
-static int on_sigterm(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
- Manager *manager = userdata;
-
- assert(manager);
-
- manager_exit(manager);
-
- return 1;
-}
-
-static int on_sighup(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
- Manager *manager = userdata;
-
- assert(manager);
-
- manager_reload(manager);
-
- return 1;
-}
-
-static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
- Manager *manager = userdata;
-
- assert(manager);
-
- for (;;) {
- pid_t pid;
- int status;
- struct worker *worker;
-
- pid = waitpid(-1, &status, WNOHANG);
- if (pid <= 0)
- break;
-
- worker = hashmap_get(manager->workers, PID_TO_PTR(pid));
- if (!worker) {
- log_warning("worker ["PID_FMT"] is unknown, ignoring", pid);
- continue;
- }
-
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) == 0)
- log_debug("worker ["PID_FMT"] exited", pid);
- else
- log_warning("worker ["PID_FMT"] exited with return code %i", pid, WEXITSTATUS(status));
- } else if (WIFSIGNALED(status)) {
- log_warning("worker ["PID_FMT"] terminated by signal %i (%s)", pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
- } else if (WIFSTOPPED(status)) {
- log_info("worker ["PID_FMT"] stopped", pid);
- continue;
- } else if (WIFCONTINUED(status)) {
- log_info("worker ["PID_FMT"] continued", pid);
- continue;
- } else
- log_warning("worker ["PID_FMT"] exit with status 0x%04x", pid, status);
-
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- if (worker->event) {
- log_error("worker ["PID_FMT"] failed while handling '%s'", pid, worker->event->devpath);
- /* delete state from disk */
- udev_device_delete_db(worker->event->dev);
- udev_device_tag_index(worker->event->dev, NULL, false);
- /* forward kernel event without amending it */
- udev_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel);
- }
- }
-
- worker_free(worker);
- }
-
- /* we can start new workers, try to schedule events */
- event_queue_start(manager);
-
- return 1;
-}
-
-static int on_post(sd_event_source *s, void *userdata) {
- Manager *manager = userdata;
- int r;
-
- assert(manager);
-
- if (udev_list_node_is_empty(&manager->events)) {
- /* no pending events */
- if (!hashmap_isempty(manager->workers)) {
- /* there are idle workers */
- log_debug("cleanup idle workers");
- manager_kill_workers(manager);
- } else {
- /* we are idle */
- if (manager->exit) {
- r = sd_event_exit(manager->event, 0);
- if (r < 0)
- return r;
- } else if (manager->cgroup)
- /* cleanup possible left-over processes in our cgroup */
- cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, CGROUP_IGNORE_SELF, NULL, NULL, NULL);
- }
- }
-
- return 1;
-}
-
-static int listen_fds(int *rctrl, int *rnetlink) {
- _cleanup_udev_unref_ struct udev *udev = NULL;
- int ctrl_fd = -1, netlink_fd = -1;
- int fd, n, r;
-
- assert(rctrl);
- assert(rnetlink);
-
- n = sd_listen_fds(true);
- if (n < 0)
- return n;
-
- for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) {
- if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) {
- if (ctrl_fd >= 0)
- return -EINVAL;
- ctrl_fd = fd;
- continue;
- }
-
- if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1)) {
- if (netlink_fd >= 0)
- return -EINVAL;
- netlink_fd = fd;
- continue;
- }
-
- return -EINVAL;
- }
-
- if (ctrl_fd < 0) {
- _cleanup_udev_ctrl_unref_ struct udev_ctrl *ctrl = NULL;
-
- udev = udev_new();
- if (!udev)
- return -ENOMEM;
-
- ctrl = udev_ctrl_new(udev);
- if (!ctrl)
- return log_error_errno(EINVAL, "error initializing udev control socket");
-
- r = udev_ctrl_enable_receiving(ctrl);
- if (r < 0)
- return log_error_errno(EINVAL, "error binding udev control socket");
-
- fd = udev_ctrl_get_fd(ctrl);
- if (fd < 0)
- return log_error_errno(EIO, "could not get ctrl fd");
-
- ctrl_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
- if (ctrl_fd < 0)
- return log_error_errno(errno, "could not dup ctrl fd: %m");
- }
-
- if (netlink_fd < 0) {
- _cleanup_udev_monitor_unref_ struct udev_monitor *monitor = NULL;
-
- if (!udev) {
- udev = udev_new();
- if (!udev)
- return -ENOMEM;
- }
-
- monitor = udev_monitor_new_from_netlink(udev, "kernel");
- if (!monitor)
- return log_error_errno(EINVAL, "error initializing netlink socket");
-
- (void) udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024);
-
- r = udev_monitor_enable_receiving(monitor);
- if (r < 0)
- return log_error_errno(EINVAL, "error binding netlink socket");
-
- fd = udev_monitor_get_fd(monitor);
- if (fd < 0)
- return log_error_errno(netlink_fd, "could not get uevent fd: %m");
-
- netlink_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
- if (ctrl_fd < 0)
- return log_error_errno(errno, "could not dup netlink fd: %m");
- }
-
- *rctrl = ctrl_fd;
- *rnetlink = netlink_fd;
-
- return 0;
-}
-
-/*
- * read the kernel command line, in case we need to get into debug mode
- * udev.log-priority=<level> syslog priority
- * udev.children-max=<number of workers> events are fully serialized if set to 1
- * udev.exec-delay=<number of seconds> delay execution of every executed program
- * udev.event-timeout=<number of seconds> seconds to wait before terminating an event
- */
-static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
- int r = 0;
-
- assert(key);
-
- if (!value)
- return 0;
-
- if (streq(key, "udev.log-priority") && value) {
- r = util_log_priority(value);
- if (r >= 0)
- log_set_max_level(r);
- } else if (streq(key, "udev.event-timeout") && value) {
- r = safe_atou64(value, &arg_event_timeout_usec);
- if (r >= 0) {
- arg_event_timeout_usec *= USEC_PER_SEC;
- arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1;
- }
- } else if (streq(key, "udev.children-max") && value)
- r = safe_atou(value, &arg_children_max);
- else if (streq(key, "udev.exec-delay") && value)
- r = safe_atoi(value, &arg_exec_delay);
- else if (startswith(key, "udev."))
- log_warning("Unknown udev kernel command line option \"%s\"", key);
-
- if (r < 0)
- log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value);
- return 0;
-}
-
-static void help(void) {
- printf("%s [OPTIONS...]\n\n"
- "Manages devices.\n\n"
- " -h --help Print this message\n"
- " --version Print version of the program\n"
- " --daemon Detach and run in the background\n"
- " --debug Enable debug output\n"
- " --children-max=INT Set maximum number of workers\n"
- " --exec-delay=SECONDS Seconds to wait before executing RUN=\n"
- " --event-timeout=SECONDS Seconds to wait before terminating an event\n"
- " --resolve-names=early|late|never\n"
- " When to resolve users and groups\n"
- , program_invocation_short_name);
-}
-
-static int parse_argv(int argc, char *argv[]) {
- static const struct option options[] = {
- { "daemon", no_argument, NULL, 'd' },
- { "debug", no_argument, NULL, 'D' },
- { "children-max", required_argument, NULL, 'c' },
- { "exec-delay", required_argument, NULL, 'e' },
- { "event-timeout", required_argument, NULL, 't' },
- { "resolve-names", required_argument, NULL, 'N' },
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, 'V' },
- {}
- };
-
- int c;
-
- assert(argc >= 0);
- assert(argv);
-
- while ((c = getopt_long(argc, argv, "c:de:Dt:N:hV", options, NULL)) >= 0) {
- int r;
-
- switch (c) {
-
- case 'd':
- arg_daemonize = true;
- break;
- case 'c':
- r = safe_atou(optarg, &arg_children_max);
- if (r < 0)
- log_warning("Invalid --children-max ignored: %s", optarg);
- break;
- case 'e':
- r = safe_atoi(optarg, &arg_exec_delay);
- if (r < 0)
- log_warning("Invalid --exec-delay ignored: %s", optarg);
- break;
- case 't':
- r = safe_atou64(optarg, &arg_event_timeout_usec);
- if (r < 0)
- log_warning("Invalid --event-timeout ignored: %s", optarg);
- else {
- arg_event_timeout_usec *= USEC_PER_SEC;
- arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1;
- }
- break;
- case 'D':
- arg_debug = true;
- break;
- case 'N':
- if (streq(optarg, "early")) {
- arg_resolve_names = 1;
- } else if (streq(optarg, "late")) {
- arg_resolve_names = 0;
- } else if (streq(optarg, "never")) {
- arg_resolve_names = -1;
- } else {
- log_error("resolve-names must be early, late or never");
- return 0;
- }
- break;
- case 'h':
- help();
- return 0;
- case 'V':
- printf("%s\n", VERSION);
- return 0;
- case '?':
- return -EINVAL;
- default:
- assert_not_reached("Unhandled option");
-
- }
- }
-
- return 1;
-}
-
-static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cgroup) {
- _cleanup_(manager_freep) Manager *manager = NULL;
- int r, fd_worker, one = 1;
-
- assert(ret);
- assert(fd_ctrl >= 0);
- assert(fd_uevent >= 0);
-
- manager = new0(Manager, 1);
- if (!manager)
- return log_oom();
-
- manager->fd_inotify = -1;
- manager->worker_watch[WRITE_END] = -1;
- manager->worker_watch[READ_END] = -1;
-
- manager->udev = udev_new();
- if (!manager->udev)
- return log_error_errno(errno, "could not allocate udev context: %m");
-
- udev_builtin_init(manager->udev);
-
- manager->rules = udev_rules_new(manager->udev, arg_resolve_names);
- if (!manager->rules)
- return log_error_errno(ENOMEM, "error reading rules");
-
- udev_list_node_init(&manager->events);
- udev_list_init(manager->udev, &manager->properties, true);
-
- manager->cgroup = cgroup;
-
- manager->ctrl = udev_ctrl_new_from_fd(manager->udev, fd_ctrl);
- if (!manager->ctrl)
- return log_error_errno(EINVAL, "error taking over udev control socket");
-
- manager->monitor = udev_monitor_new_from_netlink_fd(manager->udev, "kernel", fd_uevent);
- if (!manager->monitor)
- return log_error_errno(EINVAL, "error taking over netlink socket");
-
- /* unnamed socket from workers to the main daemon */
- r = socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch);
- if (r < 0)
- return log_error_errno(errno, "error creating socketpair: %m");
-
- fd_worker = manager->worker_watch[READ_END];
-
- r = setsockopt(fd_worker, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
- if (r < 0)
- return log_error_errno(errno, "could not enable SO_PASSCRED: %m");
-
- manager->fd_inotify = udev_watch_init(manager->udev);
- if (manager->fd_inotify < 0)
- return log_error_errno(ENOMEM, "error initializing inotify");
-
- udev_watch_restore(manager->udev);
-
- /* block and listen to all signals on signalfd */
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0);
-
- r = sd_event_default(&manager->event);
- if (r < 0)
- return log_error_errno(r, "could not allocate event loop: %m");
-
- r = sd_event_add_signal(manager->event, NULL, SIGINT, on_sigterm, manager);
- if (r < 0)
- return log_error_errno(r, "error creating sigint event source: %m");
-
- r = sd_event_add_signal(manager->event, NULL, SIGTERM, on_sigterm, manager);
- if (r < 0)
- return log_error_errno(r, "error creating sigterm event source: %m");
-
- r = sd_event_add_signal(manager->event, NULL, SIGHUP, on_sighup, manager);
- if (r < 0)
- return log_error_errno(r, "error creating sighup event source: %m");
-
- r = sd_event_add_signal(manager->event, NULL, SIGCHLD, on_sigchld, manager);
- if (r < 0)
- return log_error_errno(r, "error creating sigchld event source: %m");
-
- r = sd_event_set_watchdog(manager->event, true);
- if (r < 0)
- return log_error_errno(r, "error creating watchdog event source: %m");
-
- r = sd_event_add_io(manager->event, &manager->ctrl_event, fd_ctrl, EPOLLIN, on_ctrl_msg, manager);
- if (r < 0)
- return log_error_errno(r, "error creating ctrl event source: %m");
-
- /* This needs to be after the inotify and uevent handling, to make sure
- * that the ping is send back after fully processing the pending uevents
- * (including the synthetic ones we may create due to inotify events).
- */
- r = sd_event_source_set_priority(manager->ctrl_event, SD_EVENT_PRIORITY_IDLE);
- if (r < 0)
- return log_error_errno(r, "cold not set IDLE event priority for ctrl event source: %m");
-
- r = sd_event_add_io(manager->event, &manager->inotify_event, manager->fd_inotify, EPOLLIN, on_inotify, manager);
- if (r < 0)
- return log_error_errno(r, "error creating inotify event source: %m");
-
- r = sd_event_add_io(manager->event, &manager->uevent_event, fd_uevent, EPOLLIN, on_uevent, manager);
- if (r < 0)
- return log_error_errno(r, "error creating uevent event source: %m");
-
- r = sd_event_add_io(manager->event, NULL, fd_worker, EPOLLIN, on_worker, manager);
- if (r < 0)
- return log_error_errno(r, "error creating worker event source: %m");
-
- r = sd_event_add_post(manager->event, NULL, on_post, manager);
- if (r < 0)
- return log_error_errno(r, "error creating post event source: %m");
-
- *ret = manager;
- manager = NULL;
-
- return 0;
-}
-
-static int run(int fd_ctrl, int fd_uevent, const char *cgroup) {
- _cleanup_(manager_freep) Manager *manager = NULL;
- int r;
-
- r = manager_new(&manager, fd_ctrl, fd_uevent, cgroup);
- if (r < 0) {
- r = log_error_errno(r, "failed to allocate manager object: %m");
- goto exit;
- }
-
- r = udev_rules_apply_static_dev_perms(manager->rules);
- if (r < 0)
- log_error_errno(r, "failed to apply permissions on static device nodes: %m");
-
- (void) sd_notifyf(false,
- "READY=1\n"
- "STATUS=Processing with %u children at max", arg_children_max);
-
- r = sd_event_loop(manager->event);
- if (r < 0) {
- log_error_errno(r, "event loop failed: %m");
- goto exit;
- }
-
- sd_event_get_exit_code(manager->event, &r);
-
-exit:
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Shutting down...");
- if (manager)
- udev_ctrl_cleanup(manager->ctrl);
- return r;
-}
-
-int main(int argc, char *argv[]) {
- _cleanup_free_ char *cgroup = NULL;
- int fd_ctrl = -1, fd_uevent = -1;
- int r;
-
- log_set_target(LOG_TARGET_AUTO);
- log_parse_environment();
- log_open();
-
- r = parse_argv(argc, argv);
- if (r <= 0)
- goto exit;
-
- r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true);
- if (r < 0)
- log_warning_errno(r, "failed to parse kernel command line, ignoring: %m");
-
- if (arg_debug) {
- log_set_target(LOG_TARGET_CONSOLE);
- log_set_max_level(LOG_DEBUG);
- }
-
- if (getuid() != 0) {
- r = log_error_errno(EPERM, "root privileges required");
- goto exit;
- }
-
- if (arg_children_max == 0) {
- cpu_set_t cpu_set;
-
- arg_children_max = 8;
-
- if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set) == 0)
- arg_children_max += CPU_COUNT(&cpu_set) * 2;
-
- log_debug("set children_max to %u", arg_children_max);
- }
-
- /* set umask before creating any file/directory */
- r = chdir("/");
- if (r < 0) {
- r = log_error_errno(errno, "could not change dir to /: %m");
- goto exit;
- }
-
- umask(022);
-
- r = mac_selinux_init();
- if (r < 0) {
- log_error_errno(r, "could not initialize labelling: %m");
- goto exit;
- }
-
- r = mkdir("/run/udev", 0755);
- if (r < 0 && errno != EEXIST) {
- r = log_error_errno(errno, "could not create /run/udev: %m");
- goto exit;
- }
-
- dev_setup(NULL, UID_INVALID, GID_INVALID);
-
- if (getppid() == 1) {
- /* get our own cgroup, we regularly kill everything udev has left behind
- we only do this on systemd systems, and only if we are directly spawned
- by PID1. otherwise we are not guaranteed to have a dedicated cgroup */
- r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
- if (r < 0) {
- if (r == -ENOENT || r == -ENOMEDIUM)
- log_debug_errno(r, "did not find dedicated cgroup: %m");
- else
- log_warning_errno(r, "failed to get cgroup: %m");
- }
- }
-
- r = listen_fds(&fd_ctrl, &fd_uevent);
- if (r < 0) {
- r = log_error_errno(r, "could not listen on fds: %m");
- goto exit;
- }
-
- if (arg_daemonize) {
- pid_t pid;
-
- log_info("starting version " VERSION);
-
- /* connect /dev/null to stdin, stdout, stderr */
- if (log_get_max_level() < LOG_DEBUG) {
- r = make_null_stdio();
- if (r < 0)
- log_warning_errno(r, "Failed to redirect standard streams to /dev/null: %m");
- }
-
-
-
- pid = fork();
- switch (pid) {
- case 0:
- break;
- case -1:
- r = log_error_errno(errno, "fork of daemon failed: %m");
- goto exit;
- default:
- mac_selinux_finish();
- log_close();
- _exit(EXIT_SUCCESS);
- }
-
- setsid();
-
- write_string_file("/proc/self/oom_score_adj", "-1000", 0);
- }
-
- r = run(fd_ctrl, fd_uevent, cgroup);
-
-exit:
- mac_selinux_finish();
- log_close();
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/src/udev/v4l_id/Makefile b/src/udev/v4l_id/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/udev/v4l_id/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c
deleted file mode 100644
index aec6676a33..0000000000
--- a/src/udev/v4l_id/v4l_id.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2009 Kay Sievers <kay@vrfy.org>
- * Copyright (c) 2009 Filippo Argiolas <filippo.argiolas@gmail.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details:
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <linux/videodev2.h>
-
-#include "fd-util.h"
-#include "util.h"
-
-int main(int argc, char *argv[]) {
- static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- {}
- };
- _cleanup_close_ int fd = -1;
- char *device;
- struct v4l2_capability v2cap;
- int c;
-
- while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
-
- switch (c) {
- case 'h':
- printf("%s [-h,--help] <device file>\n\n"
- "Video4Linux device identification.\n\n"
- " -h Print this message\n"
- , program_invocation_short_name);
- return 0;
- case '?':
- return -EINVAL;
-
- default:
- assert_not_reached("Unhandled option");
- }
-
- device = argv[optind];
- if (device == NULL)
- return 2;
-
- fd = open(device, O_RDONLY);
- if (fd < 0)
- return 3;
-
- if (ioctl(fd, VIDIOC_QUERYCAP, &v2cap) == 0) {
- printf("ID_V4L_VERSION=2\n");
- printf("ID_V4L_PRODUCT=%s\n", v2cap.card);
- printf("ID_V4L_CAPABILITIES=:");
- if ((v2cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0)
- printf("capture:");
- if ((v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0)
- printf("video_output:");
- if ((v2cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0)
- printf("video_overlay:");
- if ((v2cap.capabilities & V4L2_CAP_AUDIO) > 0)
- printf("audio:");
- if ((v2cap.capabilities & V4L2_CAP_TUNER) > 0)
- printf("tuner:");
- if ((v2cap.capabilities & V4L2_CAP_RADIO) > 0)
- printf("radio:");
- printf("\n");
- }
-
- return 0;
-}