1 /* $NetBSD: mount_msdos.c,v 1.18 1997/09/16 12:24:18 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Christopher G. Demetriou 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christopher G. Demetriou. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 * $FreeBSD: src/sbin/mount_msdos/mount_msdos.c,v 1.19.2.1 2000/07/20 10:35:13 kris Exp $ 33 * $DragonFly: src/sbin/mount_msdos/mount_msdos.c,v 1.8 2008/11/02 21:52:46 swildner Exp $ 34 */ 35 36 #include <sys/param.h> 37 #include <sys/mount.h> 38 #include <sys/stat.h> 39 #include <sys/iconv.h> 40 #include <sys/linker.h> 41 #include <sys/module.h> 42 #include <vfs/msdosfs/msdosfsmount.h> 43 44 #include <ctype.h> 45 #include <err.h> 46 #include <grp.h> 47 #include <locale.h> 48 #include <pwd.h> 49 #include <stdio.h> 50 /* must be after stdio to declare fparseln */ 51 #include <libutil.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <sysexits.h> 55 #include <unistd.h> 56 57 #include "mntopts.h" 58 59 /* 60 * XXX - no way to specify "foo=<bar>"-type options; that's what we'd 61 * want for "-u", "-g", "-m", "-L", and "-D". 62 */ 63 static struct mntopt mopts[] = { 64 MOPT_STDOPTS, 65 MOPT_FORCE, 66 MOPT_SYNC, 67 MOPT_UPDATE, 68 #ifdef MSDOSFSMNT_GEMDOSFS 69 { "gemdosfs", 0, MSDOSFSMNT_GEMDOSFS, 1 }, 70 #endif 71 { "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 }, 72 { "longnames", 0, MSDOSFSMNT_LONGNAME, 1 }, 73 { "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 }, 74 MOPT_NULL 75 }; 76 77 static gid_t a_gid(char *); 78 static uid_t a_uid(char *); 79 static mode_t a_mask(char *); 80 static void usage(void) __dead2; 81 int set_charset(struct msdosfs_args*, const char*, const char*); 82 83 int 84 main(int argc, char **argv) 85 { 86 struct msdosfs_args args; 87 struct stat sb; 88 int c, error, mntflags, set_gid, set_uid, set_mask; 89 char *dev, *dir, mntpath[MAXPATHLEN], *csp; 90 const char *quirk = NULL; 91 char *cs_local = NULL; 92 char *cs_dos = NULL; 93 struct vfsconf vfc; 94 mntflags = set_gid = set_uid = set_mask = 0; 95 memset(&args, '\0', sizeof(args)); 96 args.magic = MSDOSFS_ARGSMAGIC; 97 98 while ((c = getopt(argc, argv, "sl9u:g:m:o:L:D:")) != -1) { 99 switch (c) { 100 #ifdef MSDOSFSMNT_GEMDOSFS 101 case 'G': 102 args.flags |= MSDOSFSMNT_GEMDOSFS; 103 break; 104 #endif 105 case 's': 106 args.flags |= MSDOSFSMNT_SHORTNAME; 107 break; 108 case 'l': 109 args.flags |= MSDOSFSMNT_LONGNAME; 110 break; 111 case '9': 112 args.flags |= MSDOSFSMNT_NOWIN95; 113 break; 114 case 'u': 115 args.uid = a_uid(optarg); 116 set_uid = 1; 117 break; 118 case 'g': 119 args.gid = a_gid(optarg); 120 set_gid = 1; 121 break; 122 case 'm': 123 args.mask = a_mask(optarg); 124 set_mask = 1; 125 break; 126 case 'L': 127 if (setlocale(LC_CTYPE, optarg) == NULL) 128 err(EX_CONFIG, "%s", optarg); 129 csp = strchr(optarg,'.'); 130 if (!csp) 131 err(EX_CONFIG, "%s", optarg); 132 quirk = kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT); 133 cs_local = strdup(quirk); 134 args.flags |= MSDOSFSMNT_KICONV; 135 break; 136 case 'D': 137 csp = optarg; 138 cs_dos = strdup(optarg); 139 args.flags |= MSDOSFSMNT_KICONV; 140 break; 141 case 'o': 142 getmntopts(optarg, mopts, &mntflags, &args.flags); 143 break; 144 case '?': 145 default: 146 usage(); 147 break; 148 } 149 } 150 151 if (optind + 2 != argc) 152 usage(); 153 154 dev = argv[optind]; 155 dir = argv[optind + 1]; 156 157 /* 158 * Resolve the mountpoint with realpath(3) and remove unnecessary 159 * slashes from the devicename if there are any. 160 */ 161 checkpath(dir, mntpath); 162 rmslashes(dev, dev); 163 164 args.fspec = dev; 165 args.export.ex_root = -2; /* unchecked anyway on DOS fs */ 166 167 if (cs_local != NULL) { 168 if (set_charset(&args, cs_local, cs_dos) == -1) 169 err(EX_OSERR, "msdos_iconv"); 170 } else if (cs_dos != NULL) { 171 if (set_charset(&args, "ISO8859-1", cs_dos) == -1) 172 err(EX_OSERR, "msdos_iconv"); 173 } 174 175 if (mntflags & MNT_RDONLY) 176 args.export.ex_flags = MNT_EXRDONLY; 177 else 178 args.export.ex_flags = 0; 179 if (!set_gid || !set_uid || !set_mask) { 180 if (stat(mntpath, &sb) == -1) 181 err(EX_OSERR, "stat %s", mntpath); 182 183 if (!set_uid) 184 args.uid = sb.st_uid; 185 if (!set_gid) 186 args.gid = sb.st_gid; 187 if (!set_mask) 188 args.mask = sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 189 } 190 191 error = getvfsbyname("msdos", &vfc); 192 if (error && vfsisloadable("msdos")) { 193 if (vfsload("msdos")) 194 err(EX_OSERR, "vfsload(msdos)"); 195 endvfsent(); /* clear cache */ 196 error = getvfsbyname("msdos", &vfc); 197 } 198 if (error) 199 errx(EX_OSERR, "msdos filesystem is not available"); 200 201 if (mount(vfc.vfc_name, mntpath, mntflags, &args) < 0) 202 err(EX_OSERR, "%s", dev); 203 204 exit (0); 205 } 206 207 static gid_t 208 a_gid(char *s) 209 { 210 struct group *gr; 211 char *gname; 212 gid_t gid; 213 214 if ((gr = getgrnam(s)) != NULL) 215 gid = gr->gr_gid; 216 else { 217 for (gname = s; *s && isdigit(*s); ++s); 218 if (!*s) 219 gid = atoi(gname); 220 else 221 errx(EX_NOUSER, "unknown group id: %s", gname); 222 } 223 return (gid); 224 } 225 226 static uid_t 227 a_uid(char *s) 228 { 229 struct passwd *pw; 230 char *uname; 231 uid_t uid; 232 233 if ((pw = getpwnam(s)) != NULL) 234 uid = pw->pw_uid; 235 else { 236 for (uname = s; *s && isdigit(*s); ++s); 237 if (!*s) 238 uid = atoi(uname); 239 else 240 errx(EX_NOUSER, "unknown user id: %s", uname); 241 } 242 return (uid); 243 } 244 245 static mode_t 246 a_mask(char *s) 247 { 248 int done, rv; 249 char *ep; 250 251 done = 0; 252 rv = -1; 253 if (*s >= '0' && *s <= '7') { 254 done = 1; 255 rv = strtol(optarg, &ep, 8); 256 } 257 if (!done || rv < 0 || *ep) 258 errx(EX_USAGE, "invalid file mode: %s", s); 259 return (rv); 260 } 261 262 static void 263 usage(void) 264 { 265 fprintf(stderr, "%s\n%s\n", 266 "usage: mount_msdos [-o options] [-u user] [-g group] [-m mask]", 267 " [-s] [-l] [-9] [-L locale] [-D codepage] bdev dir"); 268 exit(EX_USAGE); 269 } 270 271 int 272 set_charset(struct msdosfs_args *args, const char *cs_local, const char *cs_dos) 273 { 274 int error; 275 if (modfind("msdos_iconv") < 0) { 276 if (kldload("msdos_iconv") < 0 || modfind("msdos_iconv") < 0) 277 { 278 warnx("cannot find or load \"msdos_iconv\" kernel module"); 279 return (-1); 280 } 281 } 282 snprintf(args->cs_local, ICONV_CSNMAXLEN, "%s", cs_local); 283 error = kiconv_add_xlat16_cspairs(ENCODING_UNICODE, cs_local); 284 if (error) 285 return (-1); 286 if (!cs_dos) 287 cs_dos = strdup("CP437"); 288 snprintf(args->cs_dos, ICONV_CSNMAXLEN, "%s", cs_dos); 289 error = kiconv_add_xlat16_cspairs(cs_dos, cs_local); 290 if (error) 291 return (-1); 292 return (0); 293 } 294