199ca880aSopenharmony_ci/* 299ca880aSopenharmony_ci * Copyright (C) 2003-2013 Kay Sievers <kay@vrfy.org> 399ca880aSopenharmony_ci * 499ca880aSopenharmony_ci * This program is free software: you can redistribute it and/or modify 599ca880aSopenharmony_ci * it under the terms of the GNU General Public License as published by 699ca880aSopenharmony_ci * the Free Software Foundation, either version 2 of the License, or 799ca880aSopenharmony_ci * (at your option) any later version. 899ca880aSopenharmony_ci * 999ca880aSopenharmony_ci * This program is distributed in the hope that it will be useful, 1099ca880aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 1199ca880aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1299ca880aSopenharmony_ci * GNU General Public License for more details. 1399ca880aSopenharmony_ci * 1499ca880aSopenharmony_ci * You should have received a copy of the GNU General Public License 1599ca880aSopenharmony_ci * along with this program. If not, see <http://www.gnu.org/licenses/>. 1699ca880aSopenharmony_ci */ 1799ca880aSopenharmony_ci 1899ca880aSopenharmony_ci#include <stdlib.h> 1999ca880aSopenharmony_ci#include <stdio.h> 2099ca880aSopenharmony_ci#include <stddef.h> 2199ca880aSopenharmony_ci#include <unistd.h> 2299ca880aSopenharmony_ci#include <fcntl.h> 2399ca880aSopenharmony_ci#include <errno.h> 2499ca880aSopenharmony_ci#include <ctype.h> 2599ca880aSopenharmony_ci#include <string.h> 2699ca880aSopenharmony_ci#include <time.h> 2799ca880aSopenharmony_ci#include <net/if.h> 2899ca880aSopenharmony_ci#include <sys/ioctl.h> 2999ca880aSopenharmony_ci#include <sys/prctl.h> 3099ca880aSopenharmony_ci#include <poll.h> 3199ca880aSopenharmony_ci#include <sys/epoll.h> 3299ca880aSopenharmony_ci#include <sys/wait.h> 3399ca880aSopenharmony_ci#include <sys/socket.h> 3499ca880aSopenharmony_ci#include <sys/signalfd.h> 3599ca880aSopenharmony_ci#include <linux/sockios.h> 3699ca880aSopenharmony_ci#include <sys/sysmacros.h> 3799ca880aSopenharmony_ci 3899ca880aSopenharmony_ci#include "udev.h" 3999ca880aSopenharmony_ci 4099ca880aSopenharmony_cistruct udev_event *udev_event_new(struct udev_device *dev) { 4199ca880aSopenharmony_ci struct udev *udev = udev_device_get_udev(dev); 4299ca880aSopenharmony_ci struct udev_event *event; 4399ca880aSopenharmony_ci 4499ca880aSopenharmony_ci event = new0(struct udev_event, 1); 4599ca880aSopenharmony_ci if (event == NULL) 4699ca880aSopenharmony_ci return NULL; 4799ca880aSopenharmony_ci event->dev = dev; 4899ca880aSopenharmony_ci event->udev = udev; 4999ca880aSopenharmony_ci udev_list_init(udev, &event->run_list, false); 5099ca880aSopenharmony_ci udev_list_init(udev, &event->seclabel_list, false); 5199ca880aSopenharmony_ci event->fd_signal = -1; 5299ca880aSopenharmony_ci event->birth_usec = now(CLOCK_MONOTONIC); 5399ca880aSopenharmony_ci return event; 5499ca880aSopenharmony_ci} 5599ca880aSopenharmony_ci 5699ca880aSopenharmony_civoid udev_event_unref(struct udev_event *event) { 5799ca880aSopenharmony_ci if (event == NULL) 5899ca880aSopenharmony_ci return; 5999ca880aSopenharmony_ci udev_list_cleanup(&event->run_list); 6099ca880aSopenharmony_ci udev_list_cleanup(&event->seclabel_list); 6199ca880aSopenharmony_ci free(event->program_result); 6299ca880aSopenharmony_ci free(event->name); 6399ca880aSopenharmony_ci free(event); 6499ca880aSopenharmony_ci} 6599ca880aSopenharmony_ci 6699ca880aSopenharmony_cisize_t udev_event_apply_format(struct udev_event *event, 6799ca880aSopenharmony_ci const char *src, char *dest, size_t size, 6899ca880aSopenharmony_ci bool replace_whitespace) { 6999ca880aSopenharmony_ci struct udev_device *dev = event->dev; 7099ca880aSopenharmony_ci enum subst_type { 7199ca880aSopenharmony_ci SUBST_UNKNOWN, 7299ca880aSopenharmony_ci SUBST_DEVNODE, 7399ca880aSopenharmony_ci SUBST_ATTR, 7499ca880aSopenharmony_ci SUBST_ENV, 7599ca880aSopenharmony_ci SUBST_KERNEL, 7699ca880aSopenharmony_ci SUBST_KERNEL_NUMBER, 7799ca880aSopenharmony_ci SUBST_DRIVER, 7899ca880aSopenharmony_ci SUBST_DEVPATH, 7999ca880aSopenharmony_ci SUBST_ID, 8099ca880aSopenharmony_ci SUBST_MAJOR, 8199ca880aSopenharmony_ci SUBST_MINOR, 8299ca880aSopenharmony_ci SUBST_RESULT, 8399ca880aSopenharmony_ci SUBST_PARENT, 8499ca880aSopenharmony_ci SUBST_NAME, 8599ca880aSopenharmony_ci SUBST_LINKS, 8699ca880aSopenharmony_ci SUBST_ROOT, 8799ca880aSopenharmony_ci SUBST_SYS, 8899ca880aSopenharmony_ci }; 8999ca880aSopenharmony_ci static const struct subst_map { 9099ca880aSopenharmony_ci const char *name; 9199ca880aSopenharmony_ci const char fmt; 9299ca880aSopenharmony_ci enum subst_type type; 9399ca880aSopenharmony_ci } map[] = { 9499ca880aSopenharmony_ci { .name = "devnode", .fmt = 'N', .type = SUBST_DEVNODE }, 9599ca880aSopenharmony_ci { .name = "tempnode", .fmt = 'N', .type = SUBST_DEVNODE }, 9699ca880aSopenharmony_ci { .name = "attr", .fmt = 's', .type = SUBST_ATTR }, 9799ca880aSopenharmony_ci { .name = "sysfs", .fmt = 's', .type = SUBST_ATTR }, 9899ca880aSopenharmony_ci { .name = "env", .fmt = 'E', .type = SUBST_ENV }, 9999ca880aSopenharmony_ci { .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL }, 10099ca880aSopenharmony_ci { .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER }, 10199ca880aSopenharmony_ci { .name = "driver", .fmt = 'd', .type = SUBST_DRIVER }, 10299ca880aSopenharmony_ci { .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH }, 10399ca880aSopenharmony_ci { .name = "id", .fmt = 'b', .type = SUBST_ID }, 10499ca880aSopenharmony_ci { .name = "major", .fmt = 'M', .type = SUBST_MAJOR }, 10599ca880aSopenharmony_ci { .name = "minor", .fmt = 'm', .type = SUBST_MINOR }, 10699ca880aSopenharmony_ci { .name = "result", .fmt = 'c', .type = SUBST_RESULT }, 10799ca880aSopenharmony_ci { .name = "parent", .fmt = 'P', .type = SUBST_PARENT }, 10899ca880aSopenharmony_ci { .name = "name", .fmt = 'D', .type = SUBST_NAME }, 10999ca880aSopenharmony_ci { .name = "links", .fmt = 'L', .type = SUBST_LINKS }, 11099ca880aSopenharmony_ci { .name = "root", .fmt = 'r', .type = SUBST_ROOT }, 11199ca880aSopenharmony_ci { .name = "sys", .fmt = 'S', .type = SUBST_SYS }, 11299ca880aSopenharmony_ci }; 11399ca880aSopenharmony_ci const char *from; 11499ca880aSopenharmony_ci char *s; 11599ca880aSopenharmony_ci size_t l; 11699ca880aSopenharmony_ci 11799ca880aSopenharmony_ci from = src; 11899ca880aSopenharmony_ci s = dest; 11999ca880aSopenharmony_ci l = size; 12099ca880aSopenharmony_ci 12199ca880aSopenharmony_ci for (;;) { 12299ca880aSopenharmony_ci enum subst_type type = SUBST_UNKNOWN; 12399ca880aSopenharmony_ci char attrbuf[UTIL_PATH_SIZE], sbuf[UTIL_PATH_SIZE]; 12499ca880aSopenharmony_ci char *attr = NULL, *_s; 12599ca880aSopenharmony_ci size_t _l; 12699ca880aSopenharmony_ci bool replws = replace_whitespace; 12799ca880aSopenharmony_ci 12899ca880aSopenharmony_ci while (from[0] != '\0') { 12999ca880aSopenharmony_ci if (from[0] == '$') { 13099ca880aSopenharmony_ci /* substitute named variable */ 13199ca880aSopenharmony_ci unsigned int i; 13299ca880aSopenharmony_ci 13399ca880aSopenharmony_ci if (from[1] == '$') { 13499ca880aSopenharmony_ci from++; 13599ca880aSopenharmony_ci goto copy; 13699ca880aSopenharmony_ci } 13799ca880aSopenharmony_ci 13899ca880aSopenharmony_ci for (i = 0; i < ELEMENTSOF(map); i++) { 13999ca880aSopenharmony_ci if (startswith(&from[1], map[i].name)) { 14099ca880aSopenharmony_ci type = map[i].type; 14199ca880aSopenharmony_ci from += strlen(map[i].name)+1; 14299ca880aSopenharmony_ci goto subst; 14399ca880aSopenharmony_ci } 14499ca880aSopenharmony_ci } 14599ca880aSopenharmony_ci } else if (from[0] == '%') { 14699ca880aSopenharmony_ci /* substitute format char */ 14799ca880aSopenharmony_ci unsigned int i; 14899ca880aSopenharmony_ci 14999ca880aSopenharmony_ci if (from[1] == '%') { 15099ca880aSopenharmony_ci from++; 15199ca880aSopenharmony_ci goto copy; 15299ca880aSopenharmony_ci } 15399ca880aSopenharmony_ci 15499ca880aSopenharmony_ci for (i = 0; i < ELEMENTSOF(map); i++) { 15599ca880aSopenharmony_ci if (from[1] == map[i].fmt) { 15699ca880aSopenharmony_ci type = map[i].type; 15799ca880aSopenharmony_ci from += 2; 15899ca880aSopenharmony_ci goto subst; 15999ca880aSopenharmony_ci } 16099ca880aSopenharmony_ci } 16199ca880aSopenharmony_ci } 16299ca880aSopenharmony_cicopy: 16399ca880aSopenharmony_ci /* copy char */ 16499ca880aSopenharmony_ci if (l == 0) 16599ca880aSopenharmony_ci goto out; 16699ca880aSopenharmony_ci s[0] = from[0]; 16799ca880aSopenharmony_ci from++; 16899ca880aSopenharmony_ci s++; 16999ca880aSopenharmony_ci l--; 17099ca880aSopenharmony_ci } 17199ca880aSopenharmony_ci 17299ca880aSopenharmony_ci goto out; 17399ca880aSopenharmony_cisubst: 17499ca880aSopenharmony_ci /* extract possible $format{attr} */ 17599ca880aSopenharmony_ci if (from[0] == '{') { 17699ca880aSopenharmony_ci unsigned int i; 17799ca880aSopenharmony_ci 17899ca880aSopenharmony_ci from++; 17999ca880aSopenharmony_ci for (i = 0; from[i] != '}'; i++) { 18099ca880aSopenharmony_ci if (from[i] == '\0') { 18199ca880aSopenharmony_ci log_error("missing closing brace for format '%s'", src); 18299ca880aSopenharmony_ci goto out; 18399ca880aSopenharmony_ci } 18499ca880aSopenharmony_ci } 18599ca880aSopenharmony_ci if (i >= sizeof(attrbuf)) 18699ca880aSopenharmony_ci goto out; 18799ca880aSopenharmony_ci memcpy(attrbuf, from, i); 18899ca880aSopenharmony_ci attrbuf[i] = '\0'; 18999ca880aSopenharmony_ci from += i+1; 19099ca880aSopenharmony_ci attr = attrbuf; 19199ca880aSopenharmony_ci } else { 19299ca880aSopenharmony_ci attr = NULL; 19399ca880aSopenharmony_ci } 19499ca880aSopenharmony_ci 19599ca880aSopenharmony_ci /* result subst handles space as field separator */ 19699ca880aSopenharmony_ci if (type == SUBST_RESULT) 19799ca880aSopenharmony_ci replws = false; 19899ca880aSopenharmony_ci 19999ca880aSopenharmony_ci if (replws) { 20099ca880aSopenharmony_ci /* store dest string ptr and remaining len */ 20199ca880aSopenharmony_ci _s = s; 20299ca880aSopenharmony_ci _l = l; 20399ca880aSopenharmony_ci /* temporarily use sbuf */ 20499ca880aSopenharmony_ci s = sbuf; 20599ca880aSopenharmony_ci l = UTIL_PATH_SIZE; 20699ca880aSopenharmony_ci } 20799ca880aSopenharmony_ci 20899ca880aSopenharmony_ci switch (type) { 20999ca880aSopenharmony_ci case SUBST_DEVPATH: 21099ca880aSopenharmony_ci l = strpcpy(&s, l, udev_device_get_devpath(dev)); 21199ca880aSopenharmony_ci break; 21299ca880aSopenharmony_ci case SUBST_KERNEL: 21399ca880aSopenharmony_ci l = strpcpy(&s, l, udev_device_get_sysname(dev)); 21499ca880aSopenharmony_ci break; 21599ca880aSopenharmony_ci case SUBST_KERNEL_NUMBER: 21699ca880aSopenharmony_ci if (udev_device_get_sysnum(dev) == NULL) 21799ca880aSopenharmony_ci break; 21899ca880aSopenharmony_ci l = strpcpy(&s, l, udev_device_get_sysnum(dev)); 21999ca880aSopenharmony_ci break; 22099ca880aSopenharmony_ci case SUBST_ID: 22199ca880aSopenharmony_ci if (event->dev_parent == NULL) 22299ca880aSopenharmony_ci break; 22399ca880aSopenharmony_ci l = strpcpy(&s, l, udev_device_get_sysname(event->dev_parent)); 22499ca880aSopenharmony_ci break; 22599ca880aSopenharmony_ci case SUBST_DRIVER: { 22699ca880aSopenharmony_ci const char *driver; 22799ca880aSopenharmony_ci 22899ca880aSopenharmony_ci if (event->dev_parent == NULL) 22999ca880aSopenharmony_ci break; 23099ca880aSopenharmony_ci 23199ca880aSopenharmony_ci driver = udev_device_get_driver(event->dev_parent); 23299ca880aSopenharmony_ci if (driver == NULL) 23399ca880aSopenharmony_ci break; 23499ca880aSopenharmony_ci l = strpcpy(&s, l, driver); 23599ca880aSopenharmony_ci break; 23699ca880aSopenharmony_ci } 23799ca880aSopenharmony_ci case SUBST_MAJOR: { 23899ca880aSopenharmony_ci char num[UTIL_PATH_SIZE]; 23999ca880aSopenharmony_ci 24099ca880aSopenharmony_ci sprintf(num, "%u", major(udev_device_get_devnum(dev))); 24199ca880aSopenharmony_ci l = strpcpy(&s, l, num); 24299ca880aSopenharmony_ci break; 24399ca880aSopenharmony_ci } 24499ca880aSopenharmony_ci case SUBST_MINOR: { 24599ca880aSopenharmony_ci char num[UTIL_PATH_SIZE]; 24699ca880aSopenharmony_ci 24799ca880aSopenharmony_ci sprintf(num, "%u", minor(udev_device_get_devnum(dev))); 24899ca880aSopenharmony_ci l = strpcpy(&s, l, num); 24999ca880aSopenharmony_ci break; 25099ca880aSopenharmony_ci } 25199ca880aSopenharmony_ci case SUBST_RESULT: { 25299ca880aSopenharmony_ci char *rest; 25399ca880aSopenharmony_ci int i; 25499ca880aSopenharmony_ci 25599ca880aSopenharmony_ci if (event->program_result == NULL) 25699ca880aSopenharmony_ci break; 25799ca880aSopenharmony_ci /* get part part of the result string */ 25899ca880aSopenharmony_ci i = 0; 25999ca880aSopenharmony_ci if (attr != NULL) 26099ca880aSopenharmony_ci i = strtoul(attr, &rest, 10); 26199ca880aSopenharmony_ci if (i > 0) { 26299ca880aSopenharmony_ci char result[UTIL_PATH_SIZE]; 26399ca880aSopenharmony_ci char tmp[UTIL_PATH_SIZE]; 26499ca880aSopenharmony_ci char *cpos; 26599ca880aSopenharmony_ci 26699ca880aSopenharmony_ci strscpy(result, sizeof(result), event->program_result); 26799ca880aSopenharmony_ci cpos = result; 26899ca880aSopenharmony_ci while (--i) { 26999ca880aSopenharmony_ci while (cpos[0] != '\0' && !isspace(cpos[0])) 27099ca880aSopenharmony_ci cpos++; 27199ca880aSopenharmony_ci while (isspace(cpos[0])) 27299ca880aSopenharmony_ci cpos++; 27399ca880aSopenharmony_ci if (cpos[0] == '\0') 27499ca880aSopenharmony_ci break; 27599ca880aSopenharmony_ci } 27699ca880aSopenharmony_ci if (i > 0) { 27799ca880aSopenharmony_ci log_error("requested part of result string not found"); 27899ca880aSopenharmony_ci break; 27999ca880aSopenharmony_ci } 28099ca880aSopenharmony_ci strscpy(tmp, sizeof(tmp), cpos); 28199ca880aSopenharmony_ci /* %{2+}c copies the whole string from the second part on */ 28299ca880aSopenharmony_ci if (rest[0] != '+') { 28399ca880aSopenharmony_ci cpos = strchr(tmp, ' '); 28499ca880aSopenharmony_ci if (cpos) 28599ca880aSopenharmony_ci cpos[0] = '\0'; 28699ca880aSopenharmony_ci } 28799ca880aSopenharmony_ci l = strpcpy(&s, l, tmp); 28899ca880aSopenharmony_ci } else { 28999ca880aSopenharmony_ci l = strpcpy(&s, l, event->program_result); 29099ca880aSopenharmony_ci } 29199ca880aSopenharmony_ci break; 29299ca880aSopenharmony_ci } 29399ca880aSopenharmony_ci case SUBST_ATTR: { 29499ca880aSopenharmony_ci const char *value = NULL; 29599ca880aSopenharmony_ci char vbuf[UTIL_NAME_SIZE]; 29699ca880aSopenharmony_ci size_t len; 29799ca880aSopenharmony_ci int count; 29899ca880aSopenharmony_ci 29999ca880aSopenharmony_ci if (attr == NULL) { 30099ca880aSopenharmony_ci log_error("missing file parameter for attr"); 30199ca880aSopenharmony_ci break; 30299ca880aSopenharmony_ci } 30399ca880aSopenharmony_ci 30499ca880aSopenharmony_ci /* try to read the value specified by "[dmi/id]product_name" */ 30599ca880aSopenharmony_ci if (util_resolve_subsys_kernel(event->udev, attr, vbuf, sizeof(vbuf), 1) == 0) 30699ca880aSopenharmony_ci value = vbuf; 30799ca880aSopenharmony_ci 30899ca880aSopenharmony_ci /* try to read the attribute the device */ 30999ca880aSopenharmony_ci if (value == NULL) 31099ca880aSopenharmony_ci value = udev_device_get_sysattr_value(event->dev, attr); 31199ca880aSopenharmony_ci 31299ca880aSopenharmony_ci /* try to read the attribute of the parent device, other matches have selected */ 31399ca880aSopenharmony_ci if (value == NULL && event->dev_parent != NULL && event->dev_parent != event->dev) 31499ca880aSopenharmony_ci value = udev_device_get_sysattr_value(event->dev_parent, attr); 31599ca880aSopenharmony_ci 31699ca880aSopenharmony_ci if (value == NULL) 31799ca880aSopenharmony_ci break; 31899ca880aSopenharmony_ci 31999ca880aSopenharmony_ci /* strip trailing whitespace, and replace unwanted characters */ 32099ca880aSopenharmony_ci if (value != vbuf) 32199ca880aSopenharmony_ci strscpy(vbuf, sizeof(vbuf), value); 32299ca880aSopenharmony_ci len = strlen(vbuf); 32399ca880aSopenharmony_ci while (len > 0 && isspace(vbuf[--len])) 32499ca880aSopenharmony_ci vbuf[len] = '\0'; 32599ca880aSopenharmony_ci count = util_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT); 32699ca880aSopenharmony_ci if (count > 0) 32799ca880aSopenharmony_ci log_debug("%i character(s) replaced" , count); 32899ca880aSopenharmony_ci l = strpcpy(&s, l, vbuf); 32999ca880aSopenharmony_ci break; 33099ca880aSopenharmony_ci } 33199ca880aSopenharmony_ci case SUBST_PARENT: { 33299ca880aSopenharmony_ci struct udev_device *dev_parent; 33399ca880aSopenharmony_ci const char *devnode; 33499ca880aSopenharmony_ci 33599ca880aSopenharmony_ci dev_parent = udev_device_get_parent(event->dev); 33699ca880aSopenharmony_ci if (dev_parent == NULL) 33799ca880aSopenharmony_ci break; 33899ca880aSopenharmony_ci devnode = udev_device_get_devnode(dev_parent); 33999ca880aSopenharmony_ci if (devnode != NULL) 34099ca880aSopenharmony_ci l = strpcpy(&s, l, devnode + strlen("/dev/")); 34199ca880aSopenharmony_ci break; 34299ca880aSopenharmony_ci } 34399ca880aSopenharmony_ci case SUBST_DEVNODE: 34499ca880aSopenharmony_ci if (udev_device_get_devnode(dev) != NULL) 34599ca880aSopenharmony_ci l = strpcpy(&s, l, udev_device_get_devnode(dev)); 34699ca880aSopenharmony_ci break; 34799ca880aSopenharmony_ci case SUBST_NAME: 34899ca880aSopenharmony_ci if (event->name != NULL) 34999ca880aSopenharmony_ci l = strpcpy(&s, l, event->name); 35099ca880aSopenharmony_ci else if (udev_device_get_devnode(dev) != NULL) 35199ca880aSopenharmony_ci l = strpcpy(&s, l, udev_device_get_devnode(dev) + strlen("/dev/")); 35299ca880aSopenharmony_ci else 35399ca880aSopenharmony_ci l = strpcpy(&s, l, udev_device_get_sysname(dev)); 35499ca880aSopenharmony_ci break; 35599ca880aSopenharmony_ci case SUBST_LINKS: { 35699ca880aSopenharmony_ci struct udev_list_entry *list_entry; 35799ca880aSopenharmony_ci 35899ca880aSopenharmony_ci list_entry = udev_device_get_devlinks_list_entry(dev); 35999ca880aSopenharmony_ci if (list_entry == NULL) 36099ca880aSopenharmony_ci break; 36199ca880aSopenharmony_ci l = strpcpy(&s, l, udev_list_entry_get_name(list_entry) + strlen("/dev/")); 36299ca880aSopenharmony_ci udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry)) 36399ca880aSopenharmony_ci l = strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry) + strlen("/dev/"), NULL); 36499ca880aSopenharmony_ci break; 36599ca880aSopenharmony_ci } 36699ca880aSopenharmony_ci case SUBST_ROOT: 36799ca880aSopenharmony_ci l = strpcpy(&s, l, "/dev"); 36899ca880aSopenharmony_ci break; 36999ca880aSopenharmony_ci case SUBST_SYS: 37099ca880aSopenharmony_ci l = strpcpy(&s, l, "/sys"); 37199ca880aSopenharmony_ci break; 37299ca880aSopenharmony_ci case SUBST_ENV: 37399ca880aSopenharmony_ci if (attr == NULL) { 37499ca880aSopenharmony_ci break; 37599ca880aSopenharmony_ci } else { 37699ca880aSopenharmony_ci const char *value; 37799ca880aSopenharmony_ci 37899ca880aSopenharmony_ci value = udev_device_get_property_value(event->dev, attr); 37999ca880aSopenharmony_ci if (value == NULL) 38099ca880aSopenharmony_ci break; 38199ca880aSopenharmony_ci l = strpcpy(&s, l, value); 38299ca880aSopenharmony_ci break; 38399ca880aSopenharmony_ci } 38499ca880aSopenharmony_ci default: 38599ca880aSopenharmony_ci log_error("unknown substitution type=%i", type); 38699ca880aSopenharmony_ci break; 38799ca880aSopenharmony_ci } 38899ca880aSopenharmony_ci 38999ca880aSopenharmony_ci /* replace whitespace in sbuf and copy to dest */ 39099ca880aSopenharmony_ci if (replws) { 39199ca880aSopenharmony_ci size_t tmplen = UTIL_PATH_SIZE - l; 39299ca880aSopenharmony_ci 39399ca880aSopenharmony_ci /* restore s and l to dest string values */ 39499ca880aSopenharmony_ci s = _s; 39599ca880aSopenharmony_ci l = _l; 39699ca880aSopenharmony_ci 39799ca880aSopenharmony_ci /* copy ws-replaced value to s */ 39899ca880aSopenharmony_ci tmplen = util_replace_whitespace(sbuf, s, MIN(tmplen, l)); 39999ca880aSopenharmony_ci l -= tmplen; 40099ca880aSopenharmony_ci s += tmplen; 40199ca880aSopenharmony_ci } 40299ca880aSopenharmony_ci } 40399ca880aSopenharmony_ci 40499ca880aSopenharmony_ciout: 40599ca880aSopenharmony_ci s[0] = '\0'; 40699ca880aSopenharmony_ci return l; 40799ca880aSopenharmony_ci} 40899ca880aSopenharmony_ci 40999ca880aSopenharmony_cistatic int spawn_exec(struct udev_event *event, 41099ca880aSopenharmony_ci const char *cmd, char *const argv[], char **envp, const sigset_t *sigmask, 41199ca880aSopenharmony_ci int fd_stdout, int fd_stderr) { 41299ca880aSopenharmony_ci _cleanup_close_ int fd = -1; 41399ca880aSopenharmony_ci 41499ca880aSopenharmony_ci /* discard child output or connect to pipe */ 41599ca880aSopenharmony_ci fd = open("/dev/null", O_RDWR); 41699ca880aSopenharmony_ci if (fd >= 0) { 41799ca880aSopenharmony_ci dup2(fd, STDIN_FILENO); 41899ca880aSopenharmony_ci if (fd_stdout < 0) 41999ca880aSopenharmony_ci dup2(fd, STDOUT_FILENO); 42099ca880aSopenharmony_ci if (fd_stderr < 0) 42199ca880aSopenharmony_ci dup2(fd, STDERR_FILENO); 42299ca880aSopenharmony_ci } else 42399ca880aSopenharmony_ci log_error_errno(errno, "open /dev/null failed: %m"); 42499ca880aSopenharmony_ci 42599ca880aSopenharmony_ci /* connect pipes to std{out,err} */ 42699ca880aSopenharmony_ci if (fd_stdout >= 0) { 42799ca880aSopenharmony_ci dup2(fd_stdout, STDOUT_FILENO); 42899ca880aSopenharmony_ci safe_close(fd_stdout); 42999ca880aSopenharmony_ci } 43099ca880aSopenharmony_ci if (fd_stderr >= 0) { 43199ca880aSopenharmony_ci dup2(fd_stderr, STDERR_FILENO); 43299ca880aSopenharmony_ci safe_close(fd_stderr); 43399ca880aSopenharmony_ci } 43499ca880aSopenharmony_ci 43599ca880aSopenharmony_ci /* terminate child in case parent goes away */ 43699ca880aSopenharmony_ci prctl(PR_SET_PDEATHSIG, SIGTERM); 43799ca880aSopenharmony_ci 43899ca880aSopenharmony_ci /* restore original udev sigmask before exec */ 43999ca880aSopenharmony_ci if (sigmask) 44099ca880aSopenharmony_ci sigprocmask(SIG_SETMASK, sigmask, NULL); 44199ca880aSopenharmony_ci 44299ca880aSopenharmony_ci //execve(argv[0], argv, envp); 44399ca880aSopenharmony_ci 44499ca880aSopenharmony_ci /* exec failed */ 44599ca880aSopenharmony_ci log_error_errno(errno, "failed to execute '%s' '%s': %m", argv[0], cmd); 44699ca880aSopenharmony_ci 44799ca880aSopenharmony_ci return -errno; 44899ca880aSopenharmony_ci} 44999ca880aSopenharmony_ci 45099ca880aSopenharmony_cistatic void spawn_read(struct udev_event *event, 45199ca880aSopenharmony_ci usec_t timeout_usec, 45299ca880aSopenharmony_ci const char *cmd, 45399ca880aSopenharmony_ci int fd_stdout, int fd_stderr, 45499ca880aSopenharmony_ci char *result, size_t ressize) { 45599ca880aSopenharmony_ci _cleanup_close_ int fd_ep = -1; 45699ca880aSopenharmony_ci struct epoll_event ep_outpipe = { 45799ca880aSopenharmony_ci .events = EPOLLIN, 45899ca880aSopenharmony_ci .data.ptr = &fd_stdout, 45999ca880aSopenharmony_ci }; 46099ca880aSopenharmony_ci struct epoll_event ep_errpipe = { 46199ca880aSopenharmony_ci .events = EPOLLIN, 46299ca880aSopenharmony_ci .data.ptr = &fd_stderr, 46399ca880aSopenharmony_ci }; 46499ca880aSopenharmony_ci size_t respos = 0; 46599ca880aSopenharmony_ci int r; 46699ca880aSopenharmony_ci 46799ca880aSopenharmony_ci /* read from child if requested */ 46899ca880aSopenharmony_ci if (fd_stdout < 0 && fd_stderr < 0) 46999ca880aSopenharmony_ci return; 47099ca880aSopenharmony_ci 47199ca880aSopenharmony_ci fd_ep = epoll_create1(EPOLL_CLOEXEC); 47299ca880aSopenharmony_ci if (fd_ep < 0) { 47399ca880aSopenharmony_ci log_error_errno(errno, "error creating epoll fd: %m"); 47499ca880aSopenharmony_ci return; 47599ca880aSopenharmony_ci } 47699ca880aSopenharmony_ci 47799ca880aSopenharmony_ci if (fd_stdout >= 0) { 47899ca880aSopenharmony_ci r = epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stdout, &ep_outpipe); 47999ca880aSopenharmony_ci if (r < 0) { 48099ca880aSopenharmony_ci log_error_errno(errno, "fail to add stdout fd to epoll: %m"); 48199ca880aSopenharmony_ci return; 48299ca880aSopenharmony_ci } 48399ca880aSopenharmony_ci } 48499ca880aSopenharmony_ci 48599ca880aSopenharmony_ci if (fd_stderr >= 0) { 48699ca880aSopenharmony_ci r = epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stderr, &ep_errpipe); 48799ca880aSopenharmony_ci if (r < 0) { 48899ca880aSopenharmony_ci log_error_errno(errno, "fail to add stderr fd to epoll: %m"); 48999ca880aSopenharmony_ci return; 49099ca880aSopenharmony_ci } 49199ca880aSopenharmony_ci } 49299ca880aSopenharmony_ci 49399ca880aSopenharmony_ci /* read child output */ 49499ca880aSopenharmony_ci while (fd_stdout >= 0 || fd_stderr >= 0) { 49599ca880aSopenharmony_ci int timeout; 49699ca880aSopenharmony_ci int fdcount; 49799ca880aSopenharmony_ci struct epoll_event ev[4]; 49899ca880aSopenharmony_ci int i; 49999ca880aSopenharmony_ci 50099ca880aSopenharmony_ci if (timeout_usec > 0) { 50199ca880aSopenharmony_ci usec_t age_usec; 50299ca880aSopenharmony_ci 50399ca880aSopenharmony_ci age_usec = now(CLOCK_MONOTONIC) - event->birth_usec; 50499ca880aSopenharmony_ci if (age_usec >= timeout_usec) { 50599ca880aSopenharmony_ci log_error("timeout '%s'", cmd); 50699ca880aSopenharmony_ci return; 50799ca880aSopenharmony_ci } 50899ca880aSopenharmony_ci timeout = ((timeout_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC; 50999ca880aSopenharmony_ci } else { 51099ca880aSopenharmony_ci timeout = -1; 51199ca880aSopenharmony_ci } 51299ca880aSopenharmony_ci 51399ca880aSopenharmony_ci fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), timeout); 51499ca880aSopenharmony_ci if (fdcount < 0) { 51599ca880aSopenharmony_ci if (errno == EINTR) 51699ca880aSopenharmony_ci continue; 51799ca880aSopenharmony_ci log_error_errno(errno, "failed to poll: %m"); 51899ca880aSopenharmony_ci return; 51999ca880aSopenharmony_ci } else if (fdcount == 0) { 52099ca880aSopenharmony_ci log_error("timeout '%s'", cmd); 52199ca880aSopenharmony_ci return; 52299ca880aSopenharmony_ci } 52399ca880aSopenharmony_ci 52499ca880aSopenharmony_ci for (i = 0; i < fdcount; i++) { 52599ca880aSopenharmony_ci int *fd = (int *)ev[i].data.ptr; 52699ca880aSopenharmony_ci 52799ca880aSopenharmony_ci if (*fd < 0) 52899ca880aSopenharmony_ci continue; 52999ca880aSopenharmony_ci 53099ca880aSopenharmony_ci if (ev[i].events & EPOLLIN) { 53199ca880aSopenharmony_ci ssize_t count; 53299ca880aSopenharmony_ci char buf[4096]; 53399ca880aSopenharmony_ci 53499ca880aSopenharmony_ci count = read(*fd, buf, sizeof(buf)-1); 53599ca880aSopenharmony_ci if (count <= 0) 53699ca880aSopenharmony_ci continue; 53799ca880aSopenharmony_ci buf[count] = '\0'; 53899ca880aSopenharmony_ci 53999ca880aSopenharmony_ci /* store stdout result */ 54099ca880aSopenharmony_ci if (result != NULL && *fd == fd_stdout) { 54199ca880aSopenharmony_ci if (respos + count < ressize) { 54299ca880aSopenharmony_ci memcpy(&result[respos], buf, count); 54399ca880aSopenharmony_ci respos += count; 54499ca880aSopenharmony_ci } else { 54599ca880aSopenharmony_ci log_error("'%s' ressize %zu too short", cmd, ressize); 54699ca880aSopenharmony_ci } 54799ca880aSopenharmony_ci } 54899ca880aSopenharmony_ci 54999ca880aSopenharmony_ci /* log debug output only if we watch stderr */ 55099ca880aSopenharmony_ci if (fd_stderr >= 0) { 55199ca880aSopenharmony_ci char *pos; 55299ca880aSopenharmony_ci char *line; 55399ca880aSopenharmony_ci 55499ca880aSopenharmony_ci pos = buf; 55599ca880aSopenharmony_ci while ((line = strsep(&pos, "\n"))) { 55699ca880aSopenharmony_ci if (pos != NULL || line[0] != '\0') 55799ca880aSopenharmony_ci log_debug("'%s'(%s) '%s'", cmd, *fd == fd_stdout ? "out" : "err" , line); 55899ca880aSopenharmony_ci } 55999ca880aSopenharmony_ci } 56099ca880aSopenharmony_ci } else if (ev[i].events & EPOLLHUP) { 56199ca880aSopenharmony_ci r = epoll_ctl(fd_ep, EPOLL_CTL_DEL, *fd, NULL); 56299ca880aSopenharmony_ci if (r < 0) { 56399ca880aSopenharmony_ci log_error_errno(errno, "failed to remove fd from epoll: %m"); 56499ca880aSopenharmony_ci return; 56599ca880aSopenharmony_ci } 56699ca880aSopenharmony_ci *fd = -1; 56799ca880aSopenharmony_ci } 56899ca880aSopenharmony_ci } 56999ca880aSopenharmony_ci } 57099ca880aSopenharmony_ci 57199ca880aSopenharmony_ci /* return the child's stdout string */ 57299ca880aSopenharmony_ci if (result != NULL) 57399ca880aSopenharmony_ci result[respos] = '\0'; 57499ca880aSopenharmony_ci} 57599ca880aSopenharmony_ci 57699ca880aSopenharmony_cistatic int spawn_wait(struct udev_event *event, 57799ca880aSopenharmony_ci usec_t timeout_usec, 57899ca880aSopenharmony_ci usec_t timeout_warn_usec, 57999ca880aSopenharmony_ci const char *cmd, pid_t pid) { 58099ca880aSopenharmony_ci struct pollfd pfd[1]; 58199ca880aSopenharmony_ci int err = 0; 58299ca880aSopenharmony_ci 58399ca880aSopenharmony_ci pfd[0].events = POLLIN; 58499ca880aSopenharmony_ci pfd[0].fd = event->fd_signal; 58599ca880aSopenharmony_ci 58699ca880aSopenharmony_ci while (pid > 0) { 58799ca880aSopenharmony_ci int timeout; 58899ca880aSopenharmony_ci int timeout_warn = 0; 58999ca880aSopenharmony_ci int fdcount; 59099ca880aSopenharmony_ci 59199ca880aSopenharmony_ci if (timeout_usec > 0) { 59299ca880aSopenharmony_ci usec_t age_usec; 59399ca880aSopenharmony_ci 59499ca880aSopenharmony_ci age_usec = now(CLOCK_MONOTONIC) - event->birth_usec; 59599ca880aSopenharmony_ci if (age_usec >= timeout_usec) 59699ca880aSopenharmony_ci timeout = 1000; 59799ca880aSopenharmony_ci else { 59899ca880aSopenharmony_ci if (timeout_warn_usec > 0) 59999ca880aSopenharmony_ci timeout_warn = ((timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC; 60099ca880aSopenharmony_ci 60199ca880aSopenharmony_ci timeout = ((timeout_usec - timeout_warn_usec - age_usec) / USEC_PER_MSEC) + MSEC_PER_SEC; 60299ca880aSopenharmony_ci } 60399ca880aSopenharmony_ci } else { 60499ca880aSopenharmony_ci timeout = -1; 60599ca880aSopenharmony_ci } 60699ca880aSopenharmony_ci 60799ca880aSopenharmony_ci fdcount = poll(pfd, 1, timeout_warn); 60899ca880aSopenharmony_ci if (fdcount < 0) { 60999ca880aSopenharmony_ci if (errno == EINTR) 61099ca880aSopenharmony_ci continue; 61199ca880aSopenharmony_ci err = -errno; 61299ca880aSopenharmony_ci log_error_errno(errno, "failed to poll: %m"); 61399ca880aSopenharmony_ci goto out; 61499ca880aSopenharmony_ci } 61599ca880aSopenharmony_ci if (fdcount == 0) { 61699ca880aSopenharmony_ci log_warning("slow: '%s' ["PID_FMT"]", cmd, pid); 61799ca880aSopenharmony_ci 61899ca880aSopenharmony_ci fdcount = poll(pfd, 1, timeout); 61999ca880aSopenharmony_ci if (fdcount < 0) { 62099ca880aSopenharmony_ci if (errno == EINTR) 62199ca880aSopenharmony_ci continue; 62299ca880aSopenharmony_ci err = -errno; 62399ca880aSopenharmony_ci log_error_errno(errno, "failed to poll: %m"); 62499ca880aSopenharmony_ci goto out; 62599ca880aSopenharmony_ci } 62699ca880aSopenharmony_ci if (fdcount == 0) { 62799ca880aSopenharmony_ci log_error("timeout: killing '%s' ["PID_FMT"]", cmd, pid); 62899ca880aSopenharmony_ci kill(pid, SIGKILL); 62999ca880aSopenharmony_ci } 63099ca880aSopenharmony_ci } 63199ca880aSopenharmony_ci 63299ca880aSopenharmony_ci if (pfd[0].revents & POLLIN) { 63399ca880aSopenharmony_ci struct signalfd_siginfo fdsi; 63499ca880aSopenharmony_ci int status; 63599ca880aSopenharmony_ci ssize_t size; 63699ca880aSopenharmony_ci 63799ca880aSopenharmony_ci size = read(event->fd_signal, &fdsi, sizeof(struct signalfd_siginfo)); 63899ca880aSopenharmony_ci if (size != sizeof(struct signalfd_siginfo)) 63999ca880aSopenharmony_ci continue; 64099ca880aSopenharmony_ci 64199ca880aSopenharmony_ci switch (fdsi.ssi_signo) { 64299ca880aSopenharmony_ci case SIGTERM: 64399ca880aSopenharmony_ci event->sigterm = true; 64499ca880aSopenharmony_ci break; 64599ca880aSopenharmony_ci case SIGCHLD: 64699ca880aSopenharmony_ci if (waitpid(pid, &status, WNOHANG) < 0) 64799ca880aSopenharmony_ci break; 64899ca880aSopenharmony_ci if (WIFEXITED(status)) { 64999ca880aSopenharmony_ci log_debug("'%s' ["PID_FMT"] exit with return code %i", cmd, pid, WEXITSTATUS(status)); 65099ca880aSopenharmony_ci if (WEXITSTATUS(status) != 0) 65199ca880aSopenharmony_ci err = -1; 65299ca880aSopenharmony_ci } else if (WIFSIGNALED(status)) { 65399ca880aSopenharmony_ci log_error("'%s' ["PID_FMT"] terminated by signal %i (%s)", cmd, pid, WTERMSIG(status), strsignal(WTERMSIG(status))); 65499ca880aSopenharmony_ci err = -1; 65599ca880aSopenharmony_ci } else if (WIFSTOPPED(status)) { 65699ca880aSopenharmony_ci log_error("'%s' ["PID_FMT"] stopped", cmd, pid); 65799ca880aSopenharmony_ci err = -1; 65899ca880aSopenharmony_ci } else if (WIFCONTINUED(status)) { 65999ca880aSopenharmony_ci log_error("'%s' ["PID_FMT"] continued", cmd, pid); 66099ca880aSopenharmony_ci err = -1; 66199ca880aSopenharmony_ci } else { 66299ca880aSopenharmony_ci log_error("'%s' ["PID_FMT"] exit with status 0x%04x", cmd, pid, status); 66399ca880aSopenharmony_ci err = -1; 66499ca880aSopenharmony_ci } 66599ca880aSopenharmony_ci pid = 0; 66699ca880aSopenharmony_ci break; 66799ca880aSopenharmony_ci } 66899ca880aSopenharmony_ci } 66999ca880aSopenharmony_ci } 67099ca880aSopenharmony_ciout: 67199ca880aSopenharmony_ci return err; 67299ca880aSopenharmony_ci} 67399ca880aSopenharmony_ci 67499ca880aSopenharmony_ciint udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]) { 67599ca880aSopenharmony_ci int i = 0; 67699ca880aSopenharmony_ci char *pos; 67799ca880aSopenharmony_ci 67899ca880aSopenharmony_ci if (strchr(cmd, ' ') == NULL) { 67999ca880aSopenharmony_ci argv[i++] = cmd; 68099ca880aSopenharmony_ci goto out; 68199ca880aSopenharmony_ci } 68299ca880aSopenharmony_ci 68399ca880aSopenharmony_ci pos = cmd; 68499ca880aSopenharmony_ci while (pos != NULL && pos[0] != '\0') { 68599ca880aSopenharmony_ci if (pos[0] == '\'') { 68699ca880aSopenharmony_ci /* do not separate quotes */ 68799ca880aSopenharmony_ci pos++; 68899ca880aSopenharmony_ci argv[i] = strsep(&pos, "\'"); 68999ca880aSopenharmony_ci if (pos != NULL) 69099ca880aSopenharmony_ci while (pos[0] == ' ') 69199ca880aSopenharmony_ci pos++; 69299ca880aSopenharmony_ci } else { 69399ca880aSopenharmony_ci argv[i] = strsep(&pos, " "); 69499ca880aSopenharmony_ci if (pos != NULL) 69599ca880aSopenharmony_ci while (pos[0] == ' ') 69699ca880aSopenharmony_ci pos++; 69799ca880aSopenharmony_ci } 69899ca880aSopenharmony_ci i++; 69999ca880aSopenharmony_ci } 70099ca880aSopenharmony_ciout: 70199ca880aSopenharmony_ci argv[i] = NULL; 70299ca880aSopenharmony_ci if (argc) 70399ca880aSopenharmony_ci *argc = i; 70499ca880aSopenharmony_ci return 0; 70599ca880aSopenharmony_ci} 70699ca880aSopenharmony_ci 70799ca880aSopenharmony_ciint udev_event_spawn(struct udev_event *event, 70899ca880aSopenharmony_ci usec_t timeout_usec, 70999ca880aSopenharmony_ci usec_t timeout_warn_usec, 71099ca880aSopenharmony_ci const char *cmd, char **envp, const sigset_t *sigmask, 71199ca880aSopenharmony_ci char *result, size_t ressize) { 71299ca880aSopenharmony_ci int outpipe[2] = {-1, -1}; 71399ca880aSopenharmony_ci int errpipe[2] = {-1, -1}; 71499ca880aSopenharmony_ci pid_t pid; 71599ca880aSopenharmony_ci char arg[UTIL_PATH_SIZE]; 71699ca880aSopenharmony_ci char *argv[128]; 71799ca880aSopenharmony_ci char program[UTIL_PATH_SIZE]; 71899ca880aSopenharmony_ci int err = 0; 71999ca880aSopenharmony_ci 72099ca880aSopenharmony_ci strscpy(arg, sizeof(arg), cmd); 72199ca880aSopenharmony_ci udev_build_argv(event->udev, arg, NULL, argv); 72299ca880aSopenharmony_ci 72399ca880aSopenharmony_ci /* pipes from child to parent */ 72499ca880aSopenharmony_ci if (result != NULL || log_get_max_level() >= LOG_INFO) { 72599ca880aSopenharmony_ci if (pipe2(outpipe, O_NONBLOCK) != 0) { 72699ca880aSopenharmony_ci err = -errno; 72799ca880aSopenharmony_ci log_error_errno(errno, "pipe failed: %m"); 72899ca880aSopenharmony_ci goto out; 72999ca880aSopenharmony_ci } 73099ca880aSopenharmony_ci } 73199ca880aSopenharmony_ci if (log_get_max_level() >= LOG_INFO) { 73299ca880aSopenharmony_ci if (pipe2(errpipe, O_NONBLOCK) != 0) { 73399ca880aSopenharmony_ci err = -errno; 73499ca880aSopenharmony_ci log_error_errno(errno, "pipe failed: %m"); 73599ca880aSopenharmony_ci goto out; 73699ca880aSopenharmony_ci } 73799ca880aSopenharmony_ci } 73899ca880aSopenharmony_ci 73999ca880aSopenharmony_ci /* allow programs in /usr/lib/udev/ to be called without the path */ 74099ca880aSopenharmony_ci if (argv[0][0] != '/') { 74199ca880aSopenharmony_ci strscpyl(program, sizeof(program), UDEV_LIBEXEC_DIR "/", argv[0], NULL); 74299ca880aSopenharmony_ci#ifdef HAVE_SPLIT_USR 74399ca880aSopenharmony_ci if(access(program, X_OK)) 74499ca880aSopenharmony_ci strscpyl(program, sizeof(program), "/usr/lib/udev/", argv[0], NULL); 74599ca880aSopenharmony_ci if(access(program, X_OK)) 74699ca880aSopenharmony_ci strscpyl(program, sizeof(program), "/lib/udev/", argv[0], NULL); 74799ca880aSopenharmony_ci#endif 74899ca880aSopenharmony_ci argv[0] = program; 74999ca880aSopenharmony_ci } 75099ca880aSopenharmony_ci 75199ca880aSopenharmony_ci pid = fork(); 75299ca880aSopenharmony_ci switch(pid) { 75399ca880aSopenharmony_ci case 0: 75499ca880aSopenharmony_ci /* child closes parent's ends of pipes */ 75599ca880aSopenharmony_ci if (outpipe[READ_END] >= 0) { 75699ca880aSopenharmony_ci close(outpipe[READ_END]); 75799ca880aSopenharmony_ci outpipe[READ_END] = -1; 75899ca880aSopenharmony_ci } 75999ca880aSopenharmony_ci if (errpipe[READ_END] >= 0) { 76099ca880aSopenharmony_ci close(errpipe[READ_END]); 76199ca880aSopenharmony_ci errpipe[READ_END] = -1; 76299ca880aSopenharmony_ci } 76399ca880aSopenharmony_ci 76499ca880aSopenharmony_ci log_debug("starting '%s'", cmd); 76599ca880aSopenharmony_ci 76699ca880aSopenharmony_ci spawn_exec(event, cmd, argv, envp, sigmask, 76799ca880aSopenharmony_ci outpipe[WRITE_END], errpipe[WRITE_END]); 76899ca880aSopenharmony_ci 76999ca880aSopenharmony_ci _exit(2 ); 77099ca880aSopenharmony_ci case -1: 77199ca880aSopenharmony_ci log_error_errno(errno, "fork of '%s' failed: %m", cmd); 77299ca880aSopenharmony_ci err = -1; 77399ca880aSopenharmony_ci goto out; 77499ca880aSopenharmony_ci default: 77599ca880aSopenharmony_ci /* parent closed child's ends of pipes */ 77699ca880aSopenharmony_ci if (outpipe[WRITE_END] >= 0) { 77799ca880aSopenharmony_ci close(outpipe[WRITE_END]); 77899ca880aSopenharmony_ci outpipe[WRITE_END] = -1; 77999ca880aSopenharmony_ci } 78099ca880aSopenharmony_ci if (errpipe[WRITE_END] >= 0) { 78199ca880aSopenharmony_ci close(errpipe[WRITE_END]); 78299ca880aSopenharmony_ci errpipe[WRITE_END] = -1; 78399ca880aSopenharmony_ci } 78499ca880aSopenharmony_ci 78599ca880aSopenharmony_ci spawn_read(event, 78699ca880aSopenharmony_ci timeout_usec, 78799ca880aSopenharmony_ci cmd, 78899ca880aSopenharmony_ci outpipe[READ_END], errpipe[READ_END], 78999ca880aSopenharmony_ci result, ressize); 79099ca880aSopenharmony_ci 79199ca880aSopenharmony_ci err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid); 79299ca880aSopenharmony_ci } 79399ca880aSopenharmony_ci 79499ca880aSopenharmony_ciout: 79599ca880aSopenharmony_ci if (outpipe[READ_END] >= 0) 79699ca880aSopenharmony_ci close(outpipe[READ_END]); 79799ca880aSopenharmony_ci if (outpipe[WRITE_END] >= 0) 79899ca880aSopenharmony_ci close(outpipe[WRITE_END]); 79999ca880aSopenharmony_ci if (errpipe[READ_END] >= 0) 80099ca880aSopenharmony_ci close(errpipe[READ_END]); 80199ca880aSopenharmony_ci if (errpipe[WRITE_END] >= 0) 80299ca880aSopenharmony_ci close(errpipe[WRITE_END]); 80399ca880aSopenharmony_ci return err; 80499ca880aSopenharmony_ci} 80599ca880aSopenharmony_ci 80699ca880aSopenharmony_ci#ifdef ENABLE_RULE_GENERATOR 80799ca880aSopenharmony_ci/* function to return the count of rules that assign NAME= to a value matching arg#2 , defined in udev-rules.c */ 80899ca880aSopenharmony_ciint udev_rules_assigning_name_to(struct udev_rules *rules,const char *match_name); 80999ca880aSopenharmony_ci#endif 81099ca880aSopenharmony_ci 81199ca880aSopenharmony_cistatic int rename_netif_dev_fromname_toname(struct udev_device *dev,const char *oldname,const char *name) { 81299ca880aSopenharmony_ci int r; 81399ca880aSopenharmony_ci int sk; 81499ca880aSopenharmony_ci struct ifreq ifr; 81599ca880aSopenharmony_ci 81699ca880aSopenharmony_ci log_debug("changing net interface name from '%s' to '%s'\n",oldname,name); 81799ca880aSopenharmony_ci 81899ca880aSopenharmony_ci sk = socket(PF_INET, SOCK_DGRAM, 0); 81999ca880aSopenharmony_ci if (sk < 0) 82099ca880aSopenharmony_ci return log_error_errno(-errno, "error opening socket: %m"); 82199ca880aSopenharmony_ci 82299ca880aSopenharmony_ci memzero(&ifr, sizeof(struct ifreq)); 82399ca880aSopenharmony_ci strscpy(ifr.ifr_name, IFNAMSIZ, oldname); 82499ca880aSopenharmony_ci strscpy(ifr.ifr_newname, IFNAMSIZ, name); 82599ca880aSopenharmony_ci r = ioctl(sk, SIOCSIFNAME, &ifr); 82699ca880aSopenharmony_ci 82799ca880aSopenharmony_ci#ifdef ENABLE_RULE_GENERATOR 82899ca880aSopenharmony_ci int loop; 82999ca880aSopenharmony_ci 83099ca880aSopenharmony_ci if (r == 0) { 83199ca880aSopenharmony_ci log_info("renamed network interface %s to %s\n", ifr.ifr_name, ifr.ifr_newname); 83299ca880aSopenharmony_ci goto out; 83399ca880aSopenharmony_ci } 83499ca880aSopenharmony_ci /* keep trying if the destination interface name already exists */ 83599ca880aSopenharmony_ci log_debug("collision on rename of network interface %s to %s , retrying until timeout\n", 83699ca880aSopenharmony_ci ifr.ifr_name, ifr.ifr_newname); 83799ca880aSopenharmony_ci 83899ca880aSopenharmony_ci r = -errno; 83999ca880aSopenharmony_ci if (r != -EEXIST) 84099ca880aSopenharmony_ci goto out; 84199ca880aSopenharmony_ci 84299ca880aSopenharmony_ci /* wait a maximum of 90 seconds for our target to become available */ 84399ca880aSopenharmony_ci loop = 90 * 20; 84499ca880aSopenharmony_ci while (loop--) { 84599ca880aSopenharmony_ci const struct timespec duration = { 0, 1000 * 1000 * 1000 / 20 }; 84699ca880aSopenharmony_ci 84799ca880aSopenharmony_ci nanosleep(&duration, NULL); 84899ca880aSopenharmony_ci 84999ca880aSopenharmony_ci r = ioctl(sk, SIOCSIFNAME, &ifr); 85099ca880aSopenharmony_ci if (r == 0) { 85199ca880aSopenharmony_ci log_info("renamed network interface %s to %s\n", ifr.ifr_name, ifr.ifr_newname); 85299ca880aSopenharmony_ci break; 85399ca880aSopenharmony_ci } 85499ca880aSopenharmony_ci r = -errno; 85599ca880aSopenharmony_ci if (r != -EEXIST) 85699ca880aSopenharmony_ci break; 85799ca880aSopenharmony_ci } 85899ca880aSopenharmony_ci 85999ca880aSopenharmony_ciout: 86099ca880aSopenharmony_ci#endif 86199ca880aSopenharmony_ci if (r < 0) 86299ca880aSopenharmony_ci log_error_errno(-errno, "Error changing net interface name %s to %s: %m\n", ifr.ifr_name, ifr.ifr_newname); 86399ca880aSopenharmony_ci else 86499ca880aSopenharmony_ci log_debug("renamed network interface '%s' to '%s'", oldname, name); 86599ca880aSopenharmony_ci 86699ca880aSopenharmony_ci close(sk); 86799ca880aSopenharmony_ci return r; 86899ca880aSopenharmony_ci} 86999ca880aSopenharmony_ci 87099ca880aSopenharmony_cistatic int rename_netif(struct udev_event *event) { 87199ca880aSopenharmony_ci return rename_netif_dev_fromname_toname(event->dev,udev_device_get_sysname(event->dev),event->name); 87299ca880aSopenharmony_ci} 87399ca880aSopenharmony_ci 87499ca880aSopenharmony_civoid udev_event_execute_rules(struct udev_event *event, 87599ca880aSopenharmony_ci usec_t timeout_usec, usec_t timeout_warn_usec, 87699ca880aSopenharmony_ci struct udev_list *properties_list, 87799ca880aSopenharmony_ci struct udev_rules *rules, 87899ca880aSopenharmony_ci const sigset_t *sigmask) { 87999ca880aSopenharmony_ci struct udev_device *dev = event->dev; 88099ca880aSopenharmony_ci 88199ca880aSopenharmony_ci if (udev_device_get_subsystem(dev) == NULL) 88299ca880aSopenharmony_ci return; 88399ca880aSopenharmony_ci 88499ca880aSopenharmony_ci if (streq(udev_device_get_action(dev), "remove")) { 88599ca880aSopenharmony_ci udev_device_read_db(dev); 88699ca880aSopenharmony_ci udev_device_tag_index(dev, NULL, false); 88799ca880aSopenharmony_ci udev_device_delete_db(dev); 88899ca880aSopenharmony_ci 88999ca880aSopenharmony_ci if (major(udev_device_get_devnum(dev)) != 0) 89099ca880aSopenharmony_ci udev_watch_end(event->udev, dev); 89199ca880aSopenharmony_ci 89299ca880aSopenharmony_ci udev_rules_apply_to_event(rules, event, 89399ca880aSopenharmony_ci timeout_usec, timeout_warn_usec, 89499ca880aSopenharmony_ci properties_list, 89599ca880aSopenharmony_ci sigmask); 89699ca880aSopenharmony_ci 89799ca880aSopenharmony_ci if (major(udev_device_get_devnum(dev)) != 0) 89899ca880aSopenharmony_ci udev_node_remove(dev); 89999ca880aSopenharmony_ci } else { 90099ca880aSopenharmony_ci event->dev_db = udev_device_clone_with_db(dev); 90199ca880aSopenharmony_ci if (event->dev_db != NULL) { 90299ca880aSopenharmony_ci /* disable watch during event processing */ 90399ca880aSopenharmony_ci if (major(udev_device_get_devnum(dev)) != 0) 90499ca880aSopenharmony_ci udev_watch_end(event->udev, event->dev_db); 90599ca880aSopenharmony_ci } 90699ca880aSopenharmony_ci 90799ca880aSopenharmony_ci if (major(udev_device_get_devnum(dev)) == 0 && 90899ca880aSopenharmony_ci streq(udev_device_get_action(dev), "move")) 90999ca880aSopenharmony_ci udev_device_copy_properties(dev, event->dev_db); 91099ca880aSopenharmony_ci 91199ca880aSopenharmony_ci udev_rules_apply_to_event(rules, event, 91299ca880aSopenharmony_ci timeout_usec, timeout_warn_usec, 91399ca880aSopenharmony_ci properties_list, 91499ca880aSopenharmony_ci sigmask); 91599ca880aSopenharmony_ci 91699ca880aSopenharmony_ci /* rename a new network interface, if needed */ 91799ca880aSopenharmony_ci 91899ca880aSopenharmony_ci /* ENABLE_RULE_GENERATOR conditional: 91999ca880aSopenharmony_ci * if this is a net iface, and it is an add event, 92099ca880aSopenharmony_ci * and as long as all of the following are FALSE: 92199ca880aSopenharmony_ci * - no NAME target and the current name is not being used 92299ca880aSopenharmony_ci * - there is a NAME target and it is the same as the current name 92399ca880aSopenharmony_ci * - the rules can successfully be searched for the current name (not really part of the conditional) 92499ca880aSopenharmony_ci * the run the rename. 92599ca880aSopenharmony_ci * 92699ca880aSopenharmony_ci * note - udev_rules_assigning_name_to is run when event->name is NULL to ensure renames happen, 92799ca880aSopenharmony_ci * but also on its own to check if a temp-rename is necessary when event->name exists. 92899ca880aSopenharmony_ci * 92999ca880aSopenharmony_ci * A temp-rename is necessary when: 93099ca880aSopenharmony_ci * - there is no rule renaming the current iface but the current name IS used in some other rule 93199ca880aSopenharmony_ci * - there is a rule renaming the current iface, 93299ca880aSopenharmony_ci * the current name IS used AND the target name != the current name 93399ca880aSopenharmony_ci */ 93499ca880aSopenharmony_ci 93599ca880aSopenharmony_ci#ifdef ENABLE_RULE_GENERATOR 93699ca880aSopenharmony_ci int r; 93799ca880aSopenharmony_ci if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") && 93899ca880aSopenharmony_ci (event->name == NULL && (r=udev_rules_assigning_name_to(rules,udev_device_get_sysname(dev))) > 0 || 93999ca880aSopenharmony_ci event->name != NULL && !streq(event->name, udev_device_get_sysname(dev)))) { 94099ca880aSopenharmony_ci char syspath[UTIL_PATH_SIZE]; 94199ca880aSopenharmony_ci char *pos; 94299ca880aSopenharmony_ci char *finalifname = event->name; 94399ca880aSopenharmony_ci char newifname[IFNAMSIZ]; 94499ca880aSopenharmony_ci 94599ca880aSopenharmony_ci /* r is the number of rules that assign a device with NAME= this sysname */ 94699ca880aSopenharmony_ci if (r > 0 || (r=udev_rules_assigning_name_to(rules,udev_device_get_sysname(dev))) > 0) { 94799ca880aSopenharmony_ci /* have a conflict, rename to a temp name */ 94899ca880aSopenharmony_ci char *newpos; 94999ca880aSopenharmony_ci int ifidnum; 95099ca880aSopenharmony_ci 95199ca880aSopenharmony_ci /* build the temporary iface name */ 95299ca880aSopenharmony_ci strscpy(newifname, IFNAMSIZ, udev_device_get_sysname(dev)); 95399ca880aSopenharmony_ci newpos=pos=&newifname[strcspn(newifname,"0123456789")]; 95499ca880aSopenharmony_ci ifidnum=(int)strtol(pos,&newpos,10); 95599ca880aSopenharmony_ci *pos='\0'; 95699ca880aSopenharmony_ci if (newpos > pos && *newpos == '\0') /* append new iface num to name */ 95799ca880aSopenharmony_ci /* use udev_device_get_ifindex(dev) as it is unique to every iface */ 95899ca880aSopenharmony_ci snprintf(pos,IFNAMSIZ+(newifname-pos), "%d", 128 - udev_device_get_ifindex(dev)); 95999ca880aSopenharmony_ci 96099ca880aSopenharmony_ci /* note, r > 0, which will skip the post-rename stuff if no rename occurs */ 96199ca880aSopenharmony_ci 96299ca880aSopenharmony_ci /* if sysname isn't already the tmpname (ie there is no numeric component), do the rename */ 96399ca880aSopenharmony_ci if (!streq(newifname,udev_device_get_sysname(dev))) { 96499ca880aSopenharmony_ci r = rename_netif_dev_fromname_toname(dev,udev_device_get_sysname(dev),newifname); 96599ca880aSopenharmony_ci if (r == 0) { 96699ca880aSopenharmony_ci finalifname = newifname; 96799ca880aSopenharmony_ci log_debug("renamed netif to '%s' for collision avoidance\n", newifname); 96899ca880aSopenharmony_ci } else { 96999ca880aSopenharmony_ci log_error("could not rename netif to '%s' for collision avoidance\n",newifname); 97099ca880aSopenharmony_ci } 97199ca880aSopenharmony_ci } 97299ca880aSopenharmony_ci /* rename it now to its final target if its not already there */ 97399ca880aSopenharmony_ci if (event->name != NULL && !streq(event->name, newifname)) { 97499ca880aSopenharmony_ci r = rename_netif_dev_fromname_toname(dev,newifname,event->name); 97599ca880aSopenharmony_ci if (r == 0) 97699ca880aSopenharmony_ci finalifname = event->name; 97799ca880aSopenharmony_ci } 97899ca880aSopenharmony_ci 97999ca880aSopenharmony_ci } else { /* no need to rename to a tempname first, do a regular direct rename to event->name */ 98099ca880aSopenharmony_ci 98199ca880aSopenharmony_ci r = 1; /* skip the post-rename stuff if no rename occurs */ 98299ca880aSopenharmony_ci if (!streq(event->name, udev_device_get_sysname(dev))) 98399ca880aSopenharmony_ci r = rename_netif(event); 98499ca880aSopenharmony_ci } 98599ca880aSopenharmony_ci 98699ca880aSopenharmony_ci if (r == 0) { 98799ca880aSopenharmony_ci log_debug("renamed netif to '%s'\n", finalifname); 98899ca880aSopenharmony_ci r = udev_device_rename(dev, finalifname); 98999ca880aSopenharmony_ci#else 99099ca880aSopenharmony_ci if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") && 99199ca880aSopenharmony_ci event->name != NULL && !streq(event->name, udev_device_get_sysname(dev))) { 99299ca880aSopenharmony_ci int r; 99399ca880aSopenharmony_ci 99499ca880aSopenharmony_ci r = rename_netif(event); 99599ca880aSopenharmony_ci if (r < 0) 99699ca880aSopenharmony_ci log_warning_errno(r, "could not rename interface '%d' from '%s' to '%s': %m", udev_device_get_ifindex(dev), 99799ca880aSopenharmony_ci udev_device_get_sysname(dev), event->name); 99899ca880aSopenharmony_ci else { 99999ca880aSopenharmony_ci r = udev_device_rename(dev, event->name); 100099ca880aSopenharmony_ci#endif 100199ca880aSopenharmony_ci if (r < 0) 100299ca880aSopenharmony_ci log_warning_errno(r, "renamed interface '%d' from '%s' to '%s', but could not update udev_device: %m", 100399ca880aSopenharmony_ci udev_device_get_ifindex(dev), udev_device_get_sysname(dev), event->name); 100499ca880aSopenharmony_ci else 100599ca880aSopenharmony_ci log_debug("changed devpath to '%s'", udev_device_get_devpath(dev)); 100699ca880aSopenharmony_ci } 100799ca880aSopenharmony_ci } 100899ca880aSopenharmony_ci 100999ca880aSopenharmony_ci if (major(udev_device_get_devnum(dev)) > 0) { 101099ca880aSopenharmony_ci bool apply; 101199ca880aSopenharmony_ci 101299ca880aSopenharmony_ci /* remove/update possible left-over symlinks from old database entry */ 101399ca880aSopenharmony_ci if (event->dev_db != NULL) 101499ca880aSopenharmony_ci udev_node_update_old_links(dev, event->dev_db); 101599ca880aSopenharmony_ci 101699ca880aSopenharmony_ci if (!event->owner_set) 101799ca880aSopenharmony_ci event->uid = udev_device_get_devnode_uid(dev); 101899ca880aSopenharmony_ci 101999ca880aSopenharmony_ci if (!event->group_set) 102099ca880aSopenharmony_ci event->gid = udev_device_get_devnode_gid(dev); 102199ca880aSopenharmony_ci 102299ca880aSopenharmony_ci if (!event->mode_set) { 102399ca880aSopenharmony_ci if (udev_device_get_devnode_mode(dev) > 0) { 102499ca880aSopenharmony_ci /* kernel supplied value */ 102599ca880aSopenharmony_ci event->mode = udev_device_get_devnode_mode(dev); 102699ca880aSopenharmony_ci } else if (event->gid > 0) { 102799ca880aSopenharmony_ci /* default 0660 if a group is assigned */ 102899ca880aSopenharmony_ci event->mode = 0660; 102999ca880aSopenharmony_ci } else { 103099ca880aSopenharmony_ci /* default 0600 */ 103199ca880aSopenharmony_ci event->mode = 0600; 103299ca880aSopenharmony_ci } 103399ca880aSopenharmony_ci } 103499ca880aSopenharmony_ci 103599ca880aSopenharmony_ci apply = streq(udev_device_get_action(dev), "add") || event->owner_set || event->group_set || event->mode_set; 103699ca880aSopenharmony_ci udev_node_add(dev, apply, event->mode, event->uid, event->gid, &event->seclabel_list); 103799ca880aSopenharmony_ci } 103899ca880aSopenharmony_ci 103999ca880aSopenharmony_ci /* preserve old, or get new initialization timestamp */ 104099ca880aSopenharmony_ci udev_device_ensure_usec_initialized(event->dev, event->dev_db); 104199ca880aSopenharmony_ci 104299ca880aSopenharmony_ci /* (re)write database file */ 104399ca880aSopenharmony_ci udev_device_tag_index(dev, event->dev_db, true); 104499ca880aSopenharmony_ci udev_device_update_db(dev); 104599ca880aSopenharmony_ci udev_device_set_is_initialized(dev); 104699ca880aSopenharmony_ci 104799ca880aSopenharmony_ci event->dev_db = udev_device_unref(event->dev_db); 104899ca880aSopenharmony_ci } 104999ca880aSopenharmony_ci} 105099ca880aSopenharmony_ci 105199ca880aSopenharmony_civoid udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, const sigset_t *sigmask) { 105299ca880aSopenharmony_ci struct udev_list_entry *list_entry; 105399ca880aSopenharmony_ci 105499ca880aSopenharmony_ci udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) { 105599ca880aSopenharmony_ci const char *cmd = udev_list_entry_get_name(list_entry); 105699ca880aSopenharmony_ci enum udev_builtin_cmd builtin_cmd = udev_list_entry_get_num(list_entry); 105799ca880aSopenharmony_ci 105899ca880aSopenharmony_ci if (builtin_cmd < UDEV_BUILTIN_MAX) { 105999ca880aSopenharmony_ci char command[UTIL_PATH_SIZE]; 106099ca880aSopenharmony_ci 106199ca880aSopenharmony_ci udev_event_apply_format(event, cmd, command, sizeof(command), false); 106299ca880aSopenharmony_ci udev_builtin_run(event->dev, builtin_cmd, command, false); 106399ca880aSopenharmony_ci } else { 106499ca880aSopenharmony_ci char program[UTIL_PATH_SIZE]; 106599ca880aSopenharmony_ci char **envp; 106699ca880aSopenharmony_ci 106799ca880aSopenharmony_ci if (event->exec_delay > 0) { 106899ca880aSopenharmony_ci log_debug("delay execution of '%s'", program); 106999ca880aSopenharmony_ci sleep(event->exec_delay); 107099ca880aSopenharmony_ci } 107199ca880aSopenharmony_ci 107299ca880aSopenharmony_ci udev_event_apply_format(event, cmd, program, sizeof(program), false); 107399ca880aSopenharmony_ci envp = udev_device_get_properties_envp(event->dev); 107499ca880aSopenharmony_ci udev_event_spawn(event, timeout_usec, timeout_warn_usec, program, envp, sigmask, NULL, 0); 107599ca880aSopenharmony_ci } 107699ca880aSopenharmony_ci } 107799ca880aSopenharmony_ci} 1078