diff options
author | Tom Gundersen <teg@jklm.no> | 2014-11-22 19:02:12 +0100 |
---|---|---|
committer | Tom Gundersen <teg@jklm.no> | 2014-12-11 13:54:19 +0100 |
commit | 338fb2173bbdb46c1fc1415f0102fcada2cd7aad (patch) | |
tree | 9f1f2098198941c95950d8538aa970c07b6bcba5 | |
parent | 136cc3ec2598b721125df7c72840c1cdac16b1b5 (diff) |
sd-device: add device_new_from_nulstr
Only meant for internal use.
-rw-r--r-- | src/libsystemd/sd-device/device-internal.h | 3 | ||||
-rw-r--r-- | src/libsystemd/sd-device/sd-device.c | 289 |
2 files changed, 272 insertions, 20 deletions
diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h index 7f8c19ce1..3ba536053 100644 --- a/src/libsystemd/sd-device/device-internal.h +++ b/src/libsystemd/sd-device/device-internal.h @@ -20,6 +20,9 @@ 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 "device-monitor.h" + +int device_new_from_nulstr(sd_device **ret, uint64_t *_seqnum, DeviceAction *_action, const char **_devpath_old, uint8_t *nulstr, size_t len); int device_get_devlink_priority(sd_device *device, int *priority); int device_get_watch_handle(sd_device *device, int *handle); diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 2bbff14c2..4375d8e37 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -35,6 +35,7 @@ #include "sd-device.h" #include "device-util.h" +#include "device-internal.h" struct sd_device { RefCount n_ref; @@ -74,6 +75,10 @@ struct sd_device { bool is_initialized; uint64_t usec_initialized; + mode_t devmode; + uid_t devuid; + gid_t devgid; + bool uevent_loaded; bool db_loaded; bool parent_set; @@ -82,6 +87,8 @@ struct sd_device { bool tags_uptodate; bool devlinks_uptodate; + + bool sealed; }; static int device_new(sd_device **ret) { @@ -251,7 +258,7 @@ static int device_add_devlink(sd_device *device, const char *devlink) { return 0; } -static int device_set_syspath(sd_device *device, const char *_syspath) { +static int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { _cleanup_free_ char *syspath = NULL, *sysname = NULL; const char *devpath, *sysnum; const char *pos; @@ -262,27 +269,50 @@ static int device_set_syspath(sd_device *device, const char *_syspath) { assert(_syspath); /* must be a subdirectory of /sys */ - if (!path_startswith(_syspath, "/sys/")) + if (!path_startswith(_syspath, "/sys/")) { + log_debug("sd-device: syspath '%s' is not a subdirectory of /sys", _syspath); return -EINVAL; + } - r = readlink_and_canonicalize(_syspath, &syspath); - if (r < 0) - return r; + if (verify) { + r = readlink_and_canonicalize(_syspath, &syspath); + if (r == -EINVAL) { + /* not a symlink */ + syspath = canonicalize_file_name(_syspath); + if (!syspath) { + log_debug("sd-device: could not canonicalize '%s': %m", _syspath); + return -errno; + } + /* ignore errors due to the link not being a symlink */ + } else if (r < 0 && r != -EINVAL) { + log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r)); + return r; + } - devpath = syspath + strlen("/sys"); + if (path_startswith(syspath, "/sys/devices/")) { + char *path; - if (path_startswith(devpath, "/devices/")) { - char *path; + /* all 'devices' require an 'uevent' file */ + path = strappenda(syspath, "/uevent"); + r = access(path, F_OK); + if (r < 0) { + log_debug("sd-device: %s does not have an uevent file", syspath); + return -errno; + } + } else { + /* everything else just just needs to be a directory */ + if (!is_dir(syspath, false)) { + log_debug("sd-device: %s is not a directory", syspath); + return -EINVAL; + } + } + } else { + syspath = strdup(_syspath); + if (!syspath) + return -ENOMEM; + } - /* all 'devices' require an 'uevent' file */ - path = strappenda(syspath, "/uevent"); - r = access(path, F_OK); - if (r < 0) - return -errno; - } else - /* everything else just just needs to be a directory */ - if (!is_dir(syspath, false)) - return -EINVAL; + devpath = syspath + strlen("/sys"); pos = strrchr(syspath, '/'); if (!pos) @@ -515,7 +545,7 @@ static int device_read_uevent_file(sd_device *device) { assert(device); - if (device->uevent_loaded) + if (device->uevent_loaded || device->sealed) return 0; r = sd_device_get_syspath(device, &syspath); @@ -598,7 +628,7 @@ _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) { if (r < 0) return r; - r = device_set_syspath(device, syspath); + r = device_set_syspath(device, syspath, true); if (r < 0) return r; @@ -1207,7 +1237,7 @@ static int device_read_db(sd_device *device) { INVALID_LINE, } state = PRE_KEY; - if (device->db_loaded) + if (device->db_loaded || device->sealed) return 0; r = device_get_id_filename(device, &id); @@ -1589,6 +1619,225 @@ _public_ const char *sd_device_get_sysattr_next(sd_device *device, const char ** return key; } +static int device_set_devmode(sd_device *device, const char *mode) { + unsigned m; + int r; + + assert(device); + assert(mode); + + r = safe_atou(mode, &m); + if (r < 0) + return r; + + r = device_add_property(device, "DEVMODE", mode); + if (r < 0) + return r; + + device->devmode = m; + + return 0; +} + +static int device_set_devuid(sd_device *device, const char *uid) { + unsigned u; + int r; + + assert(device); + assert(uid); + + r = safe_atou(uid, &u); + if (r < 0) + return r; + + r = device_add_property(device, "DEVUID", uid); + if (r < 0) + return r; + + device->devuid = u; + + return 0; +} + +static int device_set_devgid(sd_device *device, const char *gid) { + unsigned g; + int r; + + assert(device); + assert(gid); + + r = safe_atou(gid, &g); + if (r < 0) + return r; + + r = device_add_property(device, "DEVGID", gid); + if (r < 0) + return r; + + device->devgid = g; + + return 0; +} + +static int device_ammend(sd_device *device, const char *key, const char *value) { + int r; + + assert(device); + assert(key); + assert(value); + + if (streq(key, "DEVPATH")) { + char *path; + + path = strappenda("/sys", value); + + /* the caller must verify or trust this data (e.g., if it comes from the kernel */ + r = device_set_syspath(device, path, false); + if (r < 0) { + log_debug("sd-device: could not set syspath to '%s': %s", path, strerror(-r)); + return r; + } + } else if (streq(key, "SUBSYSTEM")) { + r = device_set_subsystem(device, value); + if (r < 0) + return r; + } else if (streq(key, "DEVTYPE")) { + r = device_set_devtype(device, value); + if (r < 0) + return r; + } else if (streq(key, "DEVNAME")) { + r = device_set_devnode(device, value); + if (r < 0) + return r; + } else if (streq(key, "USEC_INITIALIZED")) { + r = device_set_usec_initialized(device, value); + if (r < 0) + return r; + } else if (streq(key, "DRIVER")) { + r = device_set_driver(device, value); + if (r < 0) + return r; + } else if (streq(key, "IFINDEX")) { + r = device_set_ifindex(device, value); + if (r < 0) + return r; + } else if (streq(key, "DEVMODE")) { + r = device_set_devmode(device, value); + if (r < 0) + return r; + } else if (streq(key, "DEVUID")) { + r = device_set_devuid(device, value); + if (r < 0) + return r; + } else if (streq(key, "DEVGID")) { + r = device_set_devgid(device, value); + if (r < 0) + return r; +/* + } else if (streq(key, "DEVLINKS")) { + + } else if (streq(key, "TAGS")) { +*/ + } else { + r = device_add_property(device, key, value); + if (r < 0) + return r; + } + + return 0; +} + +int device_new_from_nulstr(sd_device **ret, uint64_t *_seqnum, DeviceAction *_action, const char **_devpath_old, uint8_t *nulstr, size_t len) { + _cleanup_device_unref_ sd_device *device = NULL; + const char *major = NULL, *minor = NULL, *devpath_old = NULL; + DeviceAction action = _DEVICE_ACTION_INVALID; + uint64_t seqnum; + unsigned i = 0; + int r; + + assert(ret); + assert(_seqnum); + assert(_action); + assert(_devpath_old); + assert(nulstr); + assert(len); + + r = device_new(&device); + if (r < 0) + return r; + + while (i < len) { + const char *key, *end; + char *value; + + key = (char*)&nulstr[i]; + end = memchr(key, '\0', len - i); + if (!end) { + log_debug("sd-device: failed to parse nulstr"); + return -EINVAL; + } + i += end - key + 1; + + value = strchr(key, '='); + if (!value) { + log_debug("sd-device: not a key-value pair: '%s'", key); + return -EINVAL; + } + + *value = '\0'; + + value++; + + if (streq(key, "MAJOR")) + major = value; + else if (streq(key, "MINOR")) + minor = value; + else if (streq(key, "DEVPATH_OLD")) + devpath_old = value; + else if (streq(key, "ACTION")) { + action = device_action_from_string(value); + if (action == _DEVICE_ACTION_INVALID) { + log_debug("sd-device: received device with invalid action '%s'", value); + return -EINVAL; + } + } else if (streq(key, "SEQNUM")) { + r = safe_atou64(value, &seqnum); + if (r < 0) + return r; + } else { + r = device_ammend(device, key, value); + if (r < 0) { + log_debug("sd-device: could not append '%s=%s' to device: %s", key, value, strerror(-r)); + return r; + } + } + } + + if (!device->devpath || !device->subsystem || action == _DEVICE_ACTION_INVALID) { + log_debug("sd-device: device created from strv lacks devpath, subsystem or action"); + return -EINVAL; + } + + if (major) { + r = device_set_devnum(device, major, minor); + if (r < 0) { + log_debug("sd-device: could not set devnum %s:%s: %s", major, minor, strerror(-r)); + return r; + } + } + + *_action = action; + *_devpath_old = devpath_old; + *_seqnum = seqnum; + + device->sealed = true; + + *ret = device; + device = NULL; + + return 0; +} + int device_get_devlink_priority(sd_device *device, int *priority) { int r; |