1 /* $NetBSD: mount_puffs.c,v 1.5 2016/11/23 14:33:29 pho Exp $ */ 2 3 /* 4 * Copyright (c) 2010 Antti Kantee. All Rights Reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 /* 29 * This is to support -o getargs without having to replicate it in 30 * every file server. It also allows puffs filesystems to be mounted 31 * via "mount -a". 32 */ 33 34 #include <sys/cdefs.h> 35 #ifndef lint 36 __RCSID("$NetBSD: mount_puffs.c,v 1.5 2016/11/23 14:33:29 pho Exp $"); 37 #endif /* !lint */ 38 39 #include <sys/param.h> 40 #include <sys/mount.h> 41 42 #include <fs/puffs/puffs_msgif.h> 43 44 #include <err.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <sys/cdefs.h> 49 #include <unistd.h> 50 #include <util.h> 51 52 static int 53 usage(void) 54 { 55 56 fprintf(stderr, "usage: %s [-o options] program[#source] mountpoint\n", getprogname()); 57 return 1; 58 } 59 60 static int show_puffs_mount_args(const char *mountpoint) 61 { 62 const char *vtypes[] = { VNODE_TYPES }; 63 struct puffs_kargs kargs; 64 65 if (mount(MOUNT_PUFFS, mountpoint, MNT_GETARGS, &kargs, sizeof(kargs)) == -1) 66 err(1, "mount"); 67 68 printf("version=%d, ", kargs.pa_vers); 69 printf("flags=0x%x, ", kargs.pa_flags); 70 71 printf("root cookie=%p, ", kargs.pa_root_cookie); 72 printf("root type=%s", vtypes[kargs.pa_root_vtype]); 73 74 if (kargs.pa_root_vtype != VDIR) 75 printf(", root size=%llu", 76 (unsigned long long)kargs.pa_root_vsize); 77 if (kargs.pa_root_vtype == VCHR || kargs.pa_root_vtype == VBLK) 78 printf(", root rdev=0x%" PRIx64, (uint64_t)kargs.pa_root_rdev); 79 printf("\n"); 80 81 return 0; 82 } 83 84 static int 85 mount_puffs_filesystem(const char *program, const char *opts, 86 const char *source, const char *mountpoint) 87 { 88 int argc = 0; 89 const char **argv; 90 int rv = 0; 91 92 /* Construct an argument vector: 93 * program [-o opts] [source] mountpoint */ 94 argv = ecalloc(1 + 2 + 1 + 1, sizeof(*argv)); 95 argv[argc++] = program; 96 if (opts != NULL) { 97 argv[argc++] = "-o"; 98 argv[argc++] = opts; 99 } 100 if (source != NULL) { 101 argv[argc++] = source; 102 } 103 argv[argc++] = mountpoint; 104 argv[argc] = NULL; 105 106 /* We intentionally use execvp(3) here because the program can 107 * actually be a basename. */ 108 if (execvp(program, __UNCONST(argv)) == -1) { 109 warn("Cannot execute %s", program); 110 rv = 1; 111 } 112 113 free(argv); 114 return rv; 115 } 116 117 static void add_opt(char **opts, const char *opt) 118 { 119 const size_t orig_len = *opts == NULL ? 0 : strlen(*opts); 120 121 *opts = erealloc(*opts, orig_len + 1 + strlen(opt) + 1); 122 123 if (orig_len == 0) { 124 strcpy(*opts, opt); 125 } 126 else { 127 strcat(*opts, ","); 128 strcat(*opts, opt); 129 } 130 } 131 132 int 133 main(int argc, char *argv[]) 134 { 135 int mntflags = 0; 136 int ch; 137 char *opts = NULL; 138 int rv = 0; 139 140 while ((ch = getopt(argc, argv, "o:")) != -1) { 141 switch (ch) { 142 case 'o': 143 for (char *opt = optarg; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 144 if (strcmp(opt, "getargs") == 0) { 145 mntflags |= MNT_GETARGS; 146 break; /* No need to parse it any further. */ 147 } 148 else { 149 add_opt(&opts, opt); 150 } 151 } 152 break; 153 default: 154 rv = usage(); 155 goto free_opts; 156 } 157 } 158 argc -= optind; 159 argv += optind; 160 161 if (argc != 2) { 162 rv = usage(); 163 goto free_opts; 164 } 165 166 if (mntflags & MNT_GETARGS) { 167 /* Special case for -o getargs: retrieve kernel arguments for 168 * an already mounted filesystem. */ 169 rv = show_puffs_mount_args(argv[1]); 170 } 171 else { 172 /* Split the program name and source. This is to allow 173 * filesystems to be mounted via "mount -a" i.e. /etc/fstab */ 174 char *source = argv[0]; 175 char *program = strsep(&source, "#"); 176 177 rv = mount_puffs_filesystem(program, opts, source, argv[1]); 178 } 179 180 free_opts: 181 free(opts); 182 return rv; 183 } 184