Ejemplo n.º 1
0
/*
 * 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;
}
Ejemplo n.º 2
0
/*
 * 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;
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
0
/**
 * 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;
}
Ejemplo n.º 5
0
/*
 * 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;
}
Ejemplo n.º 6
0
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;
}