forked from Qortal/Brooklyn
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.
129 lines
2.6 KiB
129 lines
2.6 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* fd-based mount test. |
|
* |
|
* Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. |
|
* Written by David Howells ([email protected]) |
|
*/ |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <unistd.h> |
|
#include <errno.h> |
|
#include <fcntl.h> |
|
#include <sys/prctl.h> |
|
#include <sys/wait.h> |
|
#include <linux/mount.h> |
|
#include <linux/unistd.h> |
|
|
|
#define E(x) do { if ((x) == -1) { perror(#x); exit(1); } } while(0) |
|
|
|
static void check_messages(int fd) |
|
{ |
|
char buf[4096]; |
|
int err, n; |
|
|
|
err = errno; |
|
|
|
for (;;) { |
|
n = read(fd, buf, sizeof(buf)); |
|
if (n < 0) |
|
break; |
|
n -= 2; |
|
|
|
switch (buf[0]) { |
|
case 'e': |
|
fprintf(stderr, "Error: %*.*s\n", n, n, buf + 2); |
|
break; |
|
case 'w': |
|
fprintf(stderr, "Warning: %*.*s\n", n, n, buf + 2); |
|
break; |
|
case 'i': |
|
fprintf(stderr, "Info: %*.*s\n", n, n, buf + 2); |
|
break; |
|
} |
|
} |
|
|
|
errno = err; |
|
} |
|
|
|
static __attribute__((noreturn)) |
|
void mount_error(int fd, const char *s) |
|
{ |
|
check_messages(fd); |
|
fprintf(stderr, "%s: %m\n", s); |
|
exit(1); |
|
} |
|
|
|
/* Hope -1 isn't a syscall */ |
|
#ifndef __NR_fsopen |
|
#define __NR_fsopen -1 |
|
#endif |
|
#ifndef __NR_fsmount |
|
#define __NR_fsmount -1 |
|
#endif |
|
#ifndef __NR_fsconfig |
|
#define __NR_fsconfig -1 |
|
#endif |
|
#ifndef __NR_move_mount |
|
#define __NR_move_mount -1 |
|
#endif |
|
|
|
|
|
static inline int fsopen(const char *fs_name, unsigned int flags) |
|
{ |
|
return syscall(__NR_fsopen, fs_name, flags); |
|
} |
|
|
|
static inline int fsmount(int fsfd, unsigned int flags, unsigned int ms_flags) |
|
{ |
|
return syscall(__NR_fsmount, fsfd, flags, ms_flags); |
|
} |
|
|
|
static inline int fsconfig(int fsfd, unsigned int cmd, |
|
const char *key, const void *val, int aux) |
|
{ |
|
return syscall(__NR_fsconfig, fsfd, cmd, key, val, aux); |
|
} |
|
|
|
static inline int move_mount(int from_dfd, const char *from_pathname, |
|
int to_dfd, const char *to_pathname, |
|
unsigned int flags) |
|
{ |
|
return syscall(__NR_move_mount, |
|
from_dfd, from_pathname, |
|
to_dfd, to_pathname, flags); |
|
} |
|
|
|
#define E_fsconfig(fd, cmd, key, val, aux) \ |
|
do { \ |
|
if (fsconfig(fd, cmd, key, val, aux) == -1) \ |
|
mount_error(fd, key ?: "create"); \ |
|
} while (0) |
|
|
|
int main(int argc, char *argv[]) |
|
{ |
|
int fsfd, mfd; |
|
|
|
/* Mount a publically available AFS filesystem */ |
|
fsfd = fsopen("afs", 0); |
|
if (fsfd == -1) { |
|
perror("fsopen"); |
|
exit(1); |
|
} |
|
|
|
E_fsconfig(fsfd, FSCONFIG_SET_STRING, "source", "#grand.central.org:root.cell.", 0); |
|
E_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); |
|
|
|
mfd = fsmount(fsfd, 0, MOUNT_ATTR_RDONLY); |
|
if (mfd < 0) |
|
mount_error(fsfd, "fsmount"); |
|
E(close(fsfd)); |
|
|
|
if (move_mount(mfd, "", AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH) < 0) { |
|
perror("move_mount"); |
|
exit(1); |
|
} |
|
|
|
E(close(mfd)); |
|
exit(0); |
|
}
|
|
|