/* * Note that the @target has to be an absolute path (so at least "/"). The * @filename returns an allocated buffer with the last path component, for example: * * mnt_chdir_to_parent("/mnt/test", &buf) ==> chdir("/mnt"), buf="test" */ int mnt_chdir_to_parent(const char *target, char **filename) { char *buf, *parent, *last = NULL; char cwd[PATH_MAX]; int rc = -EINVAL; if (!target || *target != '/') return -EINVAL; DBG(UTILS, ul_debug("moving to %s parent", target)); buf = strdup(target); if (!buf) return -ENOMEM; if (*(buf + 1) != '\0') { last = stripoff_last_component(buf); if (!last) goto err; } parent = buf && *buf ? buf : "/"; if (chdir(parent) == -1) { DBG(UTILS, ul_debug("failed to chdir to %s: %m", parent)); rc = -errno; goto err; } if (!getcwd(cwd, sizeof(cwd))) { DBG(UTILS, ul_debug("failed to obtain current directory: %m")); rc = -errno; goto err; } if (strcmp(cwd, parent) != 0) { DBG(UTILS, ul_debug( "unexpected chdir (expected=%s, cwd=%s)", parent, cwd)); goto err; } DBG(CXT, ul_debug( "current directory moved to %s [last_component='%s']", parent, last)); if (filename) { *filename = buf; if (!last || !*last) memcpy(*filename, ".", 2); else memmove(*filename, last, strlen(last) + 1); } else free(buf); return 0; err: free(buf); return rc; }
/* * Don't export this to libmount API -- utab is private library stuff. * * If the file does not exist and @writable argument is not NULL then it will * try to create the directory (e.g. /run/mount) and the file. * * Returns: 1 if utab is a regular file, and 0 in case of * error (check errno for more details). */ int mnt_has_regular_utab(const char **utab, int *writable) { struct stat st; int rc; const char *filename = utab && *utab ? *utab : mnt_get_utab_path(); if (writable) *writable = 0; if (utab && !*utab) *utab = filename; DBG(UTILS, mnt_debug("utab: %s", filename)); rc = lstat(filename, &st); if (rc == 0) { /* file exist */ if (S_ISREG(st.st_mode)) { if (writable) *writable = !try_write(filename); return 1; } goto done; /* it's not regular file */ } if (writable) { char *dirname = strdup(filename); if (!dirname) goto done; stripoff_last_component(dirname); /* remove filename */ rc = mkdir(dirname, S_IWUSR| S_IRUSR|S_IRGRP|S_IROTH| S_IXUSR|S_IXGRP|S_IXOTH); free(dirname); if (rc && errno != EEXIST) goto done; /* probably EACCES */ *writable = !try_write(filename); if (*writable) return 1; } done: DBG(UTILS, mnt_debug("%s: irregular/non-writable file", filename)); return 0; }
/** * mnt_get_mountpoint: * @path: pathname * * This function finds the mountpoint that a given path resides in. @path * should be canonicalized. The returned pointer should be freed by the caller. * * WARNING: the function compares st_dev of the @path elements. This traditional * way maybe be insufficient on filesystems like Linux "overlay". See also * mnt_table_find_target(). * * Returns: allocated string with the target of the mounted device or NULL on error */ char *mnt_get_mountpoint(const char *path) { char *mnt; struct stat st; dev_t dir, base; if (!path) return NULL; mnt = strdup(path); if (!mnt) return NULL; if (*mnt == '/' && *(mnt + 1) == '\0') goto done; if (stat(mnt, &st)) goto err; base = st.st_dev; do { char *p = stripoff_last_component(mnt); if (!p) break; if (stat(*mnt ? mnt : "/", &st)) goto err; dir = st.st_dev; if (dir != base) { if (p > mnt) *(p - 1) = '/'; goto done; } base = dir; } while (mnt && *(mnt + 1) != '\0'); memcpy(mnt, "/", 2); done: DBG(UTILS, ul_debug("%s mountpoint is %s", path, mnt)); return mnt; err: free(mnt); return NULL; }
/** * blkid_devno_to_wholedisk: * @dev: device number * @diskname: buffer to return diskname (or NULL) * @len: diskname buffer size (or 0) * @diskdevno: pointer to returns devno of entire disk (or NULL) * * This function uses sysfs to convert the @devno device number to the *name* * of the whole disk. The function DOES NOT return full device name. The @dev * argument could be partition or whole disk -- both is converted. * * For example: sda1, 0x0801 --> sda, 0x0800 * * For conversion to the full disk *path* use blkid_devno_to_devname(), for * example: * * <informalexample> * <programlisting> * * dev_t dev = 0x0801, disk; // sda1 = 8:1 * char *diskpath, diskname[32]; * * blkid_devno_to_wholedisk(dev, diskname, sizeof(diskname), &disk); * diskpath = blkid_devno_to_devname(disk); * * // print "0x0801: sda, /dev/sda, 8:0 * printf("0x%x: %s, %s, %d:%d\n", * dev, diskname, diskpath, major(disk), minor(disk)); * * free(diskpath); * * </programlisting> * </informalexample> * * Returns: 0 on success or -1 in case of error. */ int blkid_devno_to_wholedisk(dev_t dev, char *diskname, size_t len, dev_t *diskdevno) { char path[PATH_MAX]; char linkpath[PATH_MAX]; struct stat info; char *name; int rc, linklen; if (!dev) goto err; /* check if dev is a partition */ rc = snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/partition", major(dev), minor(dev)); if (rc < 0 || rc + 1 > sizeof(path)) goto err; rc = stat(path, &info); /* 'rc == 0' means partitioned dev */ /* aka dirname (remove "/partition" from the path*/ stripoff_last_component(path); /* * Unpartitioned device: * - readlink /sys/dev/block/8:0 = ../../block/sda * - basename ../../block/sda = sda * * Partitioned device: * - readlink /sys/dev/block/8:1 = ../../block/sda/sda1 * - dirname ../../block/sda/sda1 = ../../block/sda * - basename ../../block/sda = sda */ linklen = readlink(path, linkpath, sizeof(linkpath) - 1); if (linklen < 0) goto err; linkpath[linklen] = '\0'; if (rc == 0) /* partitioned device */ stripoff_last_component(linkpath); /* dirname */ name = stripoff_last_component(linkpath); /* basename */ if (!name) goto err; if (diskname && len) { strncpy(diskname, name, len); diskname[len - 1] = '\0'; } if (diskdevno) { int maj, min; FILE *f; /* read wholedisk devno */ rc = snprintf(path, sizeof(path), "/sys/block/%s/dev", name); if (rc < 0 || rc + 1 > sizeof(path)) goto err; f = fopen(path, "r"); if (!f) goto err; rc = fscanf(f, "%d:%d", &maj, &min); fclose(f); if (rc != 2) goto err; *diskdevno = makedev(maj, min); } DBG(DEBUG_DEVNO, printf("found entire diskname for devno 0x%04llx as %s\n", (long long) dev, name)); return 0; err: DBG(DEBUG_DEVNO, printf("failed to convert 0x%04llx to wholedisk name, errno=%d\n", (long long) dev, errno)); return -1; }
/* * Returns by @diskdevno whole disk device devno and (optionaly) by * @diskname the whole disk device name. */ int sysfs_devno_to_wholedisk(dev_t dev, char *diskname, size_t len, dev_t *diskdevno) { struct sysfs_cxt cxt; int is_part = 0; if (!dev || sysfs_init(&cxt, dev, NULL) != 0) return -1; is_part = sysfs_has_attribute(&cxt, "partition"); if (!is_part) { /* * Extra case for partitions mapped by device-mapper. * * All regualar partitions (added by BLKPG ioctl or kernel PT * parser) have the /sys/.../partition file. The partitions * mapped by DM don't have such file, but they have "part" * prefix in DM UUID. */ char *uuid = sysfs_strdup(&cxt, "dm/uuid"); char *tmp = uuid; char *prefix = uuid ? strsep(&tmp, "-") : NULL; if (prefix && strncasecmp(prefix, "part", 4) == 0) is_part = 1; free(uuid); if (is_part && get_dm_wholedisk(&cxt, diskname, len, diskdevno) == 0) /* * partitioned device, mapped by DM */ goto done; is_part = 0; } if (!is_part) { /* * unpartitioned device */ if (diskname && len) { if (!sysfs_get_devname(&cxt, diskname, len)) goto err; } if (diskdevno) *diskdevno = dev; } else { /* * partitioned device * - readlink /sys/dev/block/8:1 = ../../block/sda/sda1 * - dirname ../../block/sda/sda1 = ../../block/sda * - basename ../../block/sda = sda */ char linkpath[PATH_MAX]; char *name; int linklen; linklen = sysfs_readlink(&cxt, NULL, linkpath, sizeof(linkpath) - 1); if (linklen < 0) goto err; linkpath[linklen] = '\0'; stripoff_last_component(linkpath); /* dirname */ name = stripoff_last_component(linkpath); /* basename */ if (!name) goto err; if (diskname && len) { strncpy(diskname, name, len); diskname[len - 1] = '\0'; } if (diskdevno) { *diskdevno = sysfs_devname_to_devno(name, NULL); if (!*diskdevno) goto err; } } done: sysfs_deinit(&cxt); return 0; err: sysfs_deinit(&cxt); return -1; }
static void lock_disk(struct fsck_instance *inst) { dev_t disk = fs_get_disk(inst->fs, 1); char *diskpath = NULL, *diskname; inst->lock = -1; if (!disk || is_irrotational_disk(disk)) goto done; diskpath = blkid_devno_to_devname(disk); if (!diskpath) goto done; if (access(FSCK_RUNTIME_DIRNAME, F_OK) != 0) { int rc = mkdir(FSCK_RUNTIME_DIRNAME, S_IWUSR| S_IRUSR|S_IRGRP|S_IROTH| S_IXUSR|S_IXGRP|S_IXOTH); if (rc && errno != EEXIST) { warn(_("cannot create directory %s"), FSCK_RUNTIME_DIRNAME); goto done; } } diskname = stripoff_last_component(diskpath); if (!diskname) diskname = diskpath; xasprintf(&inst->lockpath, FSCK_RUNTIME_DIRNAME "/%s.lock", diskname); if (verbose) printf(_("Locking disk by %s ... "), inst->lockpath); inst->lock = open(inst->lockpath, O_RDONLY|O_CREAT|O_CLOEXEC, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH); if (inst->lock >= 0) { int rc = -1; /* inform users that we're waiting on the lock */ if (verbose && (rc = flock(inst->lock, LOCK_EX | LOCK_NB)) != 0 && errno == EWOULDBLOCK) printf(_("(waiting) ")); if (rc != 0 && flock(inst->lock, LOCK_EX) != 0) { close(inst->lock); /* failed */ inst->lock = -1; } } if (verbose) /* TRANSLATORS: These are followups to "Locking disk...". */ printf("%s.\n", inst->lock >= 0 ? _("succeeded") : _("failed")); done: if (inst->lock < 0) { free(inst->lockpath); inst->lockpath = NULL; } free(diskpath); return; }