ref: b891e5c09af0c39af1b1e9596131afc765ef5e6c
dir: /mount.c/
#ifdef __linux__
#define _GNU_SOURCE
#endif
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <err.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define nelem(x) (sizeof x / sizeof x[0])
enum {
OPT_MAX = 4108,
PATH_MAX = 4096,
};
static char *mountargv[256];
static int mountargc = 0;
static char *optargv[256];
static int optargc = 0;
static char *port = NULL;
static char *user = NULL;
static char *authbox = NULL;
static char *askpass = "/usr/bin/env systemd-ask-password";
static void
appendarg(char *s)
{
if(mountargc >= nelem(mountargv)-1)
errx(EINVAL, "argument overflow");
mountargv[mountargc++] = strdup(s);
mountargv[mountargc] = NULL;
}
static void
_appendopt(char *key, char *val)
{
char buf[OPT_MAX];
if(optargc >= nelem(optargv)-1)
errx(EINVAL, "option overflow");
if(val == NULL)
snprintf(buf, sizeof buf, "%s%s", optargc == 0 ? "" : ",", key);
else
snprintf(buf, sizeof buf, "%s%s=%s", optargc == 0 ? "" : ",", key, val);
optargv[optargc++] = strdup(buf);
optargv[optargc] = NULL;
}
static void
appendopt(char *key, char *val)
{
if(strcmp(key, "port") == 0){
port = strdup(val);
return;
} else if(strcmp(key, "auth") == 0){
authbox = strdup(val);
return;
} else if(strcmp(key, "askpass") == 0){
askpass = strdup(val);
return;
} else if(strcmp(key, "user") == 0){
user = strdup(val);
/* passthrough as well */
} else if(strcmp(key, "trans") == 0){
errx(EINVAL, "trans=fd is set by 9ptls and can not be overriden");
} else if(strcmp(key, "rfdno") == 0 || strcmp(key, "wfdno") == 0){
errx(EINVAL, "rfdno and wfdno are reserved by 9ptls and can not be overriden");
}
_appendopt(key, val);
}
static void
parseoptions(char *opt)
{
char *s;
char *key, *val;
int inquote;
key = val = NULL;
inquote = 0;
for(s = opt; *s != '\0'; s++){
if(key == NULL)
key = s;
if(*s == '"'){
inquote = !inquote;
continue;
}
if(inquote)
continue;
switch(*s){
case '=':
if(key == s)
errx(EINVAL, "option argument has no key, only a value");
*s = '\0';
if(s[1] == '\0')
errx(EINVAL, "key %s has no value", key);
val = s+1;
continue;
case ',':
if(key == s)
errx(EINVAL, "extra comma");
*s = '\0';
appendopt(key, val);
key = val = NULL;
continue;
}
}
if(inquote)
errx(EINVAL, "unterminated double quote");
if(key != NULL)
appendopt(key, val);
_appendopt("trans", "fd");
_appendopt("rfdno", "0");
_appendopt("wfdno", "1");
}
static void
flattenoptions(char *opt, int n)
{
char *s, *e;
int i, j;
s = opt;
e = opt + n - 2;
for(i = 0; i < optargc; i++){
j = strlen(optargv[i]);
if(s+j >= e)
n = e-s;
memcpy(s, optargv[i], j);
s[j] = '\0';
s += j;
}
}
void
usage(void)
{
errx(EINVAL, "Usage: mount.9ptls [-sfnvh] [-o options] [-N namespace] <host> <mountpoint>");
}
int
main(int argc, char **argv)
{
int c;
int sflag, fflag, nflag, vflag;
char options[OPT_MAX];
char namespace[PATH_MAX];
sflag = fflag = nflag = vflag = 0;
options[0] = namespace[0] = '\0';
while((c = getopt_long(argc, argv, "sfnvo:N:h?", 0, 0)) != -1){
switch(c){
case 's':
sflag = 1;
break;
case 'f':
fflag = 1;
break;
case 'n':
nflag = 1;
break;
case 'v':
vflag = 1;
break;
case 'o':
snprintf(options, sizeof options, "%s", optarg);
break;
case 'N':
snprintf(namespace, sizeof namespace, "%s", optarg);
break;
case '?': case 'h':
if(optopt)
errx(EINVAL, "invalid option '%c'", optopt);
usage();
break;
}
}
argc -= optind;
argv += optind;
if(argc != 2)
usage();
parseoptions(options);
if(port == NULL)
errx(EINVAL, "a port option must be given");
if(user == NULL && (user = getenv("USER")) == NULL)
errx(EINVAL, "user option not given and count not infer");
setenv("TLSCLIENT_ASKPASS", askpass, 1);
flattenoptions(options, sizeof options);
appendarg("tlsclient");
appendarg("-b");
appendarg("-h");
appendarg(argv[0]);
if(authbox != NULL){
appendarg("-a");
appendarg(authbox);
}
appendarg("-u");
appendarg(user);
appendarg("-p");
appendarg(port);
appendarg("mount");
if(sflag)
appendarg("-s");
if(fflag)
appendarg("-f");
if(nflag)
appendarg("-n");
if(vflag)
appendarg("-v");
if(namespace[0] != '\0'){
appendarg("-N");
appendarg(namespace);
}
appendarg("-i");
appendarg("-t");
appendarg("9p");
appendarg("-o");
appendarg(options);
appendarg(argv[0]);
appendarg(argv[1]);
execvp("tlsclient", mountargv);
err(EXIT_FAILURE, "could not exec");
}