mount_msdosfs.c revision 152731
1160814Ssimon/* $NetBSD: mount_msdos.c,v 1.18 1997/09/16 12:24:18 lukem Exp $ */ 2296341Sdelphij 3160814Ssimon/* 4296341Sdelphij * Copyright (c) 1994 Christopher G. Demetriou 5160814Ssimon * All rights reserved. 6160814Ssimon * 7160814Ssimon * Redistribution and use in source and binary forms, with or without 8160814Ssimon * modification, are permitted provided that the following conditions 9160814Ssimon * are met: 10160814Ssimon * 1. Redistributions of source code must retain the above copyright 11160814Ssimon * notice, this list of conditions and the following disclaimer. 12160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright 13160814Ssimon * notice, this list of conditions and the following disclaimer in the 14296341Sdelphij * documentation and/or other materials provided with the distribution. 15160814Ssimon * 3. All advertising materials mentioning features or use of this software 16160814Ssimon * must display the following acknowledgement: 17160814Ssimon * This product includes software developed by Christopher G. Demetriou. 18160814Ssimon * 4. The name of the author may not be used to endorse or promote products 19160814Ssimon * derived from this software without specific prior written permission 20160814Ssimon * 21160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22160814Ssimon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23160814Ssimon * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24160814Ssimon * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25160814Ssimon * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26160814Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27160814Ssimon * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28160814Ssimon * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29160814Ssimon * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30160814Ssimon * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31160814Ssimon */ 32160814Ssimon 33160814Ssimon#ifndef lint 34160814Ssimonstatic const char rcsid[] = 35160814Ssimon "$FreeBSD: head/sbin/mount_msdosfs/mount_msdosfs.c 152731 2005-11-23 19:52:14Z avatar $"; 36160814Ssimon#endif /* not lint */ 37160814Ssimon 38160814Ssimon#include <sys/param.h> 39160814Ssimon#include <sys/mount.h> 40160814Ssimon#include <sys/stat.h> 41160814Ssimon#include <sys/iconv.h> 42160814Ssimon#include <sys/linker.h> 43160814Ssimon#include <sys/module.h> 44160814Ssimon 45160814Ssimon#include <ctype.h> 46160814Ssimon#include <err.h> 47160814Ssimon#include <grp.h> 48160814Ssimon#include <locale.h> 49160814Ssimon#include <pwd.h> 50160814Ssimon#include <stdio.h> 51160814Ssimon/* must be after stdio to declare fparseln */ 52160814Ssimon#include <libutil.h> 53160814Ssimon#include <stdlib.h> 54160814Ssimon#include <string.h> 55160814Ssimon#include <sysexits.h> 56160814Ssimon#include <unistd.h> 57160814Ssimon 58160814Ssimon#include "mntopts.h" 59160814Ssimon 60160814Ssimonstatic struct mntopt mopts[] = { 61205128Ssimon MOPT_STDOPTS, 62160814Ssimon MOPT_FORCE, 63160814Ssimon MOPT_SYNC, 64160814Ssimon MOPT_UPDATE, 65205128Ssimon MOPT_END 66296341Sdelphij}; 67205128Ssimon 68205128Ssimonstatic gid_t a_gid(char *); 69205128Ssimonstatic uid_t a_uid(char *); 70296341Sdelphijstatic mode_t a_mask(char *); 71205128Ssimonstatic void usage(void) __dead2; 72160814Ssimonstatic int set_charset(struct iovec *iov, int *iovlen, const char *, const char *); 73296341Sdelphij 74160814Ssimonint 75296341Sdelphijmain(int argc, char **argv) 76296341Sdelphij{ 77296341Sdelphij struct iovec *iov = NULL; 78296341Sdelphij int iovlen = 0; 79296341Sdelphij struct stat sb; 80296341Sdelphij int c, mntflags, set_gid, set_uid, set_mask, set_dirmask; 81296341Sdelphij int optflags = 0; 82296341Sdelphij char *dev, *dir, mntpath[MAXPATHLEN], *csp; 83296341Sdelphij char fstype[] = "msdosfs"; 84296341Sdelphij char *cs_dos = NULL; 85296341Sdelphij char *cs_local = NULL; 86296341Sdelphij mode_t mask = 0, dirmask = 0; 87160814Ssimon uid_t uid = 0; 88160814Ssimon gid_t gid = 0; 89296341Sdelphij getmnt_silent = 1; 90296341Sdelphij 91296341Sdelphij mntflags = set_gid = set_uid = set_mask = set_dirmask = 0; 92296341Sdelphij 93296341Sdelphij while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) { 94296341Sdelphij switch (c) { 95296341Sdelphij case 's': 96160814Ssimon build_iovec(&iov, &iovlen, "shortnames", NULL, (size_t)-1); 97160814Ssimon break; 98296341Sdelphij case 'l': 99296341Sdelphij build_iovec(&iov, &iovlen, "longnames", NULL, (size_t)-1); 100160814Ssimon break; 101296341Sdelphij case '9': 102296341Sdelphij build_iovec_argf(&iov, &iovlen, "nowin95", "", (size_t)-1); 103296341Sdelphij break; 104296341Sdelphij case 'u': 105296341Sdelphij uid = a_uid(optarg); 106160814Ssimon set_uid = 1; 107296341Sdelphij break; 108160814Ssimon case 'g': 109296341Sdelphij gid = a_gid(optarg); 110296341Sdelphij set_gid = 1; 111296341Sdelphij break; 112296341Sdelphij case 'm': 113296341Sdelphij mask = a_mask(optarg); 114160814Ssimon set_mask = 1; 115296341Sdelphij break; 116296341Sdelphij case 'M': 117296341Sdelphij dirmask = a_mask(optarg); 118160814Ssimon set_dirmask = 1; 119296341Sdelphij break; 120296341Sdelphij case 'L': { 121279264Sdelphij const char *quirk = NULL; 122296341Sdelphij if (setlocale(LC_CTYPE, optarg) == NULL) 123296341Sdelphij err(EX_CONFIG, "%s", optarg); 124296341Sdelphij csp = strchr(optarg,'.'); 125296341Sdelphij if (!csp) 126296341Sdelphij err(EX_CONFIG, "%s", optarg); 127296341Sdelphij quirk = kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT); 128296341Sdelphij build_iovec_argf(&iov, &iovlen, "cs_local", quirk); 129296341Sdelphij } 130296341Sdelphij break; 131296341Sdelphij case 'D': 132296341Sdelphij cs_dos = strdup(optarg); 133296341Sdelphij build_iovec_argf(&iov, &iovlen, "cs_dos", cs_dos, (size_t)-1); 134296341Sdelphij break; 135296341Sdelphij case 'o': { 136296341Sdelphij char *p = NULL; 137296341Sdelphij char *val = strdup(""); 138160814Ssimon getmntopts(optarg, mopts, &mntflags, &optflags); 139296341Sdelphij p = strchr(optarg, '='); 140296341Sdelphij if (p != NULL) { 141296341Sdelphij free(val); 142296341Sdelphij *p = '\0'; 143160814Ssimon val = p + 1; 144237657Sjkim } 145296341Sdelphij build_iovec(&iov, &iovlen, optarg, val, (size_t)-1); 146160814Ssimon } 147296341Sdelphij break; 148160814Ssimon case 'W': 149296341Sdelphij if (strcmp(optarg, "iso22dos") == 0) { 150296341Sdelphij cs_local = strdup("ISO8859-2"); 151296341Sdelphij cs_dos = strdup("CP852"); 152296341Sdelphij } else if (strcmp(optarg, "iso72dos") == 0) { 153296341Sdelphij cs_local = strdup("ISO8859-7"); 154160814Ssimon cs_dos = strdup("CP737"); 155160814Ssimon } else if (strcmp(optarg, "koi2dos") == 0) { 156296341Sdelphij cs_local = strdup("KOI8-R"); 157296341Sdelphij cs_dos = strdup("CP866"); 158296341Sdelphij } else if (strcmp(optarg, "koi8u2dos") == 0) { 159296341Sdelphij cs_local = strdup("KOI8-U"); 160296341Sdelphij cs_dos = strdup("CP866"); 161296341Sdelphij } else { 162160814Ssimon err(EX_NOINPUT, "%s", optarg); 163160814Ssimon } 164160814Ssimon build_iovec(&iov, &iovlen, "cs_local", cs_local, (size_t)-1); 165296341Sdelphij build_iovec(&iov, &iovlen, "cs_dos", cs_dos, (size_t)-1); 166160814Ssimon break; 167306230Sdelphij case '?': 168306230Sdelphij default: 169306230Sdelphij usage(); 170306230Sdelphij break; 171306230Sdelphij } 172306230Sdelphij } 173306230Sdelphij 174306230Sdelphij if (optind + 2 != argc) 175306230Sdelphij usage(); 176306230Sdelphij 177306230Sdelphij if (set_mask && !set_dirmask) { 178306230Sdelphij dirmask = mask; 179306230Sdelphij set_dirmask = 1; 180306230Sdelphij } 181306230Sdelphij else if (set_dirmask && !set_mask) { 182306230Sdelphij mask = dirmask; 183306230Sdelphij set_mask = 1; 184306230Sdelphij } 185296341Sdelphij 186160814Ssimon dev = argv[optind]; 187279264Sdelphij dir = argv[optind + 1]; 188160814Ssimon 189296341Sdelphij if (cs_local != NULL) { 190306230Sdelphij if (set_charset(iov, &iovlen, cs_local, cs_dos) == -1) 191160814Ssimon err(EX_OSERR, "msdosfs_iconv"); 192306230Sdelphij build_iovec_argf(&iov, &iovlen, "kiconv", ""); 193306230Sdelphij } else if (cs_dos != NULL) { 194306230Sdelphij build_iovec_argf(&iov, &iovlen, "cs_local", "ISO8859-1"); 195306230Sdelphij if (set_charset(iov, &iovlen, "ISO8859-1", cs_dos) == -1) 196306230Sdelphij err(EX_OSERR, "msdosfs_iconv"); 197296341Sdelphij build_iovec_argf(&iov, &iovlen, "kiconv", ""); 198160814Ssimon } 199279264Sdelphij 200160814Ssimon /* 201296341Sdelphij * Resolve the mountpoint with realpath(3) and remove unnecessary 202296341Sdelphij * slashes from the devicename if there are any. 203160814Ssimon */ 204306230Sdelphij (void)checkpath(dir, mntpath); 205237657Sjkim (void)rmslashes(dev, dev); 206296341Sdelphij 207296341Sdelphij if (!set_gid || !set_uid || !set_mask) { 208237657Sjkim if (stat(mntpath, &sb) == -1) 209296341Sdelphij err(EX_OSERR, "stat %s", mntpath); 210237657Sjkim 211237657Sjkim if (!set_uid) 212237657Sjkim uid = sb.st_uid; 213237657Sjkim if (!set_gid) 214296341Sdelphij gid = sb.st_gid; 215296341Sdelphij if (!set_mask) 216160814Ssimon mask = dirmask = 217296341Sdelphij sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 218296341Sdelphij } 219296341Sdelphij 220160814Ssimon build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1); 221160814Ssimon build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t)-1); 222296341Sdelphij build_iovec(&iov, &iovlen, "from", dev, (size_t)-1); 223237657Sjkim build_iovec_argf(&iov, &iovlen, "uid", "%d", uid); 224237657Sjkim build_iovec_argf(&iov, &iovlen, "gid", "%u", gid); 225237657Sjkim build_iovec_argf(&iov, &iovlen, "mask", "%u", mask); 226296341Sdelphij build_iovec_argf(&iov, &iovlen, "dirmask", "%u", dirmask); 227296341Sdelphij 228296341Sdelphij if (nmount(iov, iovlen, mntflags) < 0) 229296341Sdelphij err(1, "%s", dev); 230237657Sjkim 231296341Sdelphij exit (0); 232296341Sdelphij} 233296341Sdelphij 234296341Sdelphijgid_t 235296341Sdelphija_gid(s) 236296341Sdelphij char *s; 237296341Sdelphij{ 238296341Sdelphij struct group *gr; 239237657Sjkim char *gname; 240296341Sdelphij gid_t gid; 241237657Sjkim 242296341Sdelphij if ((gr = getgrnam(s)) != NULL) 243237657Sjkim gid = gr->gr_gid; 244296341Sdelphij else { 245296341Sdelphij for (gname = s; *s && isdigit(*s); ++s); 246296341Sdelphij if (!*s) 247237657Sjkim gid = atoi(gname); 248296341Sdelphij else 249296341Sdelphij errx(EX_NOUSER, "unknown group id: %s", gname); 250296341Sdelphij } 251296341Sdelphij return (gid); 252237657Sjkim} 253296341Sdelphij 254296341Sdelphijuid_t 255296341Sdelphija_uid(s) 256296341Sdelphij char *s; 257296341Sdelphij{ 258296341Sdelphij struct passwd *pw; 259237657Sjkim char *uname; 260296341Sdelphij uid_t uid; 261296341Sdelphij 262296341Sdelphij if ((pw = getpwnam(s)) != NULL) 263296341Sdelphij uid = pw->pw_uid; 264296341Sdelphij else { 265296341Sdelphij for (uname = s; *s && isdigit(*s); ++s); 266194206Ssimon if (!*s) 267205128Ssimon uid = atoi(uname); 268296341Sdelphij else 269296341Sdelphij errx(EX_NOUSER, "unknown user id: %s", uname); 270205128Ssimon } 271296341Sdelphij return (uid); 272296341Sdelphij} 273296341Sdelphij 274296341Sdelphijmode_t 275296341Sdelphija_mask(s) 276296341Sdelphij char *s; 277296341Sdelphij{ 278296341Sdelphij int done, rv; 279296341Sdelphij char *ep; 280296341Sdelphij 281296341Sdelphij done = 0; 282296341Sdelphij rv = -1; 283296341Sdelphij if (*s >= '0' && *s <= '7') { 284296341Sdelphij done = 1; 285296341Sdelphij rv = strtol(optarg, &ep, 8); 286296341Sdelphij } 287296341Sdelphij if (!done || rv < 0 || *ep) 288296341Sdelphij errx(EX_USAGE, "invalid file mode: %s", s); 289273399Sdelphij return (rv); 290296341Sdelphij} 291273399Sdelphij 292296341Sdelphijvoid 293296341Sdelphijusage() 294296341Sdelphij{ 295296341Sdelphij fprintf(stderr, "%s\n%s\n%s\n", 296296341Sdelphij "usage: mount_msdosfs [-9ls] [-D DOS_codepage] [-g gid] [-L locale]", 297296341Sdelphij " [-M mask] [-m mask] [-o options] [-u uid]", 298296341Sdelphij " [-W table] special node"); 299296341Sdelphij exit(EX_USAGE); 300296341Sdelphij} 301296341Sdelphij 302296341Sdelphijint 303296341Sdelphijset_charset(struct iovec *iov, int *iovlen, const char *cs_local, const char *cs_dos) 304296341Sdelphij{ 305296341Sdelphij int error; 306296341Sdelphij 307296341Sdelphij if (modfind("msdosfs_iconv") < 0) 308296341Sdelphij if (kldload("msdosfs_iconv") < 0 || modfind("msdosfs_iconv") < 0) { 309296341Sdelphij warnx("cannot find or load \"msdosfs_iconv\" kernel module"); 310296341Sdelphij return (-1); 311296341Sdelphij } 312296341Sdelphij 313296341Sdelphij build_iovec_argf(&iov, iovlen, "cs_win", ENCODING_UNICODE); 314296341Sdelphij error = kiconv_add_xlat16_cspairs(ENCODING_UNICODE, cs_local); 315296341Sdelphij if (error) 316296341Sdelphij return (-1); 317296341Sdelphij if (cs_dos != NULL) { 318296341Sdelphij error = kiconv_add_xlat16_cspairs(cs_dos, cs_local); 319205128Ssimon if (error) 320194206Ssimon return (-1); 321194206Ssimon } else { 322194206Ssimon build_iovec_argf(&iov, iovlen, "cs_dos", cs_local); 323194206Ssimon error = kiconv_add_xlat16_cspair(cs_local, cs_local, 324194206Ssimon KICONV_FROM_UPPER | KICONV_LOWER); 325194206Ssimon if (error) 326194206Ssimon return (-1); 327238405Sjkim } 328296341Sdelphij 329296341Sdelphij return (0); 330194206Ssimon} 331296341Sdelphij