You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

201 lines
4.5 KiB

/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <string>
static const char *progname;
static std::string shell_quote(const std::string &s)
{
std::string r = "'";
for (char c : s) {
if (c == '\'')
r += "'\\''";
else
r += c;
}
r += "'";
return r;
}
static std::string add_option(const std::string &opt,
const std::string &options)
{
if (options.empty())
return opt;
return options + "," + opt;
}
int main(int argc, char *argv[])
{
std::string type;
std::string source;
std::string mountpoint;
std::string basename;
std::string options;
std::string command;
std::string setuid;
int dev = 1;
int suid = 1;
progname = argv[0];
{
const char *slash = strrchr(argv[0], '/');
basename = slash ? (slash + 1) : argv[0];
}
type = "mergerfs";
if (strncmp(basename.c_str(), "mount.fuse.", 11) == 0)
type = basename.substr(11);
if (strncmp(basename.c_str(), "mount.fuseblk.", 14) == 0)
type = basename.substr(14);
if (type.empty())
type = "";
if (argc < 3) {
fprintf(stderr,
"usage: %s %s destination [-t type] [-o opt[,opts...]]\n",
progname, type.empty() ? "type#[source]" : "source");
exit(1);
}
source = argv[1];
mountpoint = argv[2];
for (int i = 3; i < argc; i++) {
if (strcmp(argv[i], "-v") == 0) {
continue;
} else if (strcmp(argv[i], "-t") == 0) {
i++;
if (i == argc) {
fprintf(stderr,
"%s: missing argument to option '-t'\n",
progname);
exit(1);
}
type = argv[i];
if (strncmp(type.c_str(), "fuse.", 5) == 0)
type = type.substr(5);
else if (strncmp(type.c_str(), "fuseblk.", 8) == 0)
type = type.substr(8);
if (type.empty()) {
fprintf(stderr,
"%s: empty type given as argument to option '-t'\n",
progname);
exit(1);
}
} else if (strcmp(argv[i], "-o") == 0) {
char *opts;
char *opt;
i++;
if (i == argc)
break;
opts = strdup(argv[i]);
opt = strtok(opts, ",");
while (opt)
{
int j;
int ignore = 0;
const char *ignore_opts[] =
{
"",
"nofail",
"user",
"nouser",
"users",
"auto",
"noauto",
"_netdev",
NULL
};
if (strncmp(opt, "setuid=", 7) == 0) {
setuid = opt + 7;
ignore = 1;
}
for (j = 0; ignore_opts[j]; j++)
if (strcmp(opt, ignore_opts[j]) == 0)
ignore = 1;
if (!ignore) {
if (strcmp(opt, "nodev") == 0)
dev = 0;
else if (strcmp(opt, "nosuid") == 0)
suid = 0;
options = add_option(opt, options);
}
opt = strtok(NULL, ",");
}
free(opts);
}
}
if (dev)
options = add_option("dev", options);
if (suid)
options = add_option("suid", options);
if (type.empty()) {
if (!source.empty()) {
size_t hash_pos = source.find('#');
if (hash_pos != std::string::npos) {
type = source.substr(0, hash_pos);
source = source.substr(hash_pos + 1);
} else {
type = source;
source.clear();
}
if (type.empty()) {
fprintf(stderr, "%s: empty filesystem type\n",
progname);
exit(1);
}
} else {
fprintf(stderr, "%s: empty source\n", progname);
exit(1);
}
}
command += shell_quote(type);
if (!source.empty())
command += " " + shell_quote(source);
command += " " + shell_quote(mountpoint);
if (!options.empty()) {
command += " " + shell_quote("-o");
command += " " + shell_quote(options);
}
if (!setuid.empty()) {
std::string sucommand = command;
command = "su";
command += " -";
command += " " + shell_quote(setuid);
command += " -c";
command += " " + shell_quote(sucommand);
} else if (!getenv("HOME")) {
setenv("HOME", "/root", 0);
}
execl("/bin/sh", "/bin/sh", "-c", command.c_str(), NULL);
fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname,
strerror(errno));
return 1;
}