#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <err.h>
#include <errno.h>
#include <mntopts.h>
#include <paths.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int getmnt_silent = 0;
void
getmntopts(const char *options, const struct mntopt *m0, int *flagp,
int *altflagp)
{
const struct mntopt *m;
int negative, len;
char *opt, *optbuf, *p;
int *thisflagp;
if ((optbuf = strdup(options)) == NULL)
err(1, NULL);
for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
if (opt[0] == 'n' && opt[1] == 'o') {
negative = 1;
opt += 2;
} else
negative = 0;
p = strchr(opt, '=');
if (p != NULL)
*++p = '\0';
for (m = m0; m->m_option != NULL; ++m) {
len = strlen(m->m_option);
if (strncasecmp(opt, m->m_option, len) == 0)
if (opt[len] == '\0' || opt[len] == '=')
break;
}
if (m->m_option) {
thisflagp = m->m_altloc ? altflagp : flagp;
if (negative == m->m_inverse)
*thisflagp |= m->m_flag;
else
*thisflagp &= ~m->m_flag;
} else if (!getmnt_silent) {
errx(1, "-o %s: option not supported", opt);
}
}
free(optbuf);
}
void
rmslashes(char *rrpin, char *rrpout)
{
char *rrpoutstart;
*rrpout = *rrpin;
for (rrpoutstart = rrpout; *rrpin != '\0'; *rrpout++ = *rrpin++) {
while (*rrpin == '/' && *(rrpin + 1) == '/')
rrpin++;
}
if (rrpout - rrpoutstart > 1 && *(rrpout - 1) == '/')
*(rrpout - 1) = '\0';
else
*rrpout = '\0';
}
int
checkpath(const char *path, char *resolved)
{
struct stat sb;
if (realpath(path, resolved) == NULL || stat(resolved, &sb) != 0)
return (1);
if (!S_ISDIR(sb.st_mode)) {
errno = ENOTDIR;
return (1);
}
return (0);
}
int
checkpath_allow_file(const char *path, char *resolved)
{
struct stat sb;
if (realpath(path, resolved) == NULL || stat(resolved, &sb) != 0)
return (1);
if (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode)) {
errno = ENOTDIR;
return (1);
}
return (0);
}
static char *
prependdevtopath(const char *path, char *buf, u_long buflen)
{
u_long len;
if ((len = strlen(_PATH_DEV) + strlen(path) + 1) > buflen)
return NULL;
strncpy(buf, _PATH_DEV, len);
strncat(buf, path, len - sizeof(_PATH_DEV));
return (buf);
}
struct statfs *
getmntpoint(const char *name)
{
struct stat devstat, mntdevstat;
char *devname;
struct statfs *mntbuf, *statfsp;
int i, len, isdev, mntsize, mntfromnamesize;
char device[sizeof(_PATH_DEV) - 1 + MNAMELEN];
u_long devlen;
devlen = sizeof(device);
if (stat(name, &devstat) != 0 &&
(name[0] != '/' &&
stat(prependdevtopath(name, device, devlen), &devstat) != 0))
return (NULL);
if (S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode))
isdev = 1;
else
isdev = 0;
mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
mntfromnamesize = sizeof(statfsp->f_mntfromname);
for (i = 0; i < mntsize; i++) {
statfsp = &mntbuf[i];
if (isdev == 0) {
if (strcmp(name, statfsp->f_mntonname))
continue;
return (statfsp);
}
devname = statfsp->f_mntfromname;
if (*devname == '/') {
if (stat(devname, &mntdevstat) != 0)
continue;
} else {
devname = prependdevtopath(devname, device, devlen);
if (devname == NULL ||
(len = strlen(devname)) > mntfromnamesize)
continue;
if (stat(devname, &mntdevstat) != 0)
continue;
strncpy(statfsp->f_mntfromname, devname, len);
}
if (S_ISCHR(mntdevstat.st_mode) &&
mntdevstat.st_rdev == devstat.st_rdev)
return (statfsp);
}
return (NULL);
}
int
chkdoreload(struct statfs *mntp,
void (*prtmsg)(const char *, ...) __printflike(1,2))
{
struct iovec *iov;
int iovlen, error;
char errmsg[255];
if (mntp == NULL || (mntp->f_flags & MNT_RDONLY) == 0)
return (0);
iov = NULL;
iovlen = 0;
errmsg[0] = '\0';
build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "ffs"), 4);
build_iovec(&iov, &iovlen, "from", mntp->f_mntfromname, (size_t)-1);
build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname, (size_t)-1);
build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
build_iovec(&iov, &iovlen, "update", NULL, 0);
build_iovec(&iov, &iovlen, "reload", NULL, 0);
build_iovec(&iov, &iovlen, "ro", NULL, 0);
error = nmount(iov, iovlen, mntp->f_flags);
free_iovec(&iov, &iovlen);
if (error == 0)
return (0);
if (prtmsg != NULL)
prtmsg("mount reload of '%s' failed: %s %s\n\n",
mntp->f_mntonname, strerror(errno), errmsg);
return (1);
}
void
build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val,
size_t len)
{
int i;
if (*iovlen < 0)
return;
i = *iovlen;
*iov = realloc(*iov, sizeof **iov * (i + 2));
if (*iov == NULL) {
*iovlen = -1;
return;
}
(*iov)[i].iov_base = strdup(name);
(*iov)[i].iov_len = strlen(name) + 1;
i++;
(*iov)[i].iov_base = val;
if (len == (size_t)-1) {
if (val != NULL)
len = strlen(val) + 1;
else
len = 0;
}
(*iov)[i].iov_len = (int)len;
*iovlen = ++i;
}
void
build_iovec_argf(struct iovec **iov, int *iovlen, const char *name,
const char *fmt, ...)
{
va_list ap;
char val[255] = { 0 };
va_start(ap, fmt);
vsnprintf(val, sizeof(val), fmt, ap);
va_end(ap);
build_iovec(iov, iovlen, name, strdup(val), (size_t)-1);
}
void
free_iovec(struct iovec **iov, int *iovlen)
{
int i;
for (i = 0; i < *iovlen; i += 2)
free((*iov)[i].iov_base);
free(*iov);
}