mount_msdosfs.c revision 121429
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 121429 2003-10-23 16:09:20Z 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#ifdef MSDOSFSMNT_GEMDOSFS 7448002Sjkh { "gemdosfs", 0, MSDOSFSMNT_GEMDOSFS, 1 }, 7548002Sjkh#endif 7648002Sjkh { "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 }, 7748002Sjkh { "longnames", 0, MSDOSFSMNT_LONGNAME, 1 }, 7848002Sjkh { "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 }, 792892Sdfr { NULL } 802892Sdfr}; 812892Sdfr 8292882Simpstatic gid_t a_gid(char *); 8392882Simpstatic uid_t a_uid(char *); 8492882Simpstatic mode_t a_mask(char *); 8592882Simpstatic void usage(void) __dead2; 86120492Sfjoestatic int set_charset(struct msdosfs_args *); 872892Sdfr 882892Sdfrint 89121373Strhodesmain(int argc, char **argv) 902892Sdfr{ 912892Sdfr struct msdosfs_args args; 922892Sdfr struct stat sb; 93118837Strhodes int c, mntflags, set_gid, set_uid, set_mask, set_dirmask; 94120492Sfjoe char *dev, *dir, mntpath[MAXPATHLEN], *csp; 952892Sdfr 96118837Strhodes mntflags = set_gid = set_uid = set_mask = set_dirmask = 0; 972892Sdfr (void)memset(&args, '\0', sizeof(args)); 9833549Sjkh args.magic = MSDOSFS_ARGSMAGIC; 992892Sdfr 100120492Sfjoe args.cs_win = NULL; 101120492Sfjoe args.cs_dos = NULL; 102120492Sfjoe args.cs_local = NULL; 103120492Sfjoe#ifdef TRANSITION_PERIOD_HACK 104120492Sfjoe while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) { 105120492Sfjoe#else 106120492Sfjoe while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:")) != -1) { 107120492Sfjoe#endif 1082892Sdfr switch (c) { 10933549Sjkh#ifdef MSDOSFSMNT_GEMDOSFS 11033549Sjkh case 'G': 11133549Sjkh args.flags |= MSDOSFSMNT_GEMDOSFS; 11233549Sjkh break; 11333549Sjkh#endif 11433549Sjkh case 's': 11533549Sjkh args.flags |= MSDOSFSMNT_SHORTNAME; 11633549Sjkh break; 11733549Sjkh case 'l': 11833549Sjkh args.flags |= MSDOSFSMNT_LONGNAME; 11933549Sjkh break; 12033549Sjkh case '9': 12133549Sjkh args.flags |= MSDOSFSMNT_NOWIN95; 12233549Sjkh break; 1232892Sdfr case 'u': 1242892Sdfr args.uid = a_uid(optarg); 1252892Sdfr set_uid = 1; 1262892Sdfr break; 1272892Sdfr case 'g': 1282892Sdfr args.gid = a_gid(optarg); 1292892Sdfr set_gid = 1; 1302892Sdfr break; 1312892Sdfr case 'm': 1322892Sdfr args.mask = a_mask(optarg); 1332892Sdfr set_mask = 1; 1342892Sdfr break; 135118837Strhodes case 'M': 136118837Strhodes args.dirmask = a_mask(optarg); 137118837Strhodes set_dirmask = 1; 138118837Strhodes break; 13933761Sache case 'L': 140120492Sfjoe if (setlocale(LC_CTYPE, optarg) == NULL) 141120492Sfjoe err(EX_CONFIG, "%s", optarg); 142120492Sfjoe csp = strchr(optarg,'.'); 143120492Sfjoe if (!csp) 144120492Sfjoe err(EX_CONFIG, "%s", optarg); 145120492Sfjoe args.cs_local = malloc(ICONV_CSNMAXLEN); 146120492Sfjoe if (args.cs_local == NULL) 147120492Sfjoe err(EX_OSERR, "malloc()"); 148120492Sfjoe strncpy(args.cs_local, 149120492Sfjoe kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT), 150120492Sfjoe ICONV_CSNMAXLEN); 15133761Sache break; 152120492Sfjoe case 'D': 153120492Sfjoe args.cs_dos = malloc(ICONV_CSNMAXLEN); 154120492Sfjoe if (args.cs_dos == NULL) 155120492Sfjoe err(EX_OSERR, "malloc()"); 156120492Sfjoe strncpy(args.cs_dos, optarg, ICONV_CSNMAXLEN); 15733749Sache break; 1582892Sdfr case 'o': 15948002Sjkh getmntopts(optarg, mopts, &mntflags, &args.flags); 1602892Sdfr break; 161120492Sfjoe#ifdef TRANSITION_PERIOD_HACK 162120492Sfjoe case 'W': 163120492Sfjoe args.cs_local = malloc(ICONV_CSNMAXLEN); 164120492Sfjoe if (args.cs_local == NULL) 165120492Sfjoe err(EX_OSERR, "malloc()"); 166120492Sfjoe args.cs_dos = malloc(ICONV_CSNMAXLEN); 167120492Sfjoe if (args.cs_dos == NULL) 168120492Sfjoe err(EX_OSERR, "malloc()"); 169120492Sfjoe if (strcmp(optarg, "iso22dos") == 0) { 170120492Sfjoe strcpy(args.cs_local, "ISO8859-2"); 171120492Sfjoe strcpy(args.cs_dos, "CP852"); 172120492Sfjoe } else if (strcmp(optarg, "iso72dos") == 0) { 173120492Sfjoe strcpy(args.cs_local, "ISO8859-7"); 174120492Sfjoe strcpy(args.cs_dos, "CP737"); 175120492Sfjoe } else if (strcmp(optarg, "koi2dos") == 0) { 176120492Sfjoe strcpy(args.cs_local, "KOI8-R"); 177120492Sfjoe strcpy(args.cs_dos, "CP866"); 178120492Sfjoe } else if (strcmp(optarg, "koi8u2dos") == 0) { 179120492Sfjoe strcpy(args.cs_local, "KOI8-U"); 180120492Sfjoe strcpy(args.cs_dos, "CP866"); 181120492Sfjoe } else { 182120492Sfjoe err(EX_NOINPUT, "%s", optarg); 183120492Sfjoe } 184120492Sfjoe break; 185120492Sfjoe#endif /* TRANSITION_PERIOD_HACK */ 1862892Sdfr case '?': 1872892Sdfr default: 1882892Sdfr usage(); 1892892Sdfr break; 1902892Sdfr } 1912892Sdfr } 1922892Sdfr 1932892Sdfr if (optind + 2 != argc) 1942892Sdfr usage(); 1952892Sdfr 196118837Strhodes if (set_mask && !set_dirmask) { 197118837Strhodes args.dirmask = args.mask; 198118837Strhodes set_dirmask = 1; 199118837Strhodes } 200118837Strhodes else if (set_dirmask && !set_mask) { 201118837Strhodes args.mask = args.dirmask; 202118837Strhodes set_mask = 1; 203118837Strhodes } 204118837Strhodes 2052892Sdfr dev = argv[optind]; 2062892Sdfr dir = argv[optind + 1]; 2072892Sdfr 208120492Sfjoe if (args.cs_local) { 209120492Sfjoe if (set_charset(&args) == -1) 210120492Sfjoe err(EX_OSERR, "msdosfs_iconv"); 211120492Sfjoe args.flags |= MSDOSFSMNT_KICONV; 212120492Sfjoe } else if (args.cs_dos) { 213120492Sfjoe if ((args.cs_local = malloc(ICONV_CSNMAXLEN)) == NULL) 214120492Sfjoe err(EX_OSERR, "malloc()"); 215120492Sfjoe strcpy(args.cs_local, "ISO8859-1"); 216120492Sfjoe if (set_charset(&args) == -1) 217120492Sfjoe err(EX_OSERR, "msdosfs_iconv"); 218120492Sfjoe args.flags |= MSDOSFSMNT_KICONV; 219120492Sfjoe } 220120492Sfjoe 22152055Sphk /* 22252055Sphk * Resolve the mountpoint with realpath(3) and remove unnecessary 22352055Sphk * slashes from the devicename if there are any. 22452055Sphk */ 22552055Sphk (void)checkpath(dir, mntpath); 22652055Sphk (void)rmslashes(dev, dev); 22752055Sphk 2282892Sdfr args.fspec = dev; 2292892Sdfr args.export.ex_root = -2; /* unchecked anyway on DOS fs */ 2302892Sdfr if (mntflags & MNT_RDONLY) 2312892Sdfr args.export.ex_flags = MNT_EXRDONLY; 2322892Sdfr else 2332892Sdfr args.export.ex_flags = 0; 2342892Sdfr if (!set_gid || !set_uid || !set_mask) { 23552055Sphk if (stat(mntpath, &sb) == -1) 23652055Sphk err(EX_OSERR, "stat %s", mntpath); 2372892Sdfr 2382892Sdfr if (!set_uid) 2392892Sdfr args.uid = sb.st_uid; 2402892Sdfr if (!set_gid) 2412892Sdfr args.gid = sb.st_gid; 2422892Sdfr if (!set_mask) 243118837Strhodes args.mask = args.dirmask = 244118837Strhodes sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 2452892Sdfr } 2462892Sdfr 247101270Smux if (mount("msdosfs", mntpath, mntflags, &args) < 0) 24815771Swollman err(EX_OSERR, "%s", dev); 2492892Sdfr 2502892Sdfr exit (0); 2512892Sdfr} 2522892Sdfr 2532892Sdfrgid_t 2542892Sdfra_gid(s) 2552892Sdfr char *s; 2562892Sdfr{ 2572892Sdfr struct group *gr; 2582892Sdfr char *gname; 2592892Sdfr gid_t gid; 2602892Sdfr 2612892Sdfr if ((gr = getgrnam(s)) != NULL) 2622892Sdfr gid = gr->gr_gid; 2632892Sdfr else { 2642892Sdfr for (gname = s; *s && isdigit(*s); ++s); 2652892Sdfr if (!*s) 2662892Sdfr gid = atoi(gname); 2672892Sdfr else 26815771Swollman errx(EX_NOUSER, "unknown group id: %s", gname); 2692892Sdfr } 2702892Sdfr return (gid); 2712892Sdfr} 2722892Sdfr 2732892Sdfruid_t 2742892Sdfra_uid(s) 2752892Sdfr char *s; 2762892Sdfr{ 2772892Sdfr struct passwd *pw; 2782892Sdfr char *uname; 2792892Sdfr uid_t uid; 2802892Sdfr 2812892Sdfr if ((pw = getpwnam(s)) != NULL) 2822892Sdfr uid = pw->pw_uid; 2832892Sdfr else { 2842892Sdfr for (uname = s; *s && isdigit(*s); ++s); 2852892Sdfr if (!*s) 2862892Sdfr uid = atoi(uname); 2872892Sdfr else 28815771Swollman errx(EX_NOUSER, "unknown user id: %s", uname); 2892892Sdfr } 2902892Sdfr return (uid); 2912892Sdfr} 2922892Sdfr 2932892Sdfrmode_t 2942892Sdfra_mask(s) 2952892Sdfr char *s; 2962892Sdfr{ 2972892Sdfr int done, rv; 2982892Sdfr char *ep; 2992892Sdfr 3002892Sdfr done = 0; 30133549Sjkh rv = -1; 3022892Sdfr if (*s >= '0' && *s <= '7') { 3032892Sdfr done = 1; 3042892Sdfr rv = strtol(optarg, &ep, 8); 3052892Sdfr } 3062892Sdfr if (!done || rv < 0 || *ep) 30715771Swollman errx(EX_USAGE, "invalid file mode: %s", s); 3082892Sdfr return (rv); 3092892Sdfr} 3102892Sdfr 3112892Sdfrvoid 3122892Sdfrusage() 3132892Sdfr{ 314120492Sfjoe#ifdef TRANSITION_PERIOD_HACK 315121007Sfjoe fprintf(stderr, "%s\n%s\n%s\n", 316121429Strhodes "usage: mount_msdosfs [-9ls] [-D DOS_codepage] [-g gid] [-L locale]", 317121429Strhodes " [-M mask] [-m mask] [-o options] [-u uid]", 318121429Strhodes " [-W table] special node"); 319120492Sfjoe#else 320121429Strhodes fprintf(stderr, "%s\n%s\n%s\n", 321121429Strhodes "usage: mount_msdosfs [-9ls] [-D DOS_codepage] [-g gid] [-L locale]", 322121429Strhodes " [-M mask] [-m mask] [-o options] [-u uid]", 323121429Strhodes " special node"); 324120492Sfjoe#endif 32515771Swollman exit(EX_USAGE); 3262892Sdfr} 32733749Sache 328120492Sfjoeint 329120492Sfjoeset_charset(struct msdosfs_args *args) 33033749Sache{ 331120492Sfjoe int error; 33233749Sache 333120492Sfjoe if (modfind("msdosfs_iconv") < 0) 334120492Sfjoe if (kldload("msdosfs_iconv") < 0 || modfind("msdosfs_iconv") < 0) { 335120492Sfjoe warnx( "cannot find or load \"msdosfs_iconv\" kernel module"); 336120492Sfjoe return (-1); 337120492Sfjoe } 338120492Sfjoe 339120492Sfjoe if ((args->cs_win = malloc(ICONV_CSNMAXLEN)) == NULL) 340120492Sfjoe return (-1); 341120492Sfjoe strncpy(args->cs_win, ENCODING_UNICODE, ICONV_CSNMAXLEN); 342120492Sfjoe error = kiconv_add_xlat16_cspair(args->cs_win, args->cs_local, 0); 343120492Sfjoe if (error) 344120492Sfjoe return (-1); 345120492Sfjoe error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_win, 0); 346120492Sfjoe if (error) 347120492Sfjoe return (-1); 348120492Sfjoe if (args->cs_dos) { 349120492Sfjoe error = kiconv_add_xlat16_cspair(args->cs_dos, args->cs_local, KICONV_FROM_UPPER); 350120492Sfjoe if (error) 351120492Sfjoe return (-1); 352120492Sfjoe error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_dos, KICONV_LOWER); 353120492Sfjoe if (error) 354120492Sfjoe return (-1); 355120492Sfjoe } else { 356120492Sfjoe if ((args->cs_dos = malloc(ICONV_CSNMAXLEN)) == NULL) 357120492Sfjoe return (-1); 358120492Sfjoe strcpy(args->cs_dos, args->cs_local); 359120492Sfjoe error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_local, 360120492Sfjoe KICONV_FROM_UPPER | KICONV_LOWER); 361120492Sfjoe if (error) 362120492Sfjoe return (-1); 36333749Sache } 36433761Sache 365120492Sfjoe return (0); 36633761Sache} 367