Beispiel #1
0
static void test_loop_scan(int flags, int debug)
{
	struct loopdev_cxt lc;
	int rc;

	loopcxt_init(&lc, 0);
	loopcxt_enable_debug(&lc, debug);

	if (loopcxt_init_iterator(&lc, flags))
		err(EXIT_FAILURE, "iterator initlization failed");

	while((rc = loopcxt_next(&lc)) == 0) {
		const char *device = loopcxt_get_device(&lc);

		if (flags & LOOPITER_FL_USED) {
			char *backing = loopcxt_get_backing_file(&lc);
			printf("\t%s: %s\n", device, backing);
			free(backing);
		} else
			printf("\t%s\n", device);
	}

	if (rc < 0)
		err(EXIT_FAILURE, "loopdevs scanning failed");

	loopcxt_deinit(&lc);
}
Beispiel #2
0
static void test_loop_info(const char *device, int flags, int debug)
{
	struct loopdev_cxt lc;
	char *p;
	uint64_t u64;

	loopcxt_init(&lc, flags);
	loopcxt_enable_debug(&lc, debug);

	if (loopcxt_set_device(&lc, device))
		err(EXIT_FAILURE, "failed to set device");

	p = loopcxt_get_backing_file(&lc);
	printf("\tBACKING FILE: %s\n", p);
	free(p);

	if (loopcxt_get_offset(&lc, &u64) == 0)
		printf("\tOFFSET: %jd\n", u64);

	if (loopcxt_get_sizelimit(&lc, &u64) == 0)
		printf("\tSIZE LIMIT: %jd\n", u64);

	printf("\tAUTOCLEAR: %s\n", loopcxt_is_autoclear(&lc) ? "YES" : "NOT");

	loopcxt_deinit(&lc);
}
Beispiel #3
0
static int test_loop_setup(const char *filename, const char *device, int debug)
{
	struct loopdev_cxt lc;
	int rc = 0;

	loopcxt_init(&lc, 0);
	loopcxt_enable_debug(&lc, debug);

	if (device) {
		rc = loopcxt_set_device(&lc, device);
		if (rc)
			err(EXIT_FAILURE, "failed to set device: %s", device);
	}

	do {
		if (!device) {
			rc = loopcxt_find_unused(&lc);
			if (rc)
				err(EXIT_FAILURE, "failed to find unused device");
			printf("Trying to use '%s'\n", loopcxt_get_device(&lc));
		}

		if (loopcxt_set_backing_file(&lc, filename))
			err(EXIT_FAILURE, "failed to set backing file");

		rc = loopcxt_setup_device(&lc);
		if (rc == 0)
			break;		/* success */

		if (device || rc != -EBUSY)
			err(EXIT_FAILURE, "failed to setup device for %s",
					lc.filename);

		printf("device stolen...trying again\n");
	} while (1);

	loopcxt_deinit(&lc);

	return 0;
}
Beispiel #4
0
int main(int argc, char **argv)
{
	struct loopdev_cxt lc;
	int act = 0, flags = 0, passfd = -1, c;
	char *file = NULL, *encryption = NULL;
	uint64_t offset = 0, sizelimit = 0;
	int res = 0, showdev = 0, lo_flags = 0;

	enum {
		OPT_SIZELIMIT = CHAR_MAX + 1,
		OPT_SHOW
	};
	static const struct option longopts[] = {
		{ "all", 0, 0, 'a' },
		{ "set-capacity", 1, 0, 'c' },
		{ "detach", 1, 0, 'd' },
		{ "detach-all", 0, 0, 'D' },
		{ "encryption", 1, 0, 'e' },
		{ "find", 0, 0, 'f' },
		{ "help", 0, 0, 'h' },
		{ "associated", 1, 0, 'j' },
		{ "offset", 1, 0, 'o' },
		{ "sizelimit", 1, 0, OPT_SIZELIMIT },
		{ "pass-fd", 1, 0, 'p' },
		{ "partscan", 0, 0, 'P' },
		{ "read-only", 0, 0, 'r' },
	        { "show", 0, 0, OPT_SHOW },
		{ "verbose", 0, 0, 'v' },
		{ "version", 0, 0, 'V' },
		{ NULL, 0, 0, 0 }
	};

	setlocale(LC_ALL, "");
	bindtextdomain(PACKAGE, LOCALEDIR);
	textdomain(PACKAGE);
	atexit(close_stdout);

	loopcxt_init(&lc, 0);
	loopcxt_enable_debug(&lc, getenv("LOOPDEV_DEBUG") ? TRUE : FALSE);

	while ((c = getopt_long(argc, argv, "ac:d:De:E:fhj:o:p:PrvV",
				longopts, NULL)) != -1) {

		if (act && strchr("acdDfj", c))
			errx(EXIT_FAILURE,
				_("the options %s are mutually exclusive"),
				"--{all,associated,set-capacity,detach,detach-all,find}");

		switch (c) {
		case 'a':
			act = A_SHOW;
			break;
		case 'c':
			act = A_SET_CAPACITY;
			loopcxt_set_device(&lc, optarg);
			break;
		case 'r':
			lo_flags |= LO_FLAGS_READ_ONLY;
			break;
		case 'd':
			act = A_DELETE;
			loopcxt_set_device(&lc, optarg);
			break;
		case 'D':
			act = A_DELETE_ALL;
			break;
		case 'E':
		case 'e':
			encryption = optarg;
			break;
		case 'f':
			act = A_FIND_FREE;
			break;
		case 'h':
			usage(stdout);
			break;
		case 'j':
			act = A_SHOW;
			file = optarg;
			break;
		case 'o':
			offset = strtosize_or_err(optarg, _("failed to parse offset"));
			flags |= LOOPDEV_FL_OFFSET;
			break;
		case 'p':
			passfd = strtou32_or_err(optarg,
					_("invalid passphrase file descriptor"));
			break;
		case 'P':
			lo_flags |= LO_FLAGS_PARTSCAN;
			break;
		case OPT_SHOW:
			showdev = 1;
			break;
		case 'v':
			verbose = 1;
			break;
		case 'V':
			printf(UTIL_LINUX_VERSION);
			return EXIT_SUCCESS;
		case OPT_SIZELIMIT:			/* --sizelimit */
			sizelimit = strtosize_or_err(optarg, _("failed to parse size"));
			flags |= LOOPDEV_FL_SIZELIMIT;
                        break;
		default:
			usage(stderr);
		}
	}

	if (argc == 1)
		usage(stderr);

	if (act == A_FIND_FREE && optind < argc) {
		/*
		 * losetup -f <backing_file>
		 */
		act = A_CREATE;
		file = argv[optind++];
	}
	if (!act && optind + 1 == argc) {
		/*
		 * losetup <device>
		 */
		act = A_SHOW_ONE;
		loopcxt_set_device(&lc, argv[optind++]);
	}
	if (!act) {
		/*
		 * losetup <loopdev> <backing_file>
		 */
		act = A_CREATE;

		if (optind >= argc)
			errx(EXIT_FAILURE, _("no loop device specified"));
		loopcxt_set_device(&lc, argv[optind++]);

		if (optind >= argc)
			errx(EXIT_FAILURE, _("no file specified"));
		file = argv[optind++];
	}

	if (act != A_CREATE &&
	    (encryption || sizelimit || passfd != -1 || lo_flags || showdev))
		errx(EXIT_FAILURE,
			_("the options %s are allowed to loop device setup only"),
			"--{encryption,sizelimit,pass-fd,read-only,show}");

	if ((flags & LOOPDEV_FL_OFFSET) &&
	    act != A_CREATE && (act != A_SHOW || !file))
		errx(EXIT_FAILURE, _("the option --offset is not allowed in this context."));

	switch (act) {
	case A_CREATE:
	{
		char *pass = NULL;
		int hasdev = loopcxt_has_device(&lc);

		if (encryption) {
#ifdef MCL_FUTURE
			if(mlockall(MCL_CURRENT | MCL_FUTURE))
				err(EXIT_FAILURE, _("couldn't lock into memory"));
#endif
			pass = xgetpass(passfd, _("Password: "******"not found unused device"));
				break;
			}
			if (encryption && pass)
				loopcxt_set_encryption(&lc, encryption, pass);
			if (flags & LOOPDEV_FL_OFFSET)
				loopcxt_set_offset(&lc, offset);
			if (flags & LOOPDEV_FL_SIZELIMIT)
				loopcxt_set_sizelimit(&lc, sizelimit);
			if (lo_flags)
				loopcxt_set_flags(&lc, lo_flags);
			if ((res = loopcxt_set_backing_file(&lc, file))) {
				warn(_("%s: failed to use backing file"), file);
				break;
			}
			errno = 0;
			res = loopcxt_setup_device(&lc);
			if (res == 0)
				break;			/* success */
			if (errno != EBUSY) {
				warn(_("%s: failed to setup loop device"),
					hasdev && loopcxt_get_fd(&lc) < 0 ?
					    loopcxt_get_device(&lc) : file);
				break;
			}
		} while (hasdev == 0);

		free(pass);

		if (showdev && res == 0)
			printf("%s\n", loopcxt_get_device(&lc));
		break;
	}
	case A_DELETE:
		res = delete_loop(&lc);
		while (optind < argc) {
			loopcxt_set_device(&lc, argv[optind++]);
			res += delete_loop(&lc);
		}
		break;
	case A_DELETE_ALL:
		res = delete_all_loops(&lc);
		break;
	case A_FIND_FREE:
		if (loopcxt_find_unused(&lc))
			warn(_("find unused loop device failed"));
		else
			printf("%s\n", loopcxt_get_device(&lc));
		break;
	case A_SHOW:
		res = show_all_loops(&lc, file, offset, flags);
		break;
	case A_SHOW_ONE:
		res = printf_loopdev(&lc);
		if (res)
			warn(_("%s"), loopcxt_get_device(&lc));
		break;
	case A_SET_CAPACITY:
		res = set_capacity(&lc);
		break;
	default:
		usage(stderr);
		break;
	}

	loopcxt_deinit(&lc);
	return res ? EXIT_FAILURE : EXIT_SUCCESS;
}
Beispiel #5
0
int mnt_context_setup_loopdev(struct libmnt_context *cxt)
{
	const char *backing_file, *optstr, *loopdev = NULL;
	char *val = NULL;
	size_t len;
	struct loopdev_cxt lc;
	int rc = 0, lo_flags = 0;
	uint64_t offset = 0, sizelimit = 0;

	assert(cxt->fs);
	assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));

	if (!cxt)
		return -EINVAL;

	backing_file = mnt_fs_get_srcpath(cxt->fs);
	if (!backing_file)
		return -EINVAL;

	DBG(CXT, ul_debugobj(cxt, "trying to setup loopdev for %s", backing_file));

	if (cxt->mountflags & MS_RDONLY) {
		DBG(CXT, ul_debugobj(cxt, "enabling READ-ONLY flag"));
		lo_flags |= LO_FLAGS_READ_ONLY;
	}

	rc = loopcxt_init(&lc, 0);
	if (rc)
		return rc;

	ON_DBG(CXT, loopcxt_enable_debug(&lc, 1));

	optstr = mnt_fs_get_user_options(cxt->fs);

	/*
	 * loop=
	 */
	if (rc == 0 && (cxt->user_mountflags & MNT_MS_LOOP) &&
	    mnt_optstr_get_option(optstr, "loop", &val, &len) == 0 && val) {

		val = strndup(val, len);
		rc = val ? loopcxt_set_device(&lc, val) : -ENOMEM;
		free(val);

		if (rc == 0)
			loopdev = loopcxt_get_device(&lc);
	}

	/*
	 * offset=
	 */
	if (rc == 0 && (cxt->user_mountflags & MNT_MS_OFFSET) &&
	    mnt_optstr_get_option(optstr, "offset", &val, &len) == 0) {
		rc = mnt_parse_offset(val, len, &offset);
		if (rc) {
			DBG(CXT, ul_debugobj(cxt, "failed to parse offset="));
			rc = -MNT_ERR_MOUNTOPT;
		}
	}

	/*
	 * sizelimit=
	 */
	if (rc == 0 && (cxt->user_mountflags & MNT_MS_SIZELIMIT) &&
	    mnt_optstr_get_option(optstr, "sizelimit", &val, &len) == 0) {
		rc = mnt_parse_offset(val, len, &sizelimit);
		if (rc) {
			DBG(CXT, ul_debugobj(cxt, "failed to parse sizelimit="));
			rc = -MNT_ERR_MOUNTOPT;
		}
	}

	/*
	 * encryption=
	 */
	if (rc == 0 && (cxt->user_mountflags & MNT_MS_ENCRYPTION) &&
	    mnt_optstr_get_option(optstr, "encryption", &val, &len) == 0) {
		DBG(CXT, ul_debugobj(cxt, "encryption no longer supported"));
		rc = -MNT_ERR_MOUNTOPT;
	}

	if (rc == 0 && is_mounted_same_loopfile(cxt,
				mnt_context_get_target(cxt),
				backing_file, offset))
		rc = -EBUSY;

	if (rc)
		goto done;

	/* since 2.6.37 we don't have to store backing filename to mtab
	 * because kernel provides the name in /sys.
	 */
	if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
	    !mnt_context_mtab_writable(cxt)) {
		DBG(CXT, ul_debugobj(cxt, "enabling AUTOCLEAR flag"));
		lo_flags |= LO_FLAGS_AUTOCLEAR;
	}

	do {
		/* found free device */
		if (!loopdev) {
			rc = loopcxt_find_unused(&lc);
			if (rc)
				goto done;
			DBG(CXT, ul_debugobj(cxt, "trying to use %s",
						loopcxt_get_device(&lc)));
		}

		/* set device attributes
		 * -- note that loopcxt_find_unused() resets "lc"
		 */
		rc = loopcxt_set_backing_file(&lc, backing_file);

		if (!rc && offset)
			rc = loopcxt_set_offset(&lc, offset);
		if (!rc && sizelimit)
			rc = loopcxt_set_sizelimit(&lc, sizelimit);
		if (!rc)
			loopcxt_set_flags(&lc, lo_flags);
		if (rc) {
			DBG(CXT, ul_debugobj(cxt, "failed to set loopdev attributes"));
			goto done;
		}

		/* setup the device */
		rc = loopcxt_setup_device(&lc);
		if (!rc)
			break;		/* success */

		if (loopdev || rc != -EBUSY) {
			DBG(CXT, ul_debugobj(cxt, "failed to setup device"));
			rc = -MNT_ERR_LOOPDEV;
			goto done;
		}
		DBG(CXT, ul_debugobj(cxt, "loopdev stolen...trying again"));
	} while (1);

	if (!rc)
		rc = mnt_fs_set_source(cxt->fs, loopcxt_get_device(&lc));

	if (!rc) {
		/* success */
		cxt->flags |= MNT_FL_LOOPDEV_READY;

		if ((cxt->user_mountflags & MNT_MS_LOOP) &&
		    loopcxt_is_autoclear(&lc)) {
			/*
			 * autoclear flag accepted by the kernel, don't store
			 * the "loop=" option to mtab.
			 */
			cxt->user_mountflags &= ~MNT_MS_LOOP;
			mnt_optstr_remove_option(&cxt->fs->user_optstr, "loop");
		}

		if (!(cxt->mountflags & MS_RDONLY) &&
		    loopcxt_is_readonly(&lc))
			/*
			 * mount planned read-write, but loopdev is read-only,
			 * let's fix mount options...
			 */
			mnt_context_set_mflags(cxt, cxt->mountflags | MS_RDONLY);

		/* we have to keep the device open until mount(1),
		 * otherwise it will be auto-cleared by kernel
		 */
		cxt->loopdev_fd = loopcxt_get_fd(&lc);
		loopcxt_set_fd(&lc, -1, 0);
	}
done:
	loopcxt_deinit(&lc);
	return rc;
}