mount_msdosfs.c revision 120492
137535Sdes/* $NetBSD: mount_msdos.c,v 1.18 1997/09/16 12:24:18 lukem Exp $ */ 2135546Sdes 337535Sdes/* 437535Sdes * Copyright (c) 1994 Christopher G. Demetriou 537535Sdes * All rights reserved. 637535Sdes * 737535Sdes * Redistribution and use in source and binary forms, with or without 837535Sdes * modification, are permitted provided that the following conditions 937535Sdes * are met: 1037535Sdes * 1. Redistributions of source code must retain the above copyright 1137535Sdes * notice, this list of conditions and the following disclaimer. 1237535Sdes * 2. Redistributions in binary form must reproduce the above copyright 1337535Sdes * notice, this list of conditions and the following disclaimer in the 1437535Sdes * documentation and/or other materials provided with the distribution. 1563012Sdes * 3. All advertising materials mentioning features or use of this software 1637535Sdes * must display the following acknowledgement: 1737535Sdes * This product includes software developed by Christopher G. Demetriou. 1837535Sdes * 4. The name of the author may not be used to endorse or promote products 1937535Sdes * derived from this software without specific prior written permission 2037535Sdes * 2137535Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2237535Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2337535Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2437535Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2537535Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2637535Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2737535Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2837535Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2984203Sdillon * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3084203Sdillon * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3184203Sdillon */ 3263236Sdes 3363236Sdes#ifndef lint 3463236Sdesstatic const char rcsid[] = 3563236Sdes "$FreeBSD: head/sbin/mount_msdosfs/mount_msdosfs.c 120492 2003-09-26 20:26:25Z fjoe $"; 3663236Sdes#endif /* not lint */ 3763236Sdes 3863236Sdes#include <sys/param.h> 3963236Sdes#include <sys/mount.h> 4063236Sdes#include <sys/stat.h> 4163236Sdes#include <sys/module.h> 4263236Sdes#include <sys/iconv.h> 4363236Sdes 4463236Sdes#include <fs/msdosfs/msdosfsmount.h> 4563236Sdes 4663236Sdes#include <ctype.h> 4763236Sdes#include <err.h> 4863236Sdes#include <grp.h> 4990267Sdes#include <locale.h> 5063236Sdes#include <pwd.h> 5163236Sdes#include <stdio.h> 5263236Sdes/* must be after stdio to declare fparseln */ 5363236Sdes#include <libutil.h> 5463236Sdes#include <stdlib.h> 5563236Sdes#include <string.h> 5663236Sdes#include <sysexits.h> 5763236Sdes#include <unistd.h> 5863236Sdes 5963236Sdes#include "mntopts.h" 6063236Sdes 6163236Sdes#define TRANSITION_PERIOD_HACK 6263236Sdes 6363236Sdes/* 6437535Sdes * XXX - no way to specify "foo=<bar>"-type options; that's what we'd 6560737Sume * want for "-u", "-g", "-m", "-L", "-D", and "-W". 66186124Smurray */ 6737535Sdesstatic struct mntopt mopts[] = { 6863012Sdes MOPT_STDOPTS, 6937535Sdes MOPT_FORCE, 7063012Sdes MOPT_SYNC, 7160376Sdes MOPT_UPDATE, 7260189Sdes#ifdef MSDOSFSMNT_GEMDOSFS 7337608Sdes { "gemdosfs", 0, MSDOSFSMNT_GEMDOSFS, 1 }, 7437535Sdes#endif 7537535Sdes { "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 }, 7637535Sdes { "longnames", 0, MSDOSFSMNT_LONGNAME, 1 }, 7760376Sdes { "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 }, 7837535Sdes { NULL } 79202613Sdes}; 8037535Sdes 81141958Skbyancstatic gid_t a_gid(char *); 82141958Skbyancstatic uid_t a_uid(char *); 83141958Skbyancstatic mode_t a_mask(char *); 8437535Sdesstatic void usage(void) __dead2; 8540939Sdesstatic int set_charset(struct msdosfs_args *); 8641862Sdes 8737535Sdesint 8863012Sdesmain(argc, argv) 8963012Sdes int argc; 9037535Sdes char **argv; 9163012Sdes{ 9263012Sdes struct msdosfs_args args; 9363012Sdes struct stat sb; 9463012Sdes int c, mntflags, set_gid, set_uid, set_mask, set_dirmask; 9563012Sdes char *dev, *dir, mntpath[MAXPATHLEN], *csp; 9663012Sdes 97186124Smurray mntflags = set_gid = set_uid = set_mask = set_dirmask = 0; 98169386Sdes (void)memset(&args, '\0', sizeof(args)); 9963012Sdes args.magic = MSDOSFS_ARGSMAGIC; 10087317Sdes 101125696Sdes args.cs_win = NULL; 10263012Sdes args.cs_dos = NULL; 10360196Sdes args.cs_local = NULL; 10463012Sdes#ifdef TRANSITION_PERIOD_HACK 10590267Sdes while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) { 106169386Sdes#else 10790267Sdes while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:")) != -1) { 10863012Sdes#endif 10988771Sdes switch (c) { 11063012Sdes#ifdef MSDOSFSMNT_GEMDOSFS 11190267Sdes case 'G': 11263012Sdes args.flags |= MSDOSFSMNT_GEMDOSFS; 11363012Sdes break; 11463012Sdes#endif 11563012Sdes case 's': 11697859Sdes args.flags |= MSDOSFSMNT_SHORTNAME; 11737535Sdes break; 11897858Sdes case 'l': 11997866Sdes args.flags |= MSDOSFSMNT_LONGNAME; 12097858Sdes break; 12197866Sdes case '9': 12297866Sdes args.flags |= MSDOSFSMNT_NOWIN95; 12397866Sdes break; 12497858Sdes case 'u': 12597858Sdes args.uid = a_uid(optarg); 12697858Sdes set_uid = 1; 12763281Sdes break; 12890267Sdes case 'g': 12963012Sdes args.gid = a_gid(optarg); 13037535Sdes set_gid = 1; 13137535Sdes break; 13237608Sdes case 'm': 13363012Sdes args.mask = a_mask(optarg); 13437608Sdes set_mask = 1; 13537608Sdes break; 136174588Sdes case 'M': 13737608Sdes args.dirmask = a_mask(optarg); 13890267Sdes set_dirmask = 1; 13990267Sdes break; 140174588Sdes case 'L': 14190267Sdes if (setlocale(LC_CTYPE, optarg) == NULL) 14290267Sdes err(EX_CONFIG, "%s", optarg); 143174761Sdes csp = strchr(optarg,'.'); 14490267Sdes if (!csp) 14590267Sdes err(EX_CONFIG, "%s", optarg); 146174761Sdes args.cs_local = malloc(ICONV_CSNMAXLEN); 14790267Sdes if (args.cs_local == NULL) 14890267Sdes err(EX_OSERR, "malloc()"); 149174761Sdes strncpy(args.cs_local, 15090267Sdes kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT), 151174761Sdes ICONV_CSNMAXLEN); 15297859Sdes break; 15390267Sdes case 'D': 15490267Sdes args.cs_dos = malloc(ICONV_CSNMAXLEN); 15597859Sdes if (args.cs_dos == NULL) 156176036Sdes err(EX_OSERR, "malloc()"); 15790267Sdes strncpy(args.cs_dos, optarg, ICONV_CSNMAXLEN); 15890267Sdes break; 15990267Sdes case 'o': 16063281Sdes getmntopts(optarg, mopts, &mntflags, &args.flags); 16190267Sdes break; 16297859Sdes#ifdef TRANSITION_PERIOD_HACK 16397859Sdes case 'W': 164106207Sdes args.cs_local = malloc(ICONV_CSNMAXLEN); 16590267Sdes if (args.cs_local == NULL) 166106207Sdes err(EX_OSERR, "malloc()"); 167106207Sdes args.cs_dos = malloc(ICONV_CSNMAXLEN); 168106207Sdes if (args.cs_dos == NULL) 16990267Sdes err(EX_OSERR, "malloc()"); 17063012Sdes if (strcmp(optarg, "iso22dos") == 0) { 17190267Sdes strcpy(args.cs_local, "ISO8859-2"); 17297859Sdes strcpy(args.cs_dos, "CP852"); 17337608Sdes } else if (strcmp(optarg, "iso72dos") == 0) { 17437608Sdes strcpy(args.cs_local, "ISO8859-7"); 17537608Sdes strcpy(args.cs_dos, "CP737"); 17697866Sdes } else if (strcmp(optarg, "koi2dos") == 0) { 17797866Sdes strcpy(args.cs_local, "KOI8-R"); 17897866Sdes strcpy(args.cs_dos, "CP866"); 179174588Sdes } else if (strcmp(optarg, "koi8u2dos") == 0) { 18097866Sdes strcpy(args.cs_local, "KOI8-U"); 18197866Sdes strcpy(args.cs_dos, "CP866"); 18297866Sdes } else { 18397866Sdes err(EX_NOINPUT, "%s", optarg); 18497866Sdes } 18597866Sdes break; 18697866Sdes#endif /* TRANSITION_PERIOD_HACK */ 18797866Sdes case '?': 18897866Sdes default: 18997866Sdes usage(); 190106044Sdes break; 19197866Sdes } 19297866Sdes } 19397866Sdes 19437608Sdes if (optind + 2 != argc) 19537608Sdes usage(); 19663012Sdes 197174588Sdes if (set_mask && !set_dirmask) { 19837535Sdes args.dirmask = args.mask; 19997859Sdes set_dirmask = 1; 20090267Sdes } 20197859Sdes else if (set_dirmask && !set_mask) { 20290267Sdes args.mask = args.dirmask; 20390267Sdes set_mask = 1; 20497866Sdes } 205174588Sdes 20697866Sdes dev = argv[optind]; 207174588Sdes dir = argv[optind + 1]; 208106185Sdes 20997866Sdes if (args.cs_local) { 210106185Sdes if (set_charset(&args) == -1) 21197866Sdes err(EX_OSERR, "msdosfs_iconv"); 21297866Sdes args.flags |= MSDOSFSMNT_KICONV; 21397866Sdes } else if (args.cs_dos) { 21497866Sdes if ((args.cs_local = malloc(ICONV_CSNMAXLEN)) == NULL) 21597859Sdes err(EX_OSERR, "malloc()"); 216174588Sdes strcpy(args.cs_local, "ISO8859-1"); 21790267Sdes if (set_charset(&args) == -1) 21897859Sdes err(EX_OSERR, "msdosfs_iconv"); 21990267Sdes args.flags |= MSDOSFSMNT_KICONV; 22090267Sdes } 22197859Sdes 22290267Sdes /* 22390267Sdes * Resolve the mountpoint with realpath(3) and remove unnecessary 22437535Sdes * slashes from the devicename if there are any. 22563012Sdes */ 22697866Sdes (void)checkpath(dir, mntpath); 22797866Sdes (void)rmslashes(dev, dev); 228174588Sdes 22990267Sdes args.fspec = dev; 230174588Sdes args.export.ex_root = -2; /* unchecked anyway on DOS fs */ 231106185Sdes if (mntflags & MNT_RDONLY) 23297866Sdes args.export.ex_flags = MNT_EXRDONLY; 233106185Sdes else 23497866Sdes args.export.ex_flags = 0; 23590267Sdes if (!set_gid || !set_uid || !set_mask) { 23697859Sdes if (stat(mntpath, &sb) == -1) 23797856Sdes err(EX_OSERR, "stat %s", mntpath); 23897856Sdes 239174588Sdes if (!set_uid) 24097856Sdes args.uid = sb.st_uid; 24190267Sdes if (!set_gid) 24290267Sdes args.gid = sb.st_gid; 24390267Sdes if (!set_mask) 24497866Sdes args.mask = args.dirmask = 24590267Sdes sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 24697866Sdes } 24737535Sdes 24837535Sdes if (mount("msdosfs", mntpath, mntflags, &args) < 0) 24937608Sdes err(EX_OSERR, "%s", dev); 25037608Sdes 25137608Sdes exit (0); 25237535Sdes} 253174588Sdes 25437535Sdesgid_t 25597859Sdesa_gid(s) 25690267Sdes char *s; 25763012Sdes{ 25897859Sdes struct group *gr; 25990267Sdes char *gname; 26097859Sdes gid_t gid; 26190267Sdes 26263012Sdes if ((gr = getgrnam(s)) != NULL) 26390267Sdes gid = gr->gr_gid; 26490267Sdes else { 26597866Sdes for (gname = s; *s && isdigit(*s); ++s); 266174588Sdes if (!*s) 26790267Sdes gid = atoi(gname); 26897866Sdes else 26990267Sdes errx(EX_NOUSER, "unknown group id: %s", gname); 27090267Sdes } 271176105Sdes return (gid); 27297866Sdes} 27390267Sdes 27437535Sdesuid_t 27597859Sdesa_uid(s) 27690267Sdes char *s; 27790267Sdes{ 27837535Sdes struct passwd *pw; 27937535Sdes char *uname; 28037608Sdes uid_t uid; 28137608Sdes 28237608Sdes if ((pw = getpwnam(s)) != NULL) 28337535Sdes uid = pw->pw_uid; 284174588Sdes else { 28537535Sdes for (uname = s; *s && isdigit(*s); ++s); 28697859Sdes if (!*s) 28790267Sdes uid = atoi(uname); 288174588Sdes else 28937535Sdes errx(EX_NOUSER, "unknown user id: %s", uname); 29037535Sdes } 29137608Sdes return (uid); 29237608Sdes} 29337608Sdes 29437535Sdesmode_t 295174588Sdesa_mask(s) 29637535Sdes char *s; 29797859Sdes{ 29890267Sdes int done, rv; 29963012Sdes char *ep; 300174588Sdes 30197859Sdes done = 0; 30297859Sdes rv = -1; 30397859Sdes if (*s >= '0' && *s <= '7') { 30490267Sdes done = 1; 30537535Sdes rv = strtol(optarg, &ep, 8); 30637535Sdes } 30737608Sdes if (!done || rv < 0 || *ep) 30863012Sdes errx(EX_USAGE, "invalid file mode: %s", s); 30937608Sdes return (rv); 31063012Sdes} 311174588Sdes 31237535Sdesvoid 31397859Sdesusage() 31490267Sdes{ 31563012Sdes fprintf(stderr, "%s\n%s\n", 316109967Sdes#ifdef TRANSITION_PERIOD_HACK 317174588Sdes "usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask] [-s] [-l]", 31890267Sdes " [-9] [-L locale] [-D dos-codepage] [-W table] bdev dir"); 31990267Sdes#else 32097859Sdes "usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask]", 32197866Sdes " [-s] [-l] [-9] [-L locale] [-D dos-codepage] bdev dir"); 322174588Sdes#endif 32390267Sdes exit(EX_USAGE); 324174588Sdes} 32597859Sdes 32690267Sdesint 32790267Sdesset_charset(struct msdosfs_args *args) 32890267Sdes{ 32963012Sdes int error; 33063012Sdes 33190267Sdes if (modfind("msdosfs_iconv") < 0) 33263012Sdes if (kldload("msdosfs_iconv") < 0 || modfind("msdosfs_iconv") < 0) { 33363012Sdes warnx( "cannot find or load \"msdosfs_iconv\" kernel module"); 33463012Sdes return (-1); 33563012Sdes } 33663012Sdes 33763012Sdes if ((args->cs_win = malloc(ICONV_CSNMAXLEN)) == NULL) 33890267Sdes return (-1); 33990267Sdes strncpy(args->cs_win, ENCODING_UNICODE, ICONV_CSNMAXLEN); 34090267Sdes error = kiconv_add_xlat16_cspair(args->cs_win, args->cs_local, 0); 34190267Sdes if (error) 34290267Sdes return (-1); 34390267Sdes error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_win, 0); 34490267Sdes if (error) 34590267Sdes return (-1); 34690267Sdes if (args->cs_dos) { 347202613Sdes error = kiconv_add_xlat16_cspair(args->cs_dos, args->cs_local, KICONV_FROM_UPPER); 348202613Sdes if (error) 34985093Sdes return (-1); 35063012Sdes error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_dos, KICONV_LOWER); 35163012Sdes if (error) 35263012Sdes return (-1); 35390267Sdes } else { 35490267Sdes if ((args->cs_dos = malloc(ICONV_CSNMAXLEN)) == NULL) 35563012Sdes return (-1); 35690267Sdes strcpy(args->cs_dos, args->cs_local); 35790267Sdes error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_local, 35890267Sdes KICONV_FROM_UPPER | KICONV_LOWER); 35990267Sdes if (error) 36090267Sdes return (-1); 36190267Sdes } 362202613Sdes 36390267Sdes return (0); 36463012Sdes} 36563012Sdes