示例#1
0
文件: udev-node.c 项目: sylware/mudev
/* 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);
                util_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;

                info(udev, "found '%s' claiming '%s'\n", dent->d_name, stackdir);

                /* did we find ourself? */
                if (strcmp(dent->d_name, udev_device_get_id_filename(dev)) == 0)
                        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) {
                                dbg(udev, "compare priority of '%s'(%i) > '%s'(%i)\n", target, priority,
                                    udev_device_get_devnode(dev_db), udev_device_get_devlink_priority(dev_db));
                                if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) {
                                        info(udev, "'%s' claims priority %i for '%s'\n",
                                             udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir);
                                        priority = udev_device_get_devlink_priority(dev_db);
                                        util_strscpy(buf, bufsize, devnode);
                                        target = buf;
                                }
                        }
                        udev_device_unref(dev_db);
                }
        }
        closedir(dir);
        return target;
}
示例#2
0
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;
                }
        }
        util_strscpy(to, len, type);
}
示例#3
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 2:
                        type = "atapi";
                        break;
                case 3:
                        type = "tape";
                        break;
                case 4: /* UFI */
                case 5: /* SFF-8070i */
                        type = "floppy";
                        break;
                case 1: /* RBC devices */
                        type = "rbc";
                        break;
                case 6: /* Transparent SPC-2 devices */
                        type = "scsi";
                        break;
                default:
                        break;
                }
        }
        util_strscpy(to, len, type);
        return type_num;
}
int util_delete_path(struct udev *udev, const char *path)
{
        char p[UTIL_PATH_SIZE];
        char *pos;
        int err = 0;

        if (path[0] == '/')
                while(path[1] == '/')
                        path++;
        util_strscpy(p, sizeof(p), path);
        pos = strrchr(p, '/');
        if (pos == p || pos == NULL)
                return 0;

        for (;;) {
                *pos = '\0';
                pos = strrchr(p, '/');

                /* don't remove the last one */
                if ((pos == p) || (pos == NULL))
                        break;

                err = rmdir(p);
                if (err < 0) {
                        if (errno == ENOENT)
                                err = 0;
                        break;
                }
        }
        return err;
}
示例#5
0
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];

        optind = 0;
        util_strscpy(arg, sizeof(arg), command);
        udev_build_argv(udev_device_get_udev(dev), arg, &argc, argv);
        return builtins[cmd]->cmd(dev, argc, argv, test);
}
示例#6
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;

        usbdev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
        if (!usbdev)
                return -ENOENT;

        /* get USB port number chain, configuration, interface */
        util_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 = util_strpcpyl(&s, sizeof(names->usb_ports), "u", ports, NULL);

        /* append USB config number, suppress the common config == 1 */
        if (!streq(config, "1"))
                l = util_strpcpyl(&s, sizeof(names->usb_ports), "c", config, NULL);

        /* append USB interface number, suppress the interface == 0 */
        if (!streq(interf, "0"))
                l = util_strpcpyl(&s, sizeof(names->usb_ports), "i", interf, NULL);
        if (l == 0)
                return -ENAMETOOLONG;

        names->type = NET_USB;
        return 0;
}
示例#7
0
enum udev_builtin_cmd udev_builtin_lookup(const char *command)
{
        char name[UTIL_PATH_SIZE];
        enum udev_builtin_cmd i;
        char *pos;

