mount_msdosfs.c revision 121363
119370Spst/* $NetBSD: mount_msdos.c,v 1.18 1997/09/16 12:24:18 lukem Exp $ */ 219370Spst 3130809Smarcel/* 4130809Smarcel * Copyright (c) 1994 Christopher G. Demetriou 5130809Smarcel * All rights reserved. 6130809Smarcel * 798948Sobrien * Redistribution and use in source and binary forms, with or without 819370Spst * modification, are permitted provided that the following conditions 998948Sobrien * are met: 1098948Sobrien * 1. Redistributions of source code must retain the above copyright 1198948Sobrien * notice, this list of conditions and the following disclaimer. 1298948Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1319370Spst * notice, this list of conditions and the following disclaimer in the 1498948Sobrien * documentation and/or other materials provided with the distribution. 1598948Sobrien * 3. All advertising materials mentioning features or use of this software 1698948Sobrien * must display the following acknowledgement: 1798948Sobrien * This product includes software developed by Christopher G. Demetriou. 1819370Spst * 4. The name of the author may not be used to endorse or promote products 1998948Sobrien * derived from this software without specific prior written permission 2098948Sobrien * 2198948Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2298948Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2319370Spst * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2419370Spst * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2519370Spst * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2619370Spst * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2719370Spst * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2898948Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2998948Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3019370Spst * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3119370Spst */ 3219370Spst 3319370Spst#ifndef lint 3419370Spststatic const char rcsid[] = 3519370Spst "$FreeBSD: head/sbin/mount_msdosfs/mount_msdosfs.c 121363 2003-10-22 20:11:42Z trhodes $"; 3619370Spst#endif /* not lint */ 3719370Spst 3898948Sobrien#include <sys/param.h> 3998948Sobrien#include <sys/mount.h> 4019370Spst#include <sys/stat.h> 41130809Smarcel#include <sys/module.h> 42130809Smarcel#include <sys/iconv.h> 43130809Smarcel#include <sys/linker.h> 4419370Spst 4519370Spst#include <fs/msdosfs/msdosfsmount.h> 4619370Spst 4719370Spst#include <ctype.h> 4819370Spst#include <err.h> 4919370Spst#include <grp.h> 5019370Spst#include <locale.h> 5119370Spst#include <pwd.h> 5298948Sobrien#include <stdio.h> 5398948Sobrien/* must be after stdio to declare fparseln */ 5498948Sobrien#include <libutil.h> 5598948Sobrien#include <stdlib.h> 5698948Sobrien#include <string.h> 5798948Sobrien#include <sysexits.h> 58130809Smarcel#include <unistd.h> 59130809Smarcel#include "mntopts.h" 60130809Smarcel 6198948Sobrien#define TRANSITION_PERIOD_HACK 6298948Sobrien 6346283Sdfr/* 6446283Sdfr * XXX - no way to specify "foo=<bar>"-type options; that's what we'd 6546283Sdfr * want for "-u", "-g", "-m", "-M", "-L", "-D", and "-W". 6646283Sdfr */ 6746283Sdfrstatic struct mntopt mopts[] = { 6846283Sdfr MOPT_STDOPTS, 69130809Smarcel MOPT_FORCE, 70130809Smarcel MOPT_SYNC, 71130809Smarcel MOPT_UPDATE, 7298948Sobrien#ifdef MSDOSFSMNT_GEMDOSFS 7398948Sobrien { "gemdosfs", 0, MSDOSFSMNT_GEMDOSFS, 1 }, 7498948Sobrien#endif 75130809Smarcel { "shortnames", 0, MSDOSFSMNT_SHORTNAME, 1 }, 76130809Smarcel { "longnames", 0, MSDOSFSMNT_LONGNAME, 1 }, 77130809Smarcel { "nowin95", 0, MSDOSFSMNT_NOWIN95, 1 }, 7898948Sobrien { NULL } 79130809Smarcel}; 8046283Sdfr 8146283Sdfrstatic gid_t a_gid(char *); 8246283Sdfrstatic uid_t a_uid(char *); 8346283Sdfrstatic mode_t a_mask(char *); 8498948Sobrienstatic void usage(void) __dead2; 8546283Sdfrstatic int set_charset(struct msdosfs_args *); 8646283Sdfr 8746283Sdfrint 8846283Sdfrmain(argc, argv) 8998948Sobrien int argc; 9046283Sdfr char **argv; 9198948Sobrien{ 9298948Sobrien struct msdosfs_args args; 9346283Sdfr struct stat sb; 9498948Sobrien int c, mntflags, set_gid, set_uid, set_mask, set_dirmask; 9598948Sobrien char *dev, *dir, mntpath[MAXPATHLEN], *csp; 9619370Spst 97130809Smarcel mntflags = set_gid = set_uid = set_mask = set_dirmask = 0; 9898948Sobrien (void)memset(&args, '\0', sizeof(args)); 9998948Sobrien args.magic = MSDOSFS_ARGSMAGIC; 10098948Sobrien 10198948Sobrien args.cs_win = NULL; 10298948Sobrien args.cs_dos = NULL; 10398948Sobrien args.cs_local = NULL; 10498948Sobrien#ifdef TRANSITION_PERIOD_HACK 10598948Sobrien while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) { 10698948Sobrien#else 10798948Sobrien while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:")) != -1) { 10898948Sobrien#endif 10998948Sobrien switch (c) { 11098948Sobrien#ifdef MSDOSFSMNT_GEMDOSFS 11198948Sobrien case 'G': 11298948Sobrien args.flags |= MSDOSFSMNT_GEMDOSFS; 11398948Sobrien break; 11498948Sobrien#endif 11598948Sobrien case 's': 11698948Sobrien args.flags |= MSDOSFSMNT_SHORTNAME; 11798948Sobrien break; 11898948Sobrien case 'l': 11998948Sobrien args.flags |= MSDOSFSMNT_LONGNAME; 12019370Spst break; 12119370Spst case '9': 12219370Spst args.flags |= MSDOSFSMNT_NOWIN95; 12398948Sobrien break; 12419370Spst case 'u': 12519370Spst args.uid = a_uid(optarg); 12619370Spst set_uid = 1; 12719370Spst break; 12819370Spst case 'g': 12919370Spst args.gid = a_gid(optarg); 13019370Spst set_gid = 1; 13119370Spst break; 13219370Spst case 'm': 13319370Spst args.mask = a_mask(optarg); 13419370Spst set_mask = 1; 13519370Spst break; 13619370Spst case 'M': 13719370Spst args.dirmask = a_mask(optarg); 13819370Spst set_dirmask = 1; 13919370Spst break; 14019370Spst case 'L': 14119370Spst if (setlocale(LC_CTYPE, optarg) == NULL) 14219370Spst err(EX_CONFIG, "%s", optarg); 14319370Spst csp = strchr(optarg,'.'); 14419370Spst if (!csp) 14519370Spst err(EX_CONFIG, "%s", optarg); 14619370Spst args.cs_local = malloc(ICONV_CSNMAXLEN); 14719370Spst if (args.cs_local == NULL) 14819370Spst err(EX_OSERR, "malloc()"); 14998948Sobrien strncpy(args.cs_local, 15019370Spst kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT), 15119370Spst ICONV_CSNMAXLEN); 15219370Spst break; 153130809Smarcel case 'D': 15419370Spst args.cs_dos = malloc(ICONV_CSNMAXLEN); 15519370Spst if (args.cs_dos == NULL) 15619370Spst err(EX_OSERR, "malloc()"); 157130809Smarcel strncpy(args.cs_dos, optarg, ICONV_CSNMAXLEN); 158130809Smarcel break; 159130809Smarcel case 'o': 160130809Smarcel getmntopts(optarg, mopts, &mntflags, &args.flags); 161130809Smarcel break; 162130809Smarcel#ifdef TRANSITION_PERIOD_HACK 163130809Smarcel case 'W': 164130809Smarcel args.cs_local = malloc(ICONV_CSNMAXLEN); 16519370Spst if (args.cs_local == NULL) 16619370Spst err(EX_OSERR, "malloc()"); 167130809Smarcel args.cs_dos = malloc(ICONV_CSNMAXLEN); 16819370Spst if (args.cs_dos == NULL) 169130809Smarcel err(EX_OSERR, "malloc()"); 170130809Smarcel if (strcmp(optarg, "iso22dos") == 0) { 171130809Smarcel strcpy(args.cs_local, "ISO8859-2"); 172130809Smarcel strcpy(args.cs_dos, "CP852"); 17319370Spst } else if (strcmp(optarg, "iso72dos") == 0) { 17419370Spst strcpy(args.cs_local, "ISO8859-7"); 17519370Spst strcpy(args.cs_dos, "CP737"); 17619370Spst } else if (strcmp(optarg, "koi2dos") == 0) { 17719370Spst strcpy(args.cs_local, "KOI8-R"); 17819370Spst strcpy(args.cs_dos, "CP866"); 17919370Spst } else if (strcmp(optarg, "koi8u2dos") == 0) { 18019370Spst strcpy(args.cs_local, "KOI8-U"); 18119370Spst strcpy(args.cs_dos, "CP866"); 18219370Spst } else { 18319370Spst err(EX_NOINPUT, "%s", optarg); 18419370Spst } 18519370Spst break; 18619370Spst#endif /* TRANSITION_PERIOD_HACK */ 18719370Spst case '?': 18819370Spst default: 18919370Spst usage(); 19019370Spst break; 19119370Spst } 19219370Spst } 19319370Spst 19498948Sobrien if (optind + 2 != argc) 19598948Sobrien usage(); 19698948Sobrien 19798948Sobrien if (set_mask && !set_dirmask) { 198130809Smarcel args.dirmask = args.mask; 199130809Smarcel set_dirmask = 1; 200130809Smarcel } 20146283Sdfr else if (set_dirmask && !set_mask) { 20298948Sobrien args.mask = args.dirmask; 20398948Sobrien set_mask = 1; 20446283Sdfr } 205130809Smarcel 206130809Smarcel dev = argv[optind]; 207130809Smarcel dir = argv[optind + 1]; 208130809Smarcel 209130809Smarcel if (args.cs_local) { 210130809Smarcel if (set_charset(&args) == -1) 211130809Smarcel err(EX_OSERR, "msdosfs_iconv"); 212130809Smarcel args.flags |= MSDOSFSMNT_KICONV; 213130809Smarcel } else if (args.cs_dos) { 214130809Smarcel if ((args.cs_local = malloc(ICONV_CSNMAXLEN)) == NULL) 215130809Smarcel err(EX_OSERR, "malloc()"); 216130809Smarcel strcpy(args.cs_local, "ISO8859-1"); 217130809Smarcel if (set_charset(&args) == -1) 218130809Smarcel err(EX_OSERR, "msdosfs_iconv"); 219130809Smarcel args.flags |= MSDOSFSMNT_KICONV; 220130809Smarcel } 221130809Smarcel 222130809Smarcel /* 223130809Smarcel * Resolve the mountpoint with realpath(3) and remove unnecessary 224130809Smarcel * slashes from the devicename if there are any. 225130809Smarcel */ 226130809Smarcel (void)checkpath(dir, mntpath); 227130809Smarcel (void)rmslashes(dev, dev); 228130809Smarcel 229130809Smarcel args.fspec = dev; 230130809Smarcel args.export.ex_root = -2; /* unchecked anyway on DOS fs */ 231130809Smarcel if (mntflags & MNT_RDONLY) 232130809Smarcel args.export.ex_flags = MNT_EXRDONLY; 233130809Smarcel else 234130809Smarcel args.export.ex_flags = 0; 235130809Smarcel if (!set_gid || !set_uid || !set_mask) { 236130809Smarcel if (stat(mntpath, &sb) == -1) 237130809Smarcel err(EX_OSERR, "stat %s", mntpath); 238130809Smarcel 23919370Spst if (!set_uid) 24019370Spst args.uid = sb.st_uid; 24119370Spst if (!set_gid) 24219370Spst args.gid = sb.st_gid; 24319370Spst if (!set_mask) 24419370Spst args.mask = args.dirmask = 245130809Smarcel sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 246130809Smarcel } 247130809Smarcel 248130809Smarcel if (mount("msdosfs", mntpath, mntflags, &args) < 0) 249130809Smarcel err(EX_OSERR, "%s", dev); 250130809Smarcel 251130809Smarcel exit (0); 252130809Smarcel} 253130809Smarcel 25419370Spstgid_t 25598948Sobriena_gid(s) 25698948Sobrien char *s; 25798948Sobrien{ 25846283Sdfr struct group *gr; 259130809Smarcel char *gname; 26046283Sdfr gid_t gid; 26198948Sobrien 26298948Sobrien if ((gr = getgrnam(s)) != NULL) 26398948Sobrien gid = gr->gr_gid; 26498948Sobrien else { 26598948Sobrien for (gname = s; *s && isdigit(*s); ++s); 26698948Sobrien if (!*s) 26798948Sobrien gid = atoi(gname); 26898948Sobrien else 26998948Sobrien errx(EX_NOUSER, "unknown group id: %s", gname); 27098948Sobrien } 27198948Sobrien return (gid); 27219370Spst} 27398948Sobrien 27498948Sobrienuid_t 27598948Sobriena_uid(s) 27698948Sobrien char *s; 27798948Sobrien{ 27819370Spst struct passwd *pw; 279130809Smarcel char *uname; 28098948Sobrien uid_t uid; 281130809Smarcel 28298948Sobrien if ((pw = getpwnam(s)) != NULL) 28398948Sobrien uid = pw->pw_uid; 28498948Sobrien else { 28598948Sobrien for (uname = s; *s && isdigit(*s); ++s); 28698948Sobrien if (!*s) 28798948Sobrien uid = atoi(uname); 28898948Sobrien else 28998948Sobrien errx(EX_NOUSER, "unknown user id: %s", uname); 29098948Sobrien } 29198948Sobrien return (uid); 29298948Sobrien} 29398948Sobrien 29498948Sobrienmode_t 29598948Sobriena_mask(s) 29698948Sobrien char *s; 29798948Sobrien{ 29898948Sobrien int done, rv; 29998948Sobrien char *ep; 30098948Sobrien 30198948Sobrien done = 0; 30298948Sobrien rv = -1; 303130809Smarcel if (*s >= '0' && *s <= '7') { 30498948Sobrien done = 1; 30598948Sobrien rv = strtol(optarg, &ep, 8); 30698948Sobrien } 307130809Smarcel if (!done || rv < 0 || *ep) 308130809Smarcel errx(EX_USAGE, "invalid file mode: %s", s); 309130809Smarcel return (rv); 310130809Smarcel} 311130809Smarcel 31298948Sobrienvoid 31398948Sobrienusage() 31498948Sobrien{ 31598948Sobrien#ifdef TRANSITION_PERIOD_HACK 31619370Spst fprintf(stderr, "%s\n%s\n%s\n", 31719370Spst "usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask] [-M mask]", 31819370Spst " [-s] [-l] [-9] [-L locale] [-D dos-codepage] [-W table]", 31919370Spst " bdev dir"); 32019370Spst#else 32119370Spst fprintf(stderr, "%s\n%s\n", 32219370Spst "usage: mount_msdosfs [-o options] [-u user] [-g group] [-m mask] [-M mask]", 32398948Sobrien " [-s] [-l] [-9] [-L locale] [-D dos-codepage] bdev dir"); 32419370Spst#endif 32519370Spst exit(EX_USAGE); 32619370Spst} 32719370Spst 32819370Spstint 32919370Spstset_charset(struct msdosfs_args *args) 33019370Spst{ 33119370Spst int error; 33219370Spst 33319370Spst if (modfind("msdosfs_iconv") < 0) 33419370Spst if (kldload("msdosfs_iconv") < 0 || modfind("msdosfs_iconv") < 0) { 335130809Smarcel warnx( "cannot find or load \"msdosfs_iconv\" kernel module"); 33619370Spst return (-1); 33719370Spst } 33819370Spst 339130809Smarcel if ((args->cs_win = malloc(ICONV_CSNMAXLEN)) == NULL) 34019370Spst return (-1); 34119370Spst strncpy(args->cs_win, ENCODING_UNICODE, ICONV_CSNMAXLEN); 342130809Smarcel error = kiconv_add_xlat16_cspair(args->cs_win, args->cs_local, 0); 34319370Spst if (error) 34419370Spst return (-1); 34519370Spst error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_win, 0); 346130809Smarcel if (error) 34719370Spst return (-1); 34819370Spst if (args->cs_dos) { 34919370Spst error = kiconv_add_xlat16_cspair(args->cs_dos, args->cs_local, KICONV_FROM_UPPER); 35019370Spst if (error) 351130809Smarcel return (-1); 352130809Smarcel error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_dos, KICONV_LOWER); 353130809Smarcel if (error) 354130809Smarcel return (-1); 355130809Smarcel } else { 356130809Smarcel if ((args->cs_dos = malloc(ICONV_CSNMAXLEN)) == NULL) 357130809Smarcel return (-1); 358130809Smarcel strcpy(args->cs_dos, args->cs_local); 359130809Smarcel error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_local, 360130809Smarcel KICONV_FROM_UPPER | KICONV_LOWER); 361130809Smarcel if (error) 362130809Smarcel return (-1); 363130809Smarcel } 364130809Smarcel 365130809Smarcel return (0); 366130809Smarcel} 36719370Spst