Example #1
0
/*
 * Parse mount options.  See the manual page for usage instructions.
 *
 * Returns the dentry object of the lower-level (lower) directory;
 * We want to mount our stackable file system on top of that lower directory.
 */
static struct unionfs_dentry_info *unionfs_parse_options(
    struct super_block *sb,
    char *options)
{
    struct unionfs_dentry_info *lower_root_info;
    char *optname;
    int err = 0;
    int bindex;
    int dirsfound = 0;

    /* allocate private data area */
    err = -ENOMEM;
    lower_root_info =
        kzalloc(sizeof(struct unionfs_dentry_info), GFP_KERNEL);
    if (unlikely(!lower_root_info))
        goto out_error;
    lower_root_info->bstart = -1;
    lower_root_info->bend = -1;
    lower_root_info->bopaque = -1;

    while ((optname = strsep(&options, ",")) != NULL) {
        char *optarg;

        if (!optname || !*optname)
            continue;

        optarg = strchr(optname, '=');
        if (optarg)
            *optarg++ = '\0';

        /*
         * All of our options take an argument now. Insert ones that
         * don't, above this check.
         */
        if (!optarg) {
            printk(KERN_ERR "unionfs: %s requires an argument\n",
                   optname);
            err = -EINVAL;
            goto out_error;
        }

        if (!strcmp("dirs", optname)) {
            if (++dirsfound > 1) {
                printk(KERN_ERR
                       "unionfs: multiple dirs specified\n");
                err = -EINVAL;
                goto out_error;
            }
            err = parse_dirs_option(sb, lower_root_info, optarg);
            if (err)
                goto out_error;
            continue;
        }

        err = -EINVAL;
        printk(KERN_ERR
               "unionfs: unrecognized option '%s'\n", optname);
        goto out_error;
    }
    if (dirsfound != 1) {
        printk(KERN_ERR "unionfs: dirs option required\n");
        err = -EINVAL;
        goto out_error;
    }
    goto out;

out_error:
    if (lower_root_info && lower_root_info->lower_paths) {
        for (bindex = lower_root_info->bstart;
                bindex >= 0 && bindex <= lower_root_info->bend;
                bindex++) {
            struct dentry *d;
            struct vfsmount *m;

            d = lower_root_info->lower_paths[bindex].dentry;
            m = lower_root_info->lower_paths[bindex].mnt;

            dput(d);
            /* initializing: can't use unionfs_mntput here */
            mntput(m);
        }
    }

    kfree(lower_root_info->lower_paths);
    kfree(lower_root_info);

    kfree(UNIONFS_SB(sb)->data);
    UNIONFS_SB(sb)->data = NULL;

    lower_root_info = ERR_PTR(err);
out:
    return lower_root_info;
}
Example #2
0
/*
 * Parse mount options.  See the manual page for usage instructions.
 *
 * Returns the dentry object of the lower-level (hidden) directory;
 * We want to mount our stackable file system on top of that hidden directory.
 *
 * Sets default debugging level to N, if any.
 */
static struct unionfs_dentry_info *unionfs_parse_options(struct super_block *sb,
							 char *options)
{
	struct unionfs_dentry_info *hidden_root_info;
	char *optname;
	int err = 0;
	int bindex;
	int dirsfound = 0;
#ifdef UNIONFS_IMAP
	int imapfound = 0;
#endif
	print_entry_location();

	/* allocate private data area */
	err = -ENOMEM;
	hidden_root_info =
	    KZALLOC(sizeof(struct unionfs_dentry_info), GFP_KERNEL);
	if (!hidden_root_info)
		goto out_error;
	hidden_root_info->udi_bstart = -1;
	hidden_root_info->udi_bend = -1;
	hidden_root_info->udi_bopaque = -1;

	while ((optname = strsep(&options, ",")) != NULL) {
		char *optarg;
		char *endptr;
		int intval;

		if (!*optname) {
			continue;
		}

		optarg = strchr(optname, '=');
		if (optarg) {
			*optarg++ = '\0';
		}

		/* All of our options take an argument now. Insert ones that
		 * don't, above this check.  */
		if (!optarg) {
			printk("unionfs: %s requires an argument.\n", optname);
			err = -EINVAL;
			goto out_error;
		}

		if (!strcmp("dirs", optname)) {
			if (++dirsfound > 1) {
				printk(KERN_WARNING
				       "unionfs: multiple dirs specified\n");
				err = -EINVAL;
				goto out_error;
			}
			err = parse_dirs_option(sb, hidden_root_info, optarg);
			if (err)
				goto out_error;
			continue;
		}
#ifdef UNIONFS_IMAP
		if (!strcmp("imap", optname)) {
			if (++imapfound > 1) {
				printk(KERN_WARNING
				       "unionfs: multiple imap specified\n");
				err = -EINVAL;
				goto out_error;
			}
			err = parse_imap_option(sb, hidden_root_info, optarg);
			if (err)
				goto out_error;
			continue;
		}
#endif
		if (!strcmp("delete", optname)) {
			if (!strcmp("whiteout", optarg)) {
				/* default */
#ifdef UNIONFS_DELETE_ALL
			} else if (!strcmp("all", optarg)) {
				MOUNT_FLAG(sb) |= DELETE_ALL;
#endif
			} else {
				printk(KERN_WARNING
				       "unionfs: invalid delete option '%s'\n",
				       optarg);
				err = -EINVAL;
				goto out_error;
			}
			continue;
		}
		if (!strcmp("copyup", optname)) {
			if (!strcmp("preserve", optarg)) {
				/* default */
			} else if (!strcmp("currentuser", optarg)) {
				MOUNT_FLAG(sb) |= COPYUP_CURRENT_USER;
			} else {
				printk(KERN_WARNING
				       "unionfs: could not parse copyup option value '%s'\n",
				       optarg);
				err = -EINVAL;
				goto out_error;
			}
			continue;
		}

		/* All of these options require an integer argument. */
		intval = simple_strtoul(optarg, &endptr, 0);
		if (*endptr) {
			printk(KERN_WARNING
			       "unionfs: invalid %s option '%s'\n",
			       optname, optarg);
			err = -EINVAL;
			goto out_error;
		}

		if (!strcmp("debug", optname)) {
			fist_set_debug_value(intval);
			continue;
		}

		err = -EINVAL;
		printk(KERN_WARNING
		       "unionfs: unrecognized option '%s'\n", optname);
		goto out_error;
	}
	if (dirsfound != 1) {
		printk(KERN_WARNING "unionfs: dirs option required\n");
		err = -EINVAL;
		goto out_error;
	}
	goto out;

      out_error:
	if (hidden_root_info && hidden_root_info->udi_dentry) {
		for (bindex = hidden_root_info->udi_bstart;
		     bindex >= 0 && bindex <= hidden_root_info->udi_bend;
		     bindex++) {
			struct dentry *d;
			d = hidden_root_info->udi_dentry[bindex];
			DPUT(d);
			if (stohiddenmnt_index(sb, bindex))
				mntput(stohiddenmnt_index(sb, bindex));
		}
	}

	KFREE(hidden_root_info->udi_dentry);
	KFREE(hidden_root_info);

	KFREE(stopd(sb)->usi_data);
	stopd(sb)->usi_data = NULL;

	hidden_root_info = ERR_PTR(err);
      out:
	print_exit_location();
	return hidden_root_info;
}