xref: /openbmc/linux/samples/vfs/test-fsmount.c (revision b664e06d)
1 /* fd-based mount test.
2  *
3  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public Licence
8  * as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <sys/prctl.h>
18 #include <sys/wait.h>
19 #include <linux/mount.h>
20 #include <linux/unistd.h>
21 
22 #define E(x) do { if ((x) == -1) { perror(#x); exit(1); } } while(0)
23 
24 static void check_messages(int fd)
25 {
26 	char buf[4096];
27 	int err, n;
28 
29 	err = errno;
30 
31 	for (;;) {
32 		n = read(fd, buf, sizeof(buf));
33 		if (n < 0)
34 			break;
35 		n -= 2;
36 
37 		switch (buf[0]) {
38 		case 'e':
39 			fprintf(stderr, "Error: %*.*s\n", n, n, buf + 2);
40 			break;
41 		case 'w':
42 			fprintf(stderr, "Warning: %*.*s\n", n, n, buf + 2);
43 			break;
44 		case 'i':
45 			fprintf(stderr, "Info: %*.*s\n", n, n, buf + 2);
46 			break;
47 		}
48 	}
49 
50 	errno = err;
51 }
52 
53 static __attribute__((noreturn))
54 void mount_error(int fd, const char *s)
55 {
56 	check_messages(fd);
57 	fprintf(stderr, "%s: %m\n", s);
58 	exit(1);
59 }
60 
61 /* Hope -1 isn't a syscall */
62 #ifndef __NR_fsopen
63 #define __NR_fsopen -1
64 #endif
65 #ifndef __NR_fsmount
66 #define __NR_fsmount -1
67 #endif
68 #ifndef __NR_fsconfig
69 #define __NR_fsconfig -1
70 #endif
71 #ifndef __NR_move_mount
72 #define __NR_move_mount -1
73 #endif
74 
75 
76 static inline int fsopen(const char *fs_name, unsigned int flags)
77 {
78 	return syscall(__NR_fsopen, fs_name, flags);
79 }
80 
81 static inline int fsmount(int fsfd, unsigned int flags, unsigned int ms_flags)
82 {
83 	return syscall(__NR_fsmount, fsfd, flags, ms_flags);
84 }
85 
86 static inline int fsconfig(int fsfd, unsigned int cmd,
87 			   const char *key, const void *val, int aux)
88 {
89 	return syscall(__NR_fsconfig, fsfd, cmd, key, val, aux);
90 }
91 
92 static inline int move_mount(int from_dfd, const char *from_pathname,
93 			     int to_dfd, const char *to_pathname,
94 			     unsigned int flags)
95 {
96 	return syscall(__NR_move_mount,
97 		       from_dfd, from_pathname,
98 		       to_dfd, to_pathname, flags);
99 }
100 
101 #define E_fsconfig(fd, cmd, key, val, aux)				\
102 	do {								\
103 		if (fsconfig(fd, cmd, key, val, aux) == -1)		\
104 			mount_error(fd, key ?: "create");		\
105 	} while (0)
106 
107 int main(int argc, char *argv[])
108 {
109 	int fsfd, mfd;
110 
111 	/* Mount a publically available AFS filesystem */
112 	fsfd = fsopen("afs", 0);
113 	if (fsfd == -1) {
114 		perror("fsopen");
115 		exit(1);
116 	}
117 
118 	E_fsconfig(fsfd, FSCONFIG_SET_STRING, "source", "#grand.central.org:root.cell.", 0);
119 	E_fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0);
120 
121 	mfd = fsmount(fsfd, 0, MOUNT_ATTR_RDONLY);
122 	if (mfd < 0)
123 		mount_error(fsfd, "fsmount");
124 	E(close(fsfd));
125 
126 	if (move_mount(mfd, "", AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH) < 0) {
127 		perror("move_mount");
128 		exit(1);
129 	}
130 
131 	E(close(mfd));
132 	exit(0);
133 }
134