1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * autofs mount.c 27 * 28 */ 29 30 #include <stdio.h> 31 #include <unistd.h> 32 #include <stdlib.h> 33 #include <ctype.h> 34 #include <sys/param.h> 35 #include <sys/stat.h> 36 #include <sys/mntent.h> 37 #include <sys/mnttab.h> 38 #include <sys/mount.h> 39 #include <sys/utsname.h> 40 #include <sys/tiuser.h> 41 #include <string.h> 42 #include <fslib.h> 43 #include <errno.h> 44 #include <rpcsvc/daemon_utils.h> 45 #include "automount.h" 46 47 #define MNTTAB_OPTS "ignore,nest" 48 49 static void usage(); 50 static void process_opts(char *options, int *directp); 51 static char *concat_opts(const char *opts1, const char *opts2); 52 static int ro_given(char *options); 53 54 /* 55 * list of support services needed 56 */ 57 static char *service_list[] = { AUTOMOUNTD, NULL }; 58 59 int 60 main(int argc, char *argv[]) 61 { 62 int error; 63 int c; 64 int mntflags = 0; 65 int nmflg = 0; 66 int roflg = 0; 67 char *mntpnt, *mapname; 68 struct utsname utsname; 69 char autofs_addr[MAXADDRLEN]; 70 struct autofs_args fni; 71 char *options = ""; 72 int mount_timeout = AUTOFS_MOUNT_TIMEOUT; 73 char obuf[MAX_MNTOPT_STR]; 74 75 while ((c = getopt(argc, argv, "o:mrq")) != EOF) { 76 switch (c) { 77 case '?': 78 usage(); 79 exit(1); 80 /* NOTREACHED */ 81 82 case 'o': 83 options = optarg; 84 break; 85 86 case 'm': 87 nmflg++; 88 break; 89 case 'r': /* converted to -o ro always */ 90 roflg++; 91 break; 92 /* 93 * The "quiet" flag can be ignored, since this 94 * program never complains about invalid -o options 95 * anyway. 96 */ 97 case 'q': 98 break; 99 100 default: 101 usage(); 102 } 103 } 104 if (argc - optind != 2) 105 usage(); 106 107 mapname = argv[optind]; 108 mntpnt = argv[optind + 1]; 109 110 if (strcmp(mntpnt, "/-") == 0) { 111 (void) fprintf(stderr, "invalid mountpoint: /-\n"); 112 exit(1); 113 } 114 115 if (uname(&utsname) < 0) { 116 perror("uname"); 117 exit(1); 118 } 119 (void) strcpy(autofs_addr, utsname.nodename); 120 (void) strcat(autofs_addr, ".autofs"); 121 122 process_opts(options, &fni.direct); 123 124 if (roflg && !ro_given(options)) 125 options = concat_opts(options, "ro"); 126 127 fni.addr.buf = autofs_addr; 128 fni.addr.len = strlen(fni.addr.buf); 129 fni.addr.maxlen = fni.addr.len; 130 fni.path = mntpnt; 131 fni.opts = options; 132 fni.map = mapname; 133 fni.subdir = ""; 134 if (fni.direct) 135 fni.key = mntpnt; 136 else 137 fni.key = ""; 138 fni.mount_to = mount_timeout; 139 fni.rpc_to = AUTOFS_RPC_TIMEOUT; 140 141 strcpy(obuf, options); 142 if (*obuf != '\0') 143 strcat(obuf, ","); 144 strcat(obuf, 145 fni.direct ? MNTTAB_OPTS ",direct" : MNTTAB_OPTS ",indirect"); 146 147 /* 148 * enable services as needed. 149 */ 150 _check_services(service_list); 151 152 error = mount(fni.map, mntpnt, mntflags | MS_DATA | MS_OPTIONSTR, 153 MNTTYPE_AUTOFS, &fni, sizeof (fni), obuf, MAX_MNTOPT_STR); 154 if (error < 0) { 155 perror("autofs mount"); 156 exit(1); 157 } 158 return (0); 159 } 160 161 static void 162 usage() 163 { 164 (void) fprintf(stderr, 165 "Usage: autofs mount [-r] [-o opts] map dir\n"); 166 exit(1); 167 } 168 169 /* 170 * Remove pseudo-options "direct", "indirect", "nest", and "ignore" from 171 * option list. Set *directp to 1 if "direct" is found, and 0 otherwise 172 * (mounts are indirect by default). If both "direct" and "indirect" are 173 * found, the last one wins. 174 */ 175 static void 176 process_opts(char *options, int *directp) 177 { 178 char *opt; 179 char *opts; 180 181 if ((opts = strdup(options)) == NULL) { 182 (void) fprintf(stderr, 183 "autofs mount: memory allocation failed\n"); 184 exit(1); 185 } 186 options[0] = '\0'; 187 *directp = 0; 188 189 while ((opt = strtok(opts, ",")) != NULL) { 190 opts = NULL; 191 while (isspace(*opt)) { 192 opt++; 193 } 194 if (strcmp(opt, "direct") == 0) { 195 *directp = 1; 196 } else if (strcmp(opt, "indirect") == 0) { 197 *directp = 0; 198 } else if ((strcmp(opt, "nest") != 0) && 199 (strcmp(opt, "ignore") != 0)) { 200 if (options[0] != '\0') { 201 (void) strcat(options, ","); 202 } 203 (void) strcat(options, opt); 204 } 205 }; 206 } 207 208 /* 209 * Concatenate two options strings, with a comma between them. 210 */ 211 static char * 212 concat_opts(const char *opts1, const char *opts2) 213 { 214 char *opts = malloc(strlen(opts1) + strlen(opts2) + 2); 215 if (opts == NULL) { 216 (void) fprintf(stderr, 217 "autofs mount: memory allocation failed\n"); 218 exit(1); 219 } 220 strcpy(opts, opts1); 221 if (opts1[0] != '\0' && opts2[0] != '\0') { 222 strcat(opts, ","); 223 } 224 return (strcat(opts, opts2)); 225 } 226 227 /* 228 * check the options string for 'ro' options 229 * if present returns 1 otherwise return 0; 230 */ 231 232 static int 233 ro_given(char *options) 234 { 235 char *op = options; 236 237 if (!*op) 238 return (0); 239 240 while (op != 0) { 241 if (*op == 'r' && *(op+1) == 'o' && 242 (*(op+2) == ',' || *(op+2) == '\0')) 243 return (1); 244 245 if ((op = strchr(op, ',')) != NULL) 246 op++; 247 } 248 249 250 return (0); 251 } 252