1 /* 2 * Copyright (c) 2011-2015 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@dragonflybsd.org> 6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 3. Neither the name of The DragonFly Project nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific, prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 #include <sys/types.h> 36 #include <sys/param.h> 37 #include <sys/mount.h> 38 #include <sys/socket.h> 39 #include <netinet/in.h> 40 #include <vfs/hammer2/hammer2_mount.h> 41 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <stdarg.h> 45 #include <string.h> 46 #include <unistd.h> 47 #include <dmsg.h> 48 #include <mntopts.h> 49 50 static int cluster_connect(const char *volume); 51 static void usage(const char *ctl, ...); 52 53 static struct mntopt mopts[] = { 54 MOPT_STDOPTS, 55 { "update", 0, MNT_UPDATE, 0 }, 56 { "local", 0, HMNT2_LOCAL, 1 }, 57 MOPT_NULL 58 }; 59 60 /* 61 * Usage: mount_hammer2 [volume] [mtpt] 62 */ 63 int 64 main(int ac, char *av[]) 65 { 66 struct hammer2_mount_info info; 67 struct vfsconf vfc; 68 char *mountpt; 69 char *devpath; 70 int error; 71 int ch; 72 int mount_flags; 73 int init_flags; 74 75 bzero(&info, sizeof(info)); 76 mount_flags = 0; 77 init_flags = 0; 78 79 while ((ch = getopt(ac, av, "o:u")) != -1) { 80 switch(ch) { 81 case 'o': 82 getmntopts(optarg, mopts, &mount_flags, &info.hflags); 83 break; 84 case 'u': 85 init_flags |= MNT_UPDATE; 86 break; 87 default: 88 usage("unknown option: -%c", ch); 89 /* not reached */ 90 } 91 } 92 ac -= optind; 93 av += optind; 94 mount_flags |= init_flags; 95 96 error = getvfsbyname("hammer2", &vfc); 97 if (error) { 98 fprintf(stderr, "hammer2 vfs not loaded\n"); 99 exit(1); 100 } 101 102 /* 103 * Only the mount point need be specified in update mode. 104 */ 105 if (init_flags & MNT_UPDATE) { 106 if (ac != 1) { 107 usage("missing parameter (mountpoint)"); 108 /* not reached */ 109 } 110 mountpt = av[0]; 111 if (mount(vfc.vfc_name, mountpt, mount_flags, &info)) 112 usage("mount %s: %s", mountpt, strerror(errno)); 113 exit(0); 114 } 115 116 /* 117 * New mount 118 */ 119 if (ac != 2) { 120 usage("missing parameter(s) (dev@LABEL mountpt)"); 121 /* not reached */ 122 } 123 124 devpath = strdup(av[0]); 125 mountpt = av[1]; 126 127 if (strchr(devpath, '@') == NULL) { 128 fprintf(stderr, 129 "hammer2_mount: no @LABEL specified: \"%s\"\n" 130 "typical labels are @LOCAL, @ROOT\n", 131 devpath); 132 exit(1); 133 } 134 135 /* 136 * Connect to the cluster controller. This handles both remote 137 * mounts and device cache/master/slave mounts. 138 * 139 * When doing remote mounts that are allowed to run in the background 140 * the mount program will fork, detach, print a message, and exit(0) 141 * the originator while retrying in the background. 142 */ 143 info.cluster_fd = cluster_connect(devpath); 144 if (info.cluster_fd < 0) { 145 fprintf(stderr, 146 "hammer2_mount: cluster_connect(%s) failed\n", 147 devpath); 148 exit(1); 149 } 150 151 /* 152 * Try to mount it, prefix if necessary. 153 */ 154 if (devpath[0] != '/') { 155 char *p2; 156 asprintf(&p2, "/dev/%s", devpath); 157 free(devpath); 158 devpath = p2; 159 } 160 info.volume = devpath; 161 162 error = mount(vfc.vfc_name, mountpt, mount_flags, &info); 163 if (error < 0) { 164 if (errno == ERANGE) { 165 fprintf(stderr, 166 "%s integrated with %s\n", 167 info.volume, mountpt); 168 } else { 169 perror("mount: "); 170 exit(1); 171 } 172 } 173 free(devpath); 174 175 /* 176 * XXX fork a backgrounded reconnector process to handle connection 177 * failures. XXX 178 */ 179 180 return (0); 181 } 182 183 /* 184 * Connect to the cluster controller. We can connect to a local or remote 185 * cluster controller, depending. For a multi-node cluster we always want 186 * to connect to the local controller and let it maintain the connections 187 * to the multiple remote nodes. 188 */ 189 static 190 int 191 cluster_connect(const char *volume __unused) 192 { 193 struct sockaddr_in lsin; 194 int fd; 195 196 /* 197 * This starts the hammer2 service if it isn't already running, 198 * so we can connect to it. 199 */ 200 system("/sbin/hammer2 -q service"); 201 202 /* 203 * Connect us to the service but leave the rest to the kernel. 204 * If the connection is lost during the mount 205 */ 206 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 207 perror("socket"); 208 return(-1); 209 } 210 bzero(&lsin, sizeof(lsin)); 211 lsin.sin_family = AF_INET; 212 lsin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 213 lsin.sin_port = htons(DMSG_LISTEN_PORT); 214 215 if (connect(fd, (struct sockaddr *)&lsin, sizeof(lsin)) < 0) { 216 close(fd); 217 fprintf(stderr, "mount_hammer2: unable to connect to " 218 "cluster controller\n"); 219 return(-1); 220 } 221 222 return(fd); 223 } 224 225 static 226 void 227 usage(const char *ctl, ...) 228 { 229 va_list va; 230 231 va_start(va, ctl); 232 fprintf(stderr, "hammer2_mount: "); 233 vfprintf(stderr, ctl, va); 234 va_end(va); 235 fprintf(stderr, "\n"); 236 fprintf(stderr, " hammer2_mount -u [-o opts] mountpt\n"); 237 fprintf(stderr, " hammer2_mount [-o opts] dev@LABEL mountpt\n"); 238 fprintf(stderr, "\n"); 239 fprintf(stderr, "options:\n" 240 " <standard_mount_opts>\n" 241 " local\t- disable PFS clustering for whole device\n" 242 ); 243 exit(1); 244 } 245