+
+ return 0;
+}
+
+static int import_file_into_env(struct udevice *udev, const char *filename)
+{
+ char *buf;
+ size_t bufsize;
+
+ if (file_map(filename, &buf, &bufsize) != 0) {
+ err("can't open '%s': %s\n", filename, strerror(errno));
+ return -1;
+ }
+ import_keys_into_env(udev, buf, bufsize);
+ file_unmap(buf, bufsize);
+
+ return 0;
+}
+
+static int import_program_into_env(struct udevice *udev, const char *program)
+{
+ char result[2048];
+ size_t reslen;
+
+ if (run_program(program, udev->dev->subsystem, result, sizeof(result), &reslen) != 0)
+ return -1;
+ return import_keys_into_env(udev, result, reslen);
+}
+
+static int import_parent_into_env(struct udevice *udev, const char *filter)
+{
+ struct sysfs_device *dev_parent;
+ int rc = -1;
+
+ dev_parent = sysfs_device_get_parent(udev->dev);
+ if (dev_parent != NULL) {
+ struct udevice *udev_parent;
+ struct name_entry *name_loop;
+
+ dbg("found parent '%s', get the node name\n", dev_parent->devpath);
+ udev_parent = udev_device_init(NULL);
+ if (udev_parent == NULL)
+ return -1;
+ /* import the udev_db of the parent */
+ if (udev_db_get_device(udev_parent, dev_parent->devpath) == 0) {
+ dbg("import stored parent env '%s'\n", udev_parent->name);
+ list_for_each_entry(name_loop, &udev_parent->env_list, node) {
+ char name[NAME_SIZE];
+ char *pos;
+
+ strlcpy(name, name_loop->name, sizeof(name));
+ pos = strchr(name, '=');
+ if (pos) {
+ pos[0] = '\0';
+ pos++;
+ if (fnmatch(filter, name, 0) == 0) {
+ dbg("import key '%s'\n", name_loop->name);
+ name_list_add(&udev->env_list, name_loop->name, 0);
+ setenv(name, pos, 1);
+ } else
+ dbg("skip key '%s'\n", name_loop->name);
+ }
+ }
+ rc = 0;
+ } else
+ dbg("parent not found in database\n");
+ udev_device_cleanup(udev_parent);
+ }
+
+ return rc;
+}
+
+static int pass_env_to_socket(const char *sockpath, const char *devpath, const char *action)
+{
+ int sock;
+ struct sockaddr_un saddr;
+ socklen_t saddrlen;
+ struct stat stats;
+ char buf[2048];
+ size_t bufpos = 0;
+ int i;
+ ssize_t count;
+ int retval = 0;
+
+ dbg("pass environment to socket '%s'\n", sockpath);
+ sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ memset(&saddr, 0x00, sizeof(struct sockaddr_un));
+ saddr.sun_family = AF_LOCAL;
+ if (sockpath[0] == '@') {
+ /* abstract namespace socket requested */
+ strlcpy(&saddr.sun_path[1], &sockpath[1], sizeof(saddr.sun_path)-1);
+ saddrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]);
+ } else if (stat(sockpath, &stats) == 0 && S_ISSOCK(stats.st_mode)) {
+ /* existing socket file */
+ strlcpy(saddr.sun_path, sockpath, sizeof(saddr.sun_path));
+ saddrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path);
+ } else {
+ /* no socket file, assume abstract namespace socket */
+ strlcpy(&saddr.sun_path[1], sockpath, sizeof(saddr.sun_path)-1);
+ saddrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]);
+ }
+
+ bufpos = snprintf(buf, sizeof(buf)-1, "%s@%s", action, devpath);
+ bufpos++;
+ for (i = 0; environ[i] != NULL && bufpos < (sizeof(buf)-1); i++) {
+ bufpos += strlcpy(&buf[bufpos], environ[i], sizeof(buf) - bufpos-1);
+ bufpos++;
+ }
+ if (bufpos > sizeof(buf))
+ bufpos = sizeof(buf);
+
+ count = sendto(sock, &buf, bufpos, 0, (struct sockaddr *)&saddr, saddrlen);
+ if (count < 0)
+ retval = -1;
+ info("passed %zi bytes to socket '%s', \n", count, sockpath);
+
+ close(sock);
+ return retval;
+}
+
+int udev_rules_run(struct udevice *udev)
+{
+ struct name_entry *name_loop;
+ int retval = 0;
+
+ dbg("executing run list\n");
+ list_for_each_entry(name_loop, &udev->run_list, node) {
+ if (strncmp(name_loop->name, "socket:", strlen("socket:")) == 0) {
+ pass_env_to_socket(&name_loop->name[strlen("socket:")], udev->dev->devpath, udev->action);
+ } else {
+ char program[PATH_SIZE];
+
+ strlcpy(program, name_loop->name, sizeof(program));
+ udev_rules_apply_format(udev, program, sizeof(program));
+ if (run_program(program, udev->dev->subsystem, NULL, 0, NULL) != 0)
+ if (!name_loop->ignore_error)
+ retval = -1;
+ }