mount_msdosfs.c revision 134565
133549Sjkh/* $NetBSD: mount_msdos.c,v 1.18 1997/09/16 12:24:18 lukem Exp $ */ 233549Sjkh 32892Sdfr/* 42892Sdfr * Copyright (c) 1994 Christopher G. Demetriou 52892Sdfr * All rights reserved. 62892Sdfr * 72892Sdfr * Redistribution and use in source and binary forms, with or without 82892Sdfr * modification, are permitted provided that the following conditions 92892Sdfr * are met: 102892Sdfr * 1. Redistributions of source code must retain the above copyright 112892Sdfr * notice, this list of conditions and the following disclaimer. 122892Sdfr * 2. Redistributions in binary form must reproduce the above copyright 132892Sdfr * notice, this list of conditions and the following disclaimer in the 142892Sdfr * documentation and/or other materials provided with the distribution. 152892Sdfr * 3. All advertising materials mentioning features or use of this software 162892Sdfr * must display the following acknowledgement: 172892Sdfr * This product includes software developed by Christopher G. Demetriou. 182892Sdfr * 4. The name of the author may not be used to endorse or promote products 192892Sdfr * derived from this software without specific prior written permission 202892Sdfr * 212892Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 222892Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 232892Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 242892Sdfr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 252892Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 262892Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 272892Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 282892Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 292892Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 302892Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 312892Sdfr */ 322892Sdfr 332892Sdfr#ifndef lint 3415771Swollmanstatic const char rcsid[] = 3550476Speter "$FreeBSD: head/sbin/mount_msdosfs/mount_msdosfs.c 134565 2004-08-31 05:19:57Z trhodes $"; 362892Sdfr#endif /* not lint */ 372892Sdfr 382892Sdfr#include <sys/param.h> 392892Sdfr#include <sys/mount.h> 402892Sdfr#include <sys/stat.h> 41120492Sfjoe#include <sys/iconv.h> 42121363Strhodes#include <sys/linker.h> 43121429Strhodes#include <sys/module.h> 4423335Sbde 4577162Sru#include <fs/msdosfs/msdosfsmount.h> 4623335Sbde 472892Sdfr#include <ctype.h> 482892Sdfr#include <err.h> 492892Sdfr#include <grp.h> 5033761Sache#include <locale.h> 512892Sdfr#include <pwd.h> 522892Sdfr#include <stdio.h> 5355613Sache/* must be after stdio to declare fparseln */ 5455613Sache#include <libutil.h> 552892Sdfr#include <stdlib.h> 562892Sdfr#include <string.h> 5715771Swollman#include <sysexits.h> 582892Sdfr#include <unistd.h> 59121429Strhodes 602892Sdfr#include "mntopts.h" 612892Sdfr 62120492Sfjoe#define TRANSITION_PERIOD_HACK 63120492Sfjoe 6448002Sjkh/* 6548002Sjkh * XXX - no way to specify "foo=<bar>"-type options; that's what we'd 66121007Sfjoe * want for "-u", "-g", "-m", "-M", "-L", "-D", and "-W". 6748002Sjkh */ 6815771Swollmanstatic struct mntopt mopts[] = { 692892Sdfr MOPT_STDOPTS, 7028731Sbde MOPT_FORCE, 7128731Sbde MOPT_SYNC, 7228731Sbde MOPT_UPDATE, 7348002Sjkh { "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 }, 7448002Sjkh { "longnames", 0, MSDOSFSMNT_LONGNAME, 1 }, 7548002Sjkh { "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 }, 762892Sdfr { NULL } 772892Sdfr}; 782892Sdfr 7992882Simpstatic gid_t a_gid(char *); 8092882Simpstatic uid_t a_uid(char *); 8192882Simpstatic mode_t a_mask(char *); 8292882Simpstatic void usage(void) __dead2; 83120492Sfjoestatic int set_charset(struct msdosfs_args *); 842892Sdfr 852892Sdfrint 86121373Strhodesmain(int argc, char **argv) 872892Sdfr{ 882892Sdfr struct msdosfs_args args; 892892Sdfr struct stat sb; 90118837Strhodes int c, mntflags, set_gid, set_uid, set_mask, set_dirmask; 91120492Sfjoe char *dev, *dir, mntpath[MAXPATHLEN], *csp; 922892Sdfr 93118837Strhodes mntflags = set_gid = set_uid = set_mask = set_dirmask = 0; 942892Sdfr (void)memset(&args, '\0', sizeof(args)); 9533549Sjkh args.magic = MSDOSFS_ARGSMAGIC; 962892Sdfr 97120492Sfjoe args.cs_win = NULL; 98120492Sfjoe args.cs_dos = NULL; 99120492Sfjoe args.cs_local = NULL; 100120492Sfjoe#ifdef TRANSITION_PERIOD_HACK 101120492Sfjoe while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) { 102120492Sfjoe#else 103120492Sfjoe while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:")) != -1) { 104120492Sfjoe#endif 1052892Sdfr switch (c) { 10633549Sjkh case 's': 10733549Sjkh args.flags |= MSDOSFSMNT_SHORTNAME; 10833549Sjkh break; 10933549Sjkh case 'l': 11033549Sjkh args.flags |= MSDOSFSMNT_LONGNAME; 11133549Sjkh break; 11233549Sjkh case '9': 11333549Sjkh args.flags |= MSDOSFSMNT_NOWIN95; 11433549Sjkh break; 1152892Sdfr case 'u': 1162892Sdfr args.uid = a_uid(optarg); 1172892Sdfr set_uid = 1; 1182892Sdfr break; 1192892Sdfr case 'g': 1202892Sdfr args.gid = a_gid(optarg); 1212892Sdfr set_gid = 1; 1222892Sdfr break; 1232892Sdfr case 'm': 1242892Sdfr args.mask = a_mask(optarg); 1252892Sdfr set_mask = 1; 1262892Sdfr break; 127118837Strhodes case 'M': 128118837Strhodes args.dirmask = a_mask(optarg); 129118837Strhodes set_dirmask = 1; 130118837Strhodes break; 13133761Sache case 'L': 132120492Sfjoe if (setlocale(LC_CTYPE, optarg) == NULL) 133120492Sfjoe err(EX_CONFIG, "%s", optarg); 134120492Sfjoe csp = strchr(optarg,'.'); 135120492Sfjoe if (!csp) 136120492Sfjoe err(EX_CONFIG, "%s", optarg); 137120492Sfjoe args.cs_local = malloc(ICONV_CSNMAXLEN); 138120492Sfjoe if (args.cs_local == NULL) 139120492Sfjoe err(EX_OSERR, "malloc()"); 140120492Sfjoe strncpy(args.cs_local, 141120492Sfjoe kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT), 142120492Sfjoe ICONV_CSNMAXLEN); 14333761Sache break; 144120492Sfjoe case 'D': 145120492Sfjoe args.cs_dos = malloc(ICONV_CSNMAXLEN); 146120492Sfjoe if (args.cs_dos == NULL) 147120492Sfjoe err(EX_OSERR, "malloc()"); 148120492Sfjoe strncpy(args.cs_dos, optarg, ICONV_CSNMAXLEN); 14933749Sache break; 1502892Sdfr case 'o': 15148002Sjkh getmntopts(optarg, mopts, &mntflags, &args.flags); 1522892Sdfr break; 153120492Sfjoe#ifdef TRANSITION_PERIOD_HACK 154120492Sfjoe case 'W': 155120492Sfjoe args.cs_local = malloc(ICONV_CSNMAXLEN); 156120492Sfjoe if (args.cs_local == NULL) 157120492Sfjoe err(EX_OSERR, "malloc()"); 158120492Sfjoe args.cs_dos = malloc(ICONV_CSNMAXLEN); 159120492Sfjoe if (args.cs_dos == NULL) 160120492Sfjoe err(EX_OSERR, "malloc()"); 161120492Sfjoe if (strcmp(optarg, "iso22dos") == 0) { 162120492Sfjoe strcpy(args.cs_local, "ISO8859-2"); 163120492Sfjoe strcpy(args.cs_dos, "CP852"); 164120492Sfjoe } else if (strcmp(optarg, "iso72dos") == 0) { 165120492Sfjoe strcpy(args.cs_local, "ISO8859-7"); 166120492Sfjoe strcpy(args.cs_dos, "CP737"); 167120492Sfjoe } else if (strcmp(optarg, "koi2dos") == 0) { 168120492Sfjoe strcpy(args.cs_local, "KOI8-R"); 169120492Sfjoe strcpy(args.cs_dos, "CP866"); 170120492Sfjoe } else if (strcmp(optarg, "koi8u2dos") == 0) { 171120492Sfjoe strcpy(args.cs_local, "KOI8-U"); 172120492Sfjoe strcpy(args.cs_dos, "CP866"); 173120492Sfjoe } else { 174120492Sfjoe err(EX_NOINPUT, "%s", optarg); 175120492Sfjoe } 176120492Sfjoe break; 177120492Sfjoe#endif /* TRANSITION_PERIOD_HACK */ 1782892Sdfr case '?': 1792892Sdfr default: 1802892Sdfr usage(); 1812892Sdfr break; 1822892Sdfr } 1832892Sdfr } 1842892Sdfr 1852892Sdfr if (optind + 2 != argc) 1862892Sdfr usage(); 1872892Sdfr 188118837Strhodes if (set_mask && !set_dirmask) { 189118837Strhodes args.dirmask = args.mask; 190118837Strhodes set_dirmask = 1; 191118837Strhodes } 192118837Strhodes else if (set_dirmask && !set_mask) { 193118837Strhodes args.mask = args.dirmask; 194118837Strhodes set_mask = 1; 195118837Strhodes } 196118837Strhodes 1972892Sdfr dev = argv[optind]; 1982892Sdfr dir = argv[optind + 1]; 1992892Sdfr 200120492Sfjoe if (args.cs_local) { 201120492Sfjoe if (set_charset(&args) == -1) 202120492Sfjoe err(EX_OSERR, "msdosfs_iconv"); 203120492Sfjoe args.flags |= MSDOSFSMNT_KICONV; 204120492Sfjoe } else if (args.cs_dos) { 205120492Sfjoe if ((args.cs_local = malloc(ICONV_CSNMAXLEN)) == NULL) 206120492Sfjoe err(EX_OSERR, "malloc()"); 207120492Sfjoe strcpy(args.cs_local, "ISO8859-1"); 208120492Sfjoe if (set_charset(&args) == -1) 209120492Sfjoe err(EX_OSERR, "msdosfs_iconv"); 210120492Sfjoe args.flags |= MSDOSFSMNT_KICONV; 211120492Sfjoe } 212120492Sfjoe 21352055Sphk /* 21452055Sphk * Resolve the mountpoint with realpath(3) and remove unnecessary 21552055Sphk * slashes from the devicename if there are any. 21652055Sphk */ 21752055Sphk (void)checkpath(dir, mntpath); 21852055Sphk (void)rmslashes(dev, dev); 21952055Sphk 2202892Sdfr args.fspec = dev; 2212892Sdfr args.export.ex_root = -2; /* unchecked anyway on DOS fs */ 2222892Sdfr if (mntflags & MNT_RDONLY) 2232892Sdfr args.export.ex_flags = MNT_EXRDONLY; 2242892Sdfr else 2252892Sdfr args.export.ex_flags = 0; 2262892Sdfr if (!set_gid || !set_uid || !set_mask) { 22752055Sphk if (stat(mntpath, &sb) == -1) 22852055Sphk err(EX_OSERR, "stat %s", mntpath); 2292892Sdfr 2302892Sdfr if (!set_uid) 2312892Sdfr args.uid = sb.st_uid; 2322892Sdfr if (!set_gid) 2332892Sdfr args.gid = sb.st_gid; 2342892Sdfr if (!set_mask) 235118837Strhodes args.mask = args.dirmask = 236118837Strhodes sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 2372892Sdfr } 2382892Sdfr 239101270Smux if (mount("msdosfs", mntpath, mntflags, &args) < 0) 24015771Swollman err(EX_OSERR, "%s", dev); 2412892Sdfr 2422892Sdfr exit (0); 2432892Sdfr} 2442892Sdfr 2452892Sdfrgid_t 2462892Sdfra_gid(s) 2472892Sdfr char *s; 2482892Sdfr{ 2492892Sdfr struct group *gr; 2502892Sdfr char *gname; 2512892Sdfr gid_t gid; 2522892Sdfr 2532892Sdfr if ((gr = getgrnam(s)) != NULL) 2542892Sdfr gid = gr->gr_gid; 2552892Sdfr else { 2562892Sdfr for (gname = s; *s && isdigit(*s); ++s); 2572892Sdfr if (!*s) 2582892Sdfr gid = atoi(gname); 2592892Sdfr else 26015771Swollman errx(EX_NOUSER, "unknown group id: %s", gname); 2612892Sdfr } 2622892Sdfr return (gid); 2632892Sdfr} 2642892Sdfr 2652892Sdfruid_t 2662892Sdfra_uid(s) 2672892Sdfr char *s; 2682892Sdfr{ 2692892Sdfr struct passwd *pw; 2702892Sdfr char *uname; 2712892Sdfr uid_t uid; 2722892Sdfr 2732892Sdfr if ((pw = getpwnam(s)) != NULL) 2742892Sdfr uid = pw->pw_uid; 2752892Sdfr else { 2762892Sdfr for (uname = s; *s && isdigit(*s); ++s); 2772892Sdfr if (!*s) 2782892Sdfr uid = atoi(uname); 2792892Sdfr else 28015771Swollman errx(EX_NOUSER, "unknown user id: %s", uname); 2812892Sdfr } 2822892Sdfr return (uid); 2832892Sdfr} 2842892Sdfr 2852892Sdfrmode_t 2862892Sdfra_mask(s) 2872892Sdfr char *s; 2882892Sdfr{ 2892892Sdfr int done, rv; 2902892Sdfr char *ep; 2912892Sdfr 2922892Sdfr done = 0; 29333549Sjkh rv = -1; 2942892Sdfr if (*s >= '0' && *s <= '7') { 2952892Sdfr done = 1; 2962892Sdfr rv = strtol(optarg, &ep, 8); 2972892Sdfr } 2982892Sdfr if (!done || rv < 0 || *ep) 29915771Swollman errx(EX_USAGE, "invalid file mode: %s", s); 3002892Sdfr return (rv); 3012892Sdfr} 3022892Sdfr 3032892Sdfrvoid 3042892Sdfrusage() 3052892Sdfr{ 306120492Sfjoe#ifdef TRANSITION_PERIOD_HACK 307121007Sfjoe fprintf(stderr, "%s\n%s\n%s\n", 308121429Strhodes "usage: mount_msdosfs [-9ls] [-D DOS_codepage] [-g gid] [-L locale]", 309121429Strhodes " [-M mask] [-m mask] [-o options] [-u uid]", 310121429Strhodes " [-W table] special node"); 311120492Sfjoe#else 312121429Strhodes fprintf(stderr, "%s\n%s\n%s\n", 313121429Strhodes "usage: mount_msdosfs [-9ls] [-D DOS_codepage] [-g gid] [-L locale]", 314121429Strhodes " [-M mask] [-m mask] [-o options] [-u uid]", 315121429Strhodes " special node"); 316120492Sfjoe#endif 31715771Swollman exit(EX_USAGE); 3182892Sdfr} 31933749Sache 320120492Sfjoeint 321120492Sfjoeset_charset(struct msdosfs_args *args) 32233749Sache{ 323120492Sfjoe int error; 32433749Sache 325120492Sfjoe if (modfind("msdosfs_iconv") < 0) 326120492Sfjoe if (kldload("msdosfs_iconv") < 0 || modfind("msdosfs_iconv") < 0) { 327134565Strhodes warnx("cannot find or load \"msdosfs_iconv\" kernel module"); 328120492Sfjoe return (-1); 329120492Sfjoe } 330120492Sfjoe 331120492Sfjoe if ((args->cs_win = malloc(ICONV_CSNMAXLEN)) == NULL) 332120492Sfjoe return (-1); 333120492Sfjoe strncpy(args->cs_win, ENCODING_UNICODE, ICONV_CSNMAXLEN); 334123293Sfjoe error = kiconv_add_xlat16_cspairs(args->cs_win, args->cs_local); 335120492Sfjoe if (error) 336120492Sfjoe return (-1); 337120492Sfjoe if (args->cs_dos) { 338123293Sfjoe error = kiconv_add_xlat16_cspairs(args->cs_dos, args->cs_local); 339120492Sfjoe if (error) 340120492Sfjoe return (-1); 341120492Sfjoe } else { 342120492Sfjoe if ((args->cs_dos = malloc(ICONV_CSNMAXLEN)) == NULL) 343120492Sfjoe return (-1); 344120492Sfjoe strcpy(args->cs_dos, args->cs_local); 345120492Sfjoe error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_local, 346120492Sfjoe KICONV_FROM_UPPER | KICONV_LOWER); 347120492Sfjoe if (error) 348120492Sfjoe return (-1); 34933749Sache } 35033761Sache 351120492Sfjoe return (0); 35233761Sache} 353