        util_strscpy(name, sizeof(name), command);
        pos = strchr(name, ' ');
        if (pos)
                pos[0] = '\0';
        for (i = 0; i < ELEMENTSOF(builtins); i++)
                if (strcmp(builtins[i]->name, name) == 0)
                        return i;
        return UDEV_BUILTIN_MAX;
}
static int create_path(struct udev *udev, const char *path, bool selinux)
{
        char p[UTIL_PATH_SIZE];
        char *pos;
        struct stat stats;
        int err;

        util_strscpy(p, sizeof(p), path);
        pos = strrchr(p, '/');
        if (pos == NULL)
                return 0;
        while (pos != p && pos[-1] == '/')
                pos--;
        if (pos == p)
                return 0;
        pos[0] = '\0';

        dbg(udev, "stat '%s'\n", p);
        if (stat(p, &stats) == 0) {
                if ((stats.st_mode & S_IFMT) == S_IFDIR)
                        return 0;
                else
                        return -ENOTDIR;
        }

        err = util_create_path(udev, p);
        if (err != 0)
                return err;

        dbg(udev, "mkdir '%s'\n", p);
        if (selinux)
                udev_selinux_setfscreatecon(udev, p, S_IFDIR|0755);
        err = mkdir(p, 0755);
        if (err != 0) {
                err = -errno;
                if (err == -EEXIST && stat(p, &stats) == 0) {
                        if ((stats.st_mode & S_IFMT) == S_IFDIR)
                                err = 0;
                        else
                                err = -ENOTDIR;
                }
        }
        if (selinux)
                udev_selinux_resetfscreatecon(udev);
        return err;
}
示例#9
0
/**
 * udev_monitor_new_from_socket:
 * @udev: udev library context
 * @socket_path: unix socket path
 *
 * This function should not be used in any new application. The
 * kernel's netlink socket multiplexes messages to all interested
 * clients. Creating custom sockets from udev to applications
 * should be avoided.
 *
 * Create a new udev monitor and connect to a specified socket. The
 * path to a socket either points to an existing socket file, or if
 * the socket path starts with a '@' character, an abstract namespace
 * socket will be used.
 *
 * A socket file will not be created. If it does not already exist,
 * it will fall-back and connect to an abstract namespace socket with
 * the given path. The permissions adjustment of a socket file, as
 * well as the later cleanup, needs to be done by the caller.
 *
 * The initial refcount is 1, and needs to be decremented to
 * release the resources of the udev monitor.
 *
 * Returns: a new udev monitor, or #NULL, in case of an error
 **/
UDEV_EXPORT struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path)
{
        struct udev_monitor *udev_monitor;
        struct stat statbuf;

        if (udev == NULL)
                return NULL;
        if (socket_path == NULL)
                return NULL;
        udev_monitor = udev_monitor_new(udev);
        if (udev_monitor == NULL)
                return NULL;

        udev_monitor->sun.sun_family = AF_LOCAL;
        if (socket_path[0] == '@') {
                /* translate leading '@' to abstract namespace */
                util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
                udev_monitor->sun.sun_path[0] = '\0';
                udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
        } else if (stat(socket_path, &statbuf) == 0 && S_ISSOCK(statbuf.st_mode)) {
示例#10
0
static int builtin_btrfs(struct udev_device *dev, int argc, char *argv[], bool test)
{
        struct  btrfs_ioctl_vol_args args;
        int fd;
        int err;

        if (argc != 3 || !streq(argv[1], "ready"))
                return EXIT_FAILURE;

        fd = open("/dev/btrfs-control", O_RDWR);
        if (fd < 0)
                return EXIT_FAILURE;

        util_strscpy(args.name, sizeof(args.name), argv[2]);
        err = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args);
        close(fd);
        if (err < 0)
                return EXIT_FAILURE;

        udev_builtin_add_property(dev, test, "ID_BTRFS_READY", err == 0 ? "1" : "0");
        return EXIT_SUCCESS;
}
示例#11
0
文件: udev-node.c 项目: sylware/mudev
static int node_symlink(struct udev *udev, 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 + sizeof(TMP_FILE_EXT)];
        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 = util_strpcpy(&s, l, "../");
                i++;
        }
        l = util_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)) {
                        struct stat stats2;

                        info(udev, "found existing node instead of symlink '%s'\n", slink);
                        if (lstat(node, &stats2) == 0) {
                                if ((stats.st_mode & S_IFMT) == (stats2.st_mode & S_IFMT) &&
                                    stats.st_rdev == stats2.st_rdev && stats.st_ino != stats2.st_ino) {
                                        info(udev, "replace device node '%s' with symlink to our node '%s'\n",
                                             slink, node);
                                } else {
                                        err(udev, "device node '%s' already exists, "
                                            "link to '%s' will not overwrite it\n",
                                            slink, node);
                                        goto exit;
                                }
                        }
                } else if (S_ISLNK(stats.st_mode)) {
                        char buf[UTIL_PATH_SIZE];
                        int len;

                        dbg(udev, "found existing symlink '%s'\n", slink);
                        len = readlink(slink, buf, sizeof(buf));
                        if (len > 0 && len < (int)sizeof(buf)) {
                                buf[len] = '\0';
                                if (strcmp(target, buf) == 0) {
                                        info(udev, "preserve already existing symlink '%s' to '%s'\n",
                                             slink, target);
                                        udev_selinux_lsetfilecon(udev, slink, S_IFLNK);
                                        utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
                                        goto exit;
                                }
                        }
                }
        } else {
                info(udev, "creating symlink '%s' to '%s'\n", slink, target);
                do {
                        err = util_create_path_selinux(udev, slink);
                        if (err != 0 && err != -ENOENT)
                                break;
                        udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
                        err = symlink(target, slink);
                        if (err != 0)
                                err = -errno;
                        udev_selinux_resetfscreatecon(udev);
                } while (err == -ENOENT);
                if (err == 0)
                        goto exit;
        }

        info(udev, "atomically replace '%s'\n", slink);
        util_strscpyl(slink_tmp, sizeof(slink_tmp), slink, TMP_FILE_EXT, NULL);
        unlink(slink_tmp);
        do {
                err = util_create_path_selinux(udev, slink_tmp);
                if (err != 0 && err != -ENOENT)
                        break;
                udev_selinux_setfscreatecon(udev, slink_tmp, S_IFLNK);
                err = symlink(target, slink_tmp);
                if (err != 0)
                        err = -errno;
                udev_selinux_resetfscreatecon(udev);
        } while (err == -ENOENT);
        if (err != 0) {
                err(udev, "symlink '%s' '%s' failed: %m\n", target, slink_tmp);
                goto exit;
        }
        err = rename(slink_tmp, slink);
        if (err != 0) {
                err(udev, "rename '%s' '%s' failed: %m\n", slink_tmp, slink);
                unlink(slink_tmp);
        }
