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