#include <sys/ioctl.h>
#include "parser.h"
+#include "paths.h"
#include "petitboot-paths.h"
/* Define below to operate without the frontend */
#endif
}
-struct device_map {
- char *dev, *mnt;
-};
+static int mkdir_recursive(const char *dir)
+{
+ char *str, *sep;
+ int mode = 0755;
+ struct stat statbuf;
-#define DEVICE_MAP_SIZE 32
-static struct device_map device_map[DEVICE_MAP_SIZE];
+ pb_log("mkdir_recursive(%s)\n", dir);
-const char *mountpoint_for_device(const char *dev_path)
-{
- int i;
- const char *basename;
-
- /* shorten '/dev/foo' to 'foo' */
- basename = strrchr(dev_path, '/');
- if (basename)
- basename++;
- else
- basename = dev_path;
-
- /* check existing entries in the map */
- for (i = 0; (i < DEVICE_MAP_SIZE) && device_map[i].dev; i++)
- if (!strcmp(device_map[i].dev, basename))
- return device_map[i].mnt;
-
- if (i == DEVICE_MAP_SIZE)
- return NULL;
-
- device_map[i].dev = strdup(dev_path);
- asprintf(&device_map[i].mnt, "%s/%s", TMP_DIR, basename);
- return device_map[i].mnt;
+ if (!*dir)
+ return 0;
+
+ if (!stat(dir, &statbuf)) {
+ if (!S_ISDIR(statbuf.st_mode)) {
+ pb_log("%s: %s exists, but isn't a directory\n",
+ __func__, dir);
+ return -1;
+ }
+ return 0;
+ }
+
+ str = strdup(dir);
+ sep = strchr(*str == '/' ? str + 1 : str, '/');
+
+ while (1) {
+
+ /* terminate the path at sep */
+ if (sep)
+ *sep = '\0';
+ pb_log("mkdir(%s)\n", str);
+
+ if (mkdir(str, mode) && errno != EEXIST) {
+ pb_log("mkdir(%s): %s\n", str, strerror(errno));
+ return -1;
+ }
+
+ if (!sep)
+ break;
+
+ /* reset dir to the full path */
+ strcpy(str, dir);
+ sep = strchr(sep + 1, '/');
+ }
+
+ free(str);
+
+ return 0;
}
-/**
- * Resolve a path given in a config file, to a path in the local filesystem.
- * Paths may be of the form:
- * device:path (eg /dev/sda:/boot/vmlinux)
- *
- * or just a path:
- * /boot/vmlinux
- * - in this case, the default mountpoint is used.
- *
- * Returns a newly-allocated string containing a full path to the file in path
- */
-char *resolve_path(const char *path, const char *default_mountpoint)
+static void setup_device_links(const char *device)
{
- char *ret;
- const char *devpath, *sep;
+ struct link {
+ char *env, *dir;
+ } *link, links[] = {
+ {
+ .env = "ID_FS_UUID",
+ .dir = "disk/by-uuid"
+ },
+ {
+ .env = "ID_FS_LABEL",
+ .dir = "disk/by-label"
+ },
+ {
+ .env = NULL
+ }
+ };
- sep = strchr(path, ':');
- if (!sep) {
- devpath = default_mountpoint;
- asprintf(&ret, "%s/%s", devpath, path);
- } else {
- /* copy just the device name into tmp */
- char *dev = strndup(path, sep - path);
- devpath = mountpoint_for_device(dev);
- asprintf(&ret, "%s/%s", devpath, sep + 1);
- free(dev);
- }
+ for (link = links; link->env; link++) {
+ char *value, *dir, *path;
- return ret;
+ value = getenv(link->env);
+ if (!value)
+ continue;
+
+ value = encode_label(value);
+ dir = join_paths(TMP_DIR, link->dir);
+ path = join_paths(dir, value);
+
+ if (!mkdir_recursive(dir)) {
+ unlink(path);
+ if (symlink(mountpoint_for_device(device), path)) {
+ pb_log("symlink(%s): %s\n",
+ path, strerror(errno));
+ }
+ }
+
+ free(path);
+ free(dir);
+ free(value);
+ }
}
int mount_device(const char *dev_path)
goto out;
}
- if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ setup_device_links(dev_path);
rc = 0;
+ }
out:
return rc;
/* Polling loop for optical drive */
for (; (*optical) != 0; ) {
- pb_log("poll for optical drive insertion ...\n");
fd = open(dev_path, O_RDONLY|O_NONBLOCK);
if (fd < 0)
return EXIT_FAILURE;
rc = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
close(fd);
- if (rc == -1) {
- pb_log("not an optical drive, fallback...\n");
+ if (rc == -1)
break;
- }
+
*optical = 1;
if (rc == CDS_DISC_OK)
return EXIT_SUCCESS;
- pb_log("no... waiting\n");
detach_and_sleep(REMOVABLE_SLEEP_DELAY);
}
/* Fall back to bare open() */
*optical = 0;
for (;;) {
- pb_log("poll for non-optical drive insertion ...\n");
fd = open(dev_path, O_RDONLY);
if (fd < 0 && errno != ENOMEDIUM)
return EXIT_FAILURE;
close(fd);
if (fd >= 0)
return EXIT_SUCCESS;
- pb_log("no... waiting\n");
detach_and_sleep(REMOVABLE_SLEEP_DELAY);
}
}
int rc, fd;
for (;optical;) {
- pb_log("poll for optical drive removal ...\n");
fd = open(dev_path, O_RDONLY|O_NONBLOCK);
if (fd < 0)
return EXIT_FAILURE;
close(fd);
if (rc != CDS_DISC_OK)
return EXIT_SUCCESS;
- pb_log("no... waiting\n");
detach_and_sleep(REMOVABLE_SLEEP_DELAY);
}
/* Fall back to bare open() */
for (;;) {
- pb_log("poll for non-optical drive removal ...\n");
fd = open(dev_path, O_RDONLY);
if (fd < 0 && errno != ENOMEDIUM)
return EXIT_FAILURE;
close(fd);
if (fd < 0)
return EXIT_SUCCESS;
- pb_log("no... waiting\n");
detach_and_sleep(REMOVABLE_SLEEP_DELAY);
}
}
return EXIT_FAILURE;
}
+ set_mount_base(TMP_DIR);
+
if (connect_to_socket())
return EXIT_FAILURE;