1 /* 2 * Copyright (c) 2011-2012 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/mount.h> 37 #include <sys/socket.h> 38 #include <netinet/in.h> 39 #include <vfs/hammer2/hammer2_mount.h> 40 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 #include <dmsg.h> 46 47 static int cluster_connect(const char *volume); 48 49 /* 50 * Usage: mount_hammer2 [volume] [mtpt] 51 */ 52 int 53 main(int argc, char *argv[]) 54 { 55 struct hammer2_mount_info info; 56 struct vfsconf vfc; 57 char *mountpt; 58 char *devpath; 59 int error; 60 int mount_flags; 61 62 bzero(&info, sizeof(info)); 63 mount_flags = 0; 64 65 if (argc < 3) 66 exit(1); 67 68 error = getvfsbyname("hammer2", &vfc); 69 if (error) { 70 fprintf(stderr, "hammer2 vfs not loaded\n"); 71 exit(1); 72 } 73 74 devpath = strdup(argv[1]); 75 76 if (strchr(devpath, '@') == NULL) { 77 fprintf(stderr, 78 "hammer2_mount: no @LABEL specified: \"%s\"\n" 79 "typical labels are @BOOT, @ROOT, and @DATA\n", 80 devpath); 81 exit(1); 82 } 83 84 /* 85 * Connect to the cluster controller. This handles both remote 86 * mounts and device cache/master/slave mounts. 87 * 88 * When doing remote mounts that are allowed to run in the background 89 * the mount program will fork, detach, print a message, and exit(0) 90 * the originator while retrying in the background. 91 */ 92 info.cluster_fd = cluster_connect(devpath); 93 if (info.cluster_fd < 0) { 94 fprintf(stderr, 95 "hammer2_mount: cluster_connect(%s) failed\n", 96 devpath); 97 exit(1); 98 } 99 100 /* 101 * Try to mount it, prefix if necessary. 102 */ 103 if (devpath[0] != '/') { 104 char *p2; 105 asprintf(&p2, "/dev/%s", devpath); 106 free(devpath); 107 devpath = p2; 108 } 109 info.volume = devpath; 110 info.hflags = 0; 111 mountpt = argv[2]; 112 113 error = mount(vfc.vfc_name, mountpt, mount_flags, &info); 114 if (error < 0) { 115 if (errno == ERANGE) { 116 fprintf(stderr, 117 "%s integrated with %s\n", 118 info.volume, mountpt); 119 } else { 120 perror("mount: "); 121 exit(1); 122 } 123 } 124 free(devpath); 125 126 /* 127 * XXX fork a backgrounded reconnector process to handle connection 128 * failures. XXX 129 */ 130 131 return (0); 132 } 133 134 /* 135 * Connect to the cluster controller. We can connect to a local or remote 136 * cluster controller, depending. For a multi-node cluster we always want 137 * to connect to the local controller and let it maintain the connections 138 * to the multiple remote nodes. 139 */ 140 static 141 int 142 cluster_connect(const char *volume __unused) 143 { 144 struct sockaddr_in lsin; 145 int fd; 146 147 /* 148 * This starts the hammer2 service if it isn't already running, 149 * so we can connect to it. 150 */ 151 system("/sbin/hammer2 -q service"); 152 153 /* 154 * Connect us to the service but leave the rest to the kernel. 155 * If the connection is lost during the mount 156 */ 157 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 158 perror("socket"); 159 return(-1); 160 } 161 bzero(&lsin, sizeof(lsin)); 162 lsin.sin_family = AF_INET; 163 lsin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 164 lsin.sin_port = htons(DMSG_LISTEN_PORT); 165 166 if (connect(fd, (struct sockaddr *)&lsin, sizeof(lsin)) < 0) { 167 close(fd); 168 fprintf(stderr, "mount_hammer2: unable to connect to " 169 "cluster controller\n"); 170 return(-1); 171 } 172 173 return(fd); 174 } 175