mount_msdosfs.c revision 121363
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 121363 2003-10-22 20:11:42Z trhodes $"; 362892Sdfr#endif /* not lint */ 372892Sdfr 382892Sdfr#include <sys/param.h> 392892Sdfr#include <sys/mount.h> 402892Sdfr#include <sys/stat.h> 41120492Sfjoe#include <sys/module.h> 42120492Sfjoe#include <sys/iconv.h> 43121363Strhodes#include <sys/linker.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> 592892Sdfr#include "mntopts.h" 602892Sdfr 61120492Sfjoe#define TRANSITION_PERIOD_HACK 62120492Sfjoe 6348002Sjkh/* 6448002Sjkh * XXX - no way to specify "foo=<bar>"-type options; that's what we'd 65121007Sfjoe * want for "-u", "-g", "-m", "-M", "-L", "-D", and "-W". 6648002Sjkh */ 6715771Swollmanstatic struct mntopt mopts[] = { 682892Sdfr MOPT_STDOPTS, 6928731Sbde MOPT_FORCE, 7028731Sbde MOPT_SYNC, 7128731Sbde MOPT_UPDATE, 7248002Sjkh#ifdef MSDOSFSMNT_GEMDOSFS 7348002Sjkh { "gemdosfs", 0, MSDOSFSMNT_GEMDOSFS, 1 }, 7448002Sjkh#endif 7548002Sjkh { "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 }, 7648002Sjkh { "longnames", 0, MSDOSFSMNT_LONGNAME, 1 }, 7748002Sjkh { "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 }, 782892Sdfr { NULL } 792892Sdfr}; 802892Sdfr 8192882Simpstatic gid_t a_gid(char *); 8292882Simpstatic uid_t a_uid(char *); 8392882Simpstatic mode_t a_mask(char *); 8492882Simpstatic void usage(void) __dead2; 85120492Sfjoestatic int set_charset(struct msdosfs_args *); 862892Sdfr 872892Sdfrint 882892Sdfrmain(argc, argv) 892892Sdfr int argc; 902892Sdfr char **argv; 912892Sdfr{ 922892Sdfr struct msdosfs_args args; 932892Sdfr struct stat sb; 94118837Strhodes int c, mntflags, set_gid, set_uid, set_mask, set_dirmask; 95120492Sfjoe char *dev, *dir, mntpath[MAXPATHLEN], *csp; 962892Sdfr 97118837Strhodes mntflags = set_gid = set_uid = set_mask = set_dirmask = 0; 982892Sdfr (void)memset(&args, '\0', sizeof(args)); 9933549Sjkh args.magic = MSDOSFS_ARGSMAGIC; 1002892Sdfr 101120492Sfjoe args.cs_win = NULL; 102120492Sfjoe args.cs_dos = NULL; 103120492Sfjoe args.cs_local = NULL; 104120492Sfjoe#ifdef TRANSITION_PERIOD_HACK 105120492Sfjoe while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) { 106120492Sfjoe#else 107120492Sfjoe while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:")) != -1) { 108120492Sfjoe#endif 1092892Sdfr switch (c) { 11033549Sjkh#ifdef MSDOSFSMNT_GEMDOSFS 11133549Sjkh case 'G': 11233549Sjkh args.flags |= MSDOSFSMNT_GEMDOSFS; 11333549Sjkh break; 11433549Sjkh#endif 11533549Sjkh case 's': 11633549Sjkh args.flags |= MSDOSFSMNT_SHORTNAME; 11733549Sjkh break; 11833549Sjkh case 'l': 11933549Sjkh args.flags |= MSDOSFSMNT_LONGNAME; 12033549Sjkh break; 12133549Sjkh case '9': 12233549Sjkh args.flags |= MSDOSFSMNT_NOWIN95; 12333549Sjkh break; 1242892Sdfr case 'u': 1252892Sdfr args.uid = a_uid(optarg); 1262892Sdfr set_uid = 1; 1272892Sdfr break; 1282892Sdfr case 'g': 1292892Sdfr args.gid = a_gid(optarg); 1302892Sdfr set_gid = 1; 1312892Sdfr break; 1322892Sdfr case 'm': 1332892Sdfr args.mask = a_mask(optarg); 1342892Sdfr set_mask = 1; 1352892Sdfr break; 136118837Strhodes case 'M': 137118837Strhodes args.dirmask = a_mask(optarg); 138118837Strhodes set_dirmask = 1; 139118837Strhodes break; 14033761Sache case 'L': 141120492Sfjoe if (setlocale(LC_CTYPE, optarg) == NULL) 142120492Sfjoe err(EX_CONFIG, "%s", optarg); 143120492Sfjoe csp = strchr(optarg,'.'); 144120492Sfjoe if (!csp) 145120492Sfjoe err(EX_CONFIG, "%s", optarg); 146120492Sfjoe args.cs_local = malloc(ICONV_CSNMAXLEN); 147120492Sfjoe if (args.cs_local == NULL) 148120492Sfjoe err(EX_OSERR, "malloc()"); 149120492Sfjoe strncpy(args.cs_local, 150120492Sfjoe kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT), 151120492Sfjoe ICONV_CSNMAXLEN); 15233761Sache break; 153120492Sfjoe case 'D': 154120492Sfjoe args.cs_dos = malloc(ICONV_CSNMAXLEN); 155120492Sfjoe if (args.cs_dos == NULL) 156120492Sfjoe err(EX_OSERR, "malloc()"); 157120492Sfjoe strncpy(args.cs_dos, optarg, ICONV_CSNMAXLEN); 15833749Sache break; 1592892Sdfr case 'o': 16048002Sjkh getmntopts(optarg, mopts, &mntflags, &args.flags); 1612892Sdfr break; 162120492Sfjoe#ifdef TRANSITION_PERIOD_HACK 163120492Sfjoe case 'W': 164120492Sfjoe args.cs_local = malloc(ICONV_CSNMAXLEN); 165120492Sfjoe if (args.cs_local == NULL) 166120492Sfjoe err(EX_OSERR, "malloc()"); 167120492Sfjoe args.cs_dos = malloc(ICONV_CSNMAXLEN); 168120492Sfjoe if (args.cs_dos == NULL) 169120492Sfjoe err(EX_OSERR, "malloc()"); 170120492Sfjoe if (strcmp(optarg, "iso22dos") == 0) { 171120492Sfjoe strcpy(args.cs_local, "ISO8859-2"); 172120492Sfjoe strcpy(args.cs_dos, "CP852"); 173120492Sfjoe } else if (strcmp(optarg, "iso72dos") == 0) { 174120492Sfjoe strcpy(args.cs_local, "ISO8859-7"); 175120492Sfjoe strcpy(args.cs_dos, "CP737"); 176120492Sfjoe } else if (strcmp(optarg, "koi2dos") == 0) { 177120492Sfjoe strcpy(args.cs_local, "KOI8-R"); 178120492Sfjoe strcpy(args.cs_dos, "CP866"); 179120492Sfjoe } else if (strcmp(optarg, "koi8u2dos") == 0) { 180120492Sfjoe strcpy(args.cs_local, "KOI8-U"); 181120492Sfjoe strcpy(args.cs_dos, "CP866"); 182120492Sfjoe } else { 183120492Sfjoe err(EX_NOINPUT, "%s", optarg); 184120492Sfjoe } 185120492Sfjoe break; 186120492Sfjoe#endif /* TRANSITION_PERIOD_HACK */ 1872892Sdfr case '?': 1882892Sdfr default: 1892892Sdfr usage(); 1902892Sdfr break; 1912892Sdfr } 1922892Sdfr } 1932892Sdfr 1942892Sdfr if (optind + 2 != argc) 1952892Sdfr usage(); 1962892Sdfr 197118837Strhodes if (set_mask && !set_dirmask) { 198118837Strhodes args.dirmask = args.mask; 199118837Strhodes set_dirmask = 1; 200118837Strhodes } 201118837Strhodes else if (set_dirmask && !set_mask) { 202118837Strhodes args.mask = args.dirmask; 203118837Strhodes set_mask = 1; 204118837Strhodes } 205118837Strhodes 2062892Sdfr dev = argv[optind]; 2072892Sdfr dir = argv[optind + 1]; 2082892Sdfr 209120492Sfjoe if (args.cs_local) { 210120492Sfjoe if (set_charset(&args) == -1) 211120492Sfjoe err(EX_OSERR, "msdosfs_iconv"); 212120492Sfjoe args.flags |= MSDOSFSMNT_KICONV; 213120492Sfjoe } else if (args.cs_dos) { 214120492Sfjoe if ((args.cs_local = malloc(ICONV_CSNMAXLEN)) == NULL) 215120492Sfjoe err(EX_OSERR, "malloc()"); 216120492Sfjoe strcpy(args.cs_local, "ISO8859-1"); 217120492Sfjoe if (set_charset(&args) == -1) 218120492Sfjoe err(EX_OSERR, "msdosfs_iconv"); 219120492Sfjoe args.flags |= MSDOSFSMNT_KICONV; 220120492Sfjoe } 221120492Sfjoe 22252055Sphk /* 22352055Sphk * Resolve the mountpoint with realpath(3) and remove unnecessary 22452055Sphk * slashes from the devicename if there are any. 22552055Sphk */ 22652055Sphk (void)checkpath(dir, mntpath); 22752055Sphk (void)rmslashes(dev, dev); 22852055Sphk 2292892Sdfr args.fspec = dev; 2302892Sdfr args.export.ex_root = -2; /* unchecked anyway on DOS fs */ 2312892Sdfr if (mntflags & MNT_RDONLY) 2322892Sdfr args.export.ex_flags = MNT_EXRDONLY; 2332892Sdfr else 2342892Sdfr args.export.ex_flags = 0; 2352892Sdfr if (!set_gid || !set_uid || !set_mask) { 23652055Sphk if (stat(mntpath, &sb) == -1) 23752055Sphk err(EX_OSERR, "stat %s", mntpath); 2382892Sdfr 2392892Sdfr if (!set_uid) 2402892Sdfr args.uid = sb.st_uid; 2412892Sdfr if (!set_gid) 2422892Sdfr args.gid = sb.st_gid; 2432892Sdfr if (!set_mask) 244118837Strhodes args.mask = args.dirmask = 245118837Strhodes sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 2462892Sdfr } 2472892Sdfr 248101270Smux if (mount("msdosfs", mntpath, mntflags, &args) < 0) 24915771Swollman err(EX_OSERR, "%s", dev); 2502892Sdfr 2512892Sdfr exit (0); 2522892Sdfr} 2532892Sdfr 2542892Sdfrgid_t 2552892Sdfra_gid(s) 2562892Sdfr char *s; 2572892Sdfr{ 2582892Sdfr struct group *gr; 2592892Sdfr char *gname; 2602892Sdfr gid_t gid; 2612892Sdfr 2622892Sdfr if ((gr = getgrnam(s)) != NULL) 2632892Sdfr gid = gr->gr_gid; 2642892Sdfr else { 2652892Sdfr for (gname = s; *s && isdigit(*s); ++s); 2662892Sdfr if (!*s) 2672892Sdfr gid = atoi(gname); 2682892Sdfr else 26915771Swollman errx(EX_NOUSER, "unknown group id: %s", gname); 2702892Sdfr } 2712892Sdfr return (gid); 2722892Sdfr} 2732892Sdfr 2742892Sdfruid_t 2752892Sdfra_uid(s) 2762892Sdfr char *s; 2772892Sdfr{ 2782892Sdfr struct passwd *pw; 2792892Sdfr char *uname; 2802892Sdfr uid_t uid; 2812892Sdfr 2822892Sdfr if ((pw = getpwnam(s)) != NULL) 2832892Sdfr uid = pw->pw_uid; 2842892Sdfr else { 2852892Sdfr for (uname = s; *s && isdigit(*s); ++s); 2862892Sdfr if (!*s) 2872892Sdfr uid = atoi(uname); 2882892Sdfr else 28915771Swollman errx(EX_NOUSER, "unknown user id: %s", uname); 2902892Sdfr } 2912892Sdfr return (uid); 2922892Sdfr} 2932892Sdfr 2942892Sdfrmode_t 2952892Sdfra_mask(s) 2962892Sdfr char *s; 2972892Sdfr{ 2982892Sdfr int done, rv; 2992892Sdfr char *ep; 3002892Sdfr 3012892Sdfr done = 0; 30233549Sjkh rv = -1; 3032892Sdfr if (*s >= '0' && *s <= '7') { 3042892Sdfr done = 1; 3052892Sdfr rv = strtol(optarg, &ep, 8); 3062892Sdfr } 3072892Sdfr if (!done || rv < 0 || *ep) 30815771Swollman errx(EX_USAGE, "invalid file mode: %s", s); 3092892Sdfr return (rv); 3102892Sdfr} 3112892Sdfr 3122892Sdfrvoid 3132892Sdfrusage() 3142892Sdfr{ 315120492Sfjoe#ifdef TRANSITION_PERIOD_HACK 316121007Sfjoe fprintf(stderr, "%s\n%s\n%s\n", 317121360Strhodes "usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask] [-M mask]", 318121360Strhodes " [-s] [-l] [-9] [-L locale] [-D dos-codepage] [-W table]", 319121007Sfjoe " bdev dir"); 320120492Sfjoe#else 321121007Sfjoe fprintf(stderr, "%s\n%s\n", 322121007Sfjoe "usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask] [-M mask]", 323120492Sfjoe " [-s] [-l] [-9] [-L locale] [-D dos-codepage] bdev dir"); 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