exit:
        return err;
}
示例#12
0
/* 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);
		util_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;
		char devpath[UTIL_PATH_SIZE];
		char syspath[UTIL_PATH_SIZE];
		ssize_t len;

		dent = readdir(dir);
		if (dent == NULL || dent->d_name[0] == '\0')
			break;
		if (dent->d_name[0] == '.')
			continue;
		dbg(udev, "found '%s/%s'\n", stackdir, dent->d_name);
		len = readlinkat(dirfd(dir), dent->d_name, devpath, sizeof(devpath));
		if (len <= 0 || len == (ssize_t)sizeof(devpath))
			continue;
		devpath[len] = '\0';
		util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), devpath, NULL);
		info(udev, "found '%s' claiming '%s'\n", syspath, stackdir);

		/* did we find ourself? */
		if (strcmp(udev_device_get_syspath(dev), syspath) == 0)
			continue;

		dev_db = udev_device_new_from_syspath(udev, syspath);
		if (dev_db != NULL) {
			const char *devnode;

			devnode = udev_device_get_devnode(dev_db);
			if (devnode != NULL) {
				dbg(udev, "compare priority of '%s'(%i) > '%s'(%i)\n", target, priority,
				    udev_device_get_devnode(dev_db), udev_device_get_devlink_priority(dev_db));
				if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) {
					info(udev, "'%s' claims priority %i for '%s'\n",
					     syspath, udev_device_get_devlink_priority(dev_db), stackdir);
					priority = udev_device_get_devlink_priority(dev_db);
					util_strscpy(buf, bufsize, devnode);
					target = buf;
				}
			}
			udev_device_unref(dev_db);
		}
	}
	closedir(dir);
	return target;
}
示例#13
0
文件: scsi_id.c 项目: adsr/systemd
static int set_options(struct udev *udev,
                       int argc, char **argv, const char *short_opts,
                       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 (1) {
                option = getopt_long(argc, argv, short_opts, options, NULL);
                if (option == -1)
                        break;

                switch (option) {
                case 'b':
                        all_good = 0;
                        break;

                case 'd':
                        dev_specified = 1;
                        util_strscpy(maj_min_dev, MAX_PATH_LEN, optarg);
                        break;

                case 'e':
                        use_stderr = 1;
                        break;

                case 'f':
                        util_strscpy(config_file, MAX_PATH_LEN, optarg);
                        break;

                case 'g':
                        all_good = 1;
                        break;

                case 'h':
                        printf("Usage: scsi_id OPTIONS <device>\n"
                               "  --device=                     device node for SG_IO commands\n"
                               "  --config=                     location of config file\n"
                               "  --page=0x80|0x83|pre-spc3-83  SCSI page (0x80, 0x83, pre-spc3-83)\n"
                               "  --sg-version=3|4              use SGv3 or SGv4\n"
                               "  --blacklisted                 threat device as blacklisted\n"
                               "  --whitelisted                 threat device as whitelisted\n"
                               "  --replace-whitespace          replace all whitespaces by underscores\n"
                               "  --verbose                     verbose logging\n"
                               "  --version                     print version\n"
                               "  --export                      print values as environment keys\n"
                               "  --help                        print this help text\n\n");
                        exit(0);

                case 'p':
                        if (strcmp(optarg, "0x80") == 0) {
                                default_page_code = PAGE_80;
                        } else if (strcmp(optarg, "0x83") == 0) {
                                default_page_code = PAGE_83;
                        } else if (strcmp(optarg, "pre-spc3-83") == 0) {
                                default_page_code = PAGE_83_PRE_SPC3;
                        } else {
                                log_error("Unknown page code '%s'\n", optarg);
                                return -1;
                        }
                        break;

                case 's':
                        sg_version = atoi(optarg);
                        if (sg_version < 3 || sg_version > 4) {
                                log_error("Unknown SG version '%s'\n", optarg);
                                return -1;
                        }
                        break;

                case 'u':
                        reformat_serial = 1;
                        break;

                case 'x':
                        export = 1;
                        break;

                case 'v':
                        debug++;
                        break;

                case 'V':
                        printf("%s\n", VERSION);
                        exit(0);
                        break;

                default:
                        exit(1);
                }
        }
        if (optind < argc && !dev_specified) {
                dev_specified = 1;
                util_strscpy(maj_min_dev, MAX_PATH_LEN, argv[optind]);
        }
        return 0;
}
示例#14
0
int main(int argc, char *argv[])
{
	struct udev *udev;
	static const struct option options[] = {
		{ "export", no_argument, NULL, 'x' },
		{ "debug", no_argument, NULL, 'd' },
		{ "help", no_argument, NULL, 'h' },
		{}
	};
	char **devices;
	FILE *fp;
	struct mntent *mnt;
	int rc = 1;

	udev = udev_new();
	if (udev == NULL)
		goto exit;

	udev_log_init("fstab_id");
	udev_set_log_fn(udev, log_fn);

	while (1) {
		int option;

		option = getopt_long(argc, argv, "dxh", options, NULL);
		if (option == -1)
			break;

		switch (option) {
		case 'd':
			debug = 1;
			if (udev_get_log_priority(udev) < LOG_INFO)
				udev_set_log_priority(udev, LOG_INFO);
			break;
		case 'h':
			printf("Usage: fstab_id [OPTIONS] name [...]\n"
			       "  --export        print environment keys\n"
			       "  --debug         debug to stderr\n"
			       "  --help          print this help text\n\n");
			goto exit;
		case 'x':
			break;
		default:
			rc = 2;
			goto exit;
		}
	}

	devices = &argv[optind];
	if (devices[0] == NULL) {
		fprintf(stderr, "error: missing device(s) to match\n");
		rc = 3;
		goto exit;
	}

	fp = setmntent ("/etc/fstab", "r");
	if (fp == NULL) {
		fprintf(stderr, "error: opening fstab: %s\n", strerror(errno));
		rc = 4;
		goto exit;
	}

	while (1) {
		mnt = getmntent(fp);
		if (mnt == NULL)
			break;

		info(udev, "found '%s'@'%s'\n", mnt->mnt_fsname, mnt->mnt_dir);

		/* skip root device */
		if (strcmp(mnt->mnt_dir, "/") == 0)
			continue;

		/* match LABEL */
		if (strncmp(mnt->mnt_fsname, "LABEL=", 6) == 0) {
			const char *label;
			char str[256];

			label = &mnt->mnt_fsname[6];
			if (label[0] == '"' || label[0] == '\'') {
				char *pos;

				util_strscpy(str, sizeof(str), &label[1]);
				pos = strrchr(str, label[0]);
				if (pos == NULL)
					continue;
				pos[0] = '\0';
				label = str;
			}
			if (matches_device_list(udev, devices, label)) {
				print_fstab_entry(udev, mnt);
				rc = 0;
				break;
			}
			continue;
		}

		/* match UUID */
		if (strncmp(mnt->mnt_fsname, "UUID=", 5) == 0) {
			const char *uuid;
			char str[256];

			uuid = &mnt->mnt_fsname[5];
			if (uuid[0] == '"' || uuid[0] == '\'') {
				char *pos;

				util_strscpy(str, sizeof(str), &uuid[1]);
				pos = strrchr(str, uuid[0]);
				if (pos == NULL)
					continue;
				pos[0] = '\0';
				uuid = str;
			}
			if (matches_device_list(udev, devices, uuid)) {
				print_fstab_entry(udev, mnt);
				rc = 0;
				break;
			}
			continue;
		}

		/* only devices */
		if (strncmp(mnt->mnt_fsname, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
			continue;

		if (matches_device_list(udev, devices, &mnt->mnt_fsname[strlen(udev_get_dev_path(udev))+1])) {
			print_fstab_entry(udev, mnt);
			rc = 0;
			break;
		}
	}
	endmntent(fp);

exit:
	udev_unref(udev);
	udev_log_close();
	return rc;
}
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;

	dbg(udev, "version %s\n", VERSION);

	for (;;) {
		int option;

		option = getopt_long(argc, argv, "h", options, NULL);
		if (option == -1)
			break;

		switch (option) {
		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\n");
		rc = 3;
		goto out;
	}

	/* add /sys if needed */
	if (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
		util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), syspath, NULL);
	else
		util_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;
	}

	cmd = udev_builtin_lookup(command);
	if (cmd >= UDEV_BUILTIN_MAX) {
		fprintf(stderr, "unknown command '%s'\n", command);
		help(udev);
		rc = 5;
		goto out;
	}

	if (udev_builtin_run(dev, cmd, true) < 0) {
		fprintf(stderr, "error executing '%s'\n\n", command);
		rc = 6;
	}
out:
	udev_device_unref(dev);
	return rc;
}
示例#16
0
/* handle "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */
int util_resolve_subsys_kernel(struct udev *udev, const char *string,
                               char *result, size_t maxsize, int read_value)
{
        char temp[UTIL_PATH_SIZE];
        char *subsys;
        char *sysname;
        struct udev_device *dev;
        char *attr;

        if (string[0] != '[')
                return -1;

        util_strscpy(temp, sizeof(temp), string);

        subsys = &temp[1];

        sysname = strchr(subsys, '/');
        if (sysname == NULL)
                return -1;
        sysname[0] = '\0';
        sysname = &sysname[1];

        attr = strchr(sysname, ']');
        if (attr == NULL)
                return -1;
        attr[0] = '\0';
        attr = &attr[1];
        if (attr[0] == '/')
                attr = &attr[1];
        if (attr[0] == '\0')
                attr = NULL;

        if (read_value && attr == NULL)
                return -1;

        dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname);
        if (dev == NULL)
                return -1;

        if (read_value) {
                const char *val;

                val = udev_device_get_sysattr_value(dev, attr);
                if (val != NULL)
                        util_strscpy(result, maxsize, val);
                else
                        result[0] = '\0';
                info(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
        } else {
                size_t l;
                char *s;

                s = result;
                l = util_strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL);
                if (attr != NULL)
                        util_strpcpyl(&s, l, "/", attr, NULL);
                info(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
        }
        udev_device_unref(dev);
        return 0;
}
示例#17
0
文件: udev-node.c 项目: adsr/systemd
static int node_symlink(struct udev *udev, 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 + sizeof(TMP_FILE_EXT)];
        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 = util_strpcpy(&s, l, "../");
                i++;
        }
        l = util_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\n", 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 (strcmp(target, buf) == 0) {
                                        log_debug("preserve already existing symlink '%s' to '%s'\n", 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'\n", slink, target);
                do {
                        err = mkdir_parents_label(slink, 0755);
                        if (err != 0 && err != -ENOENT)
                                break;
                        label_context_set(slink, S_IFLNK);
                        err = symlink(target, slink);
                        if (err != 0)
                                err = -errno;
                        label_context_clear();
                } while (err == -ENOENT);
                if (err == 0)
                        goto exit;
        }

        log_debug("atomically replace '%s'\n", slink);
        util_strscpyl(slink_tmp, sizeof(slink_tmp), slink, TMP_FILE_EXT, NULL);
        unlink(slink_tmp);
        do {
                err = mkdir_parents_label(slink_tmp, 0755);
                if (err != 0 && err != -ENOENT)
                        break;
                label_context_set(slink_tmp, S_IFLNK);
                err = symlink(target, slink_tmp);
                if (err != 0)
                        err = -errno;
                label_context_clear();
        } while (err == -ENOENT);
        if (err != 0) {
                log_error("symlink '%s' '%s' failed: %m\n", target, slink_tmp);
                goto exit;
        }
        err = rename(slink_tmp, slink);
        if (err != 0) {
                log_error("rename '%s' '%s' failed: %m\n", slink_tmp, slink);
                unlink(slink_tmp);
        }
exit:
        return err;
}