mount_msdosfs.c revision 152974
1191983Sweongyo/* $NetBSD: mount_msdos.c,v 1.18 1997/09/16 12:24:18 lukem Exp $ */ 2191983Sweongyo 3191983Sweongyo/* 4191983Sweongyo * Copyright (c) 1994 Christopher G. Demetriou 5191983Sweongyo * All rights reserved. 6191983Sweongyo * 7191983Sweongyo * Redistribution and use in source and binary forms, with or without 8191983Sweongyo * modification, are permitted provided that the following conditions 9191983Sweongyo * are met: 10191983Sweongyo * 1. Redistributions of source code must retain the above copyright 11191983Sweongyo * notice, this list of conditions and the following disclaimer. 12191983Sweongyo * 2. Redistributions in binary form must reproduce the above copyright 13191983Sweongyo * notice, this list of conditions and the following disclaimer in the 14191983Sweongyo * documentation and/or other materials provided with the distribution. 15191983Sweongyo * 3. All advertising materials mentioning features or use of this software 16191983Sweongyo * must display the following acknowledgement: 17191983Sweongyo * This product includes software developed by Christopher G. Demetriou. 18191983Sweongyo * 4. The name of the author may not be used to endorse or promote products 19191983Sweongyo * derived from this software without specific prior written permission 20191983Sweongyo * 21191983Sweongyo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22191983Sweongyo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23191983Sweongyo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24191983Sweongyo * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25191983Sweongyo * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26191983Sweongyo * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27191983Sweongyo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28191983Sweongyo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29191983Sweongyo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30191983Sweongyo * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31191983Sweongyo */ 32191983Sweongyo 33191983Sweongyo#ifndef lint 34191983Sweongyostatic const char rcsid[] = 35191983Sweongyo "$FreeBSD: head/sbin/mount_msdosfs/mount_msdosfs.c 152974 2005-12-01 00:18:48Z avatar $"; 36191983Sweongyo#endif /* not lint */ 37191983Sweongyo 38191983Sweongyo#include <sys/param.h> 39191983Sweongyo#include <sys/mount.h> 40191983Sweongyo#include <sys/stat.h> 41191983Sweongyo#include <sys/iconv.h> 42191983Sweongyo#include <sys/linker.h> 43191983Sweongyo#include <sys/module.h> 44191983Sweongyo 45191983Sweongyo#include <ctype.h> 46191983Sweongyo#include <err.h> 47191983Sweongyo#include <grp.h> 48191983Sweongyo#include <locale.h> 49191983Sweongyo#include <pwd.h> 50191983Sweongyo#include <stdio.h> 51194677Sthompsa/* must be after stdio to declare fparseln */ 52191983Sweongyo#include <libutil.h> 53191983Sweongyo#include <stdlib.h> 54191983Sweongyo#include <string.h> 55191983Sweongyo#include <sysexits.h> 56191983Sweongyo#include <unistd.h> 57191983Sweongyo 58191983Sweongyo#include "mntopts.h" 59191983Sweongyo 60191983Sweongyostatic struct mntopt mopts[] = { 61191983Sweongyo MOPT_STDOPTS, 62191983Sweongyo MOPT_FORCE, 63191983Sweongyo MOPT_SYNC, 64191983Sweongyo MOPT_UPDATE, 65191983Sweongyo MOPT_END 66191983Sweongyo}; 67191983Sweongyo 68191983Sweongyostatic gid_t a_gid(char *); 69191983Sweongyostatic uid_t a_uid(char *); 70191983Sweongyostatic mode_t a_mask(char *); 71191983Sweongyostatic void usage(void) __dead2; 72191983Sweongyostatic int set_charset(struct iovec **iov, int *iovlen, const char *, const char *); 73248085Smarius 74191983Sweongyoint 75191983Sweongyomain(int argc, char **argv) 76191983Sweongyo{ 77191983Sweongyo struct iovec *iov = NULL; 78242775Shselasky int iovlen = 0; 79191983Sweongyo struct stat sb; 80191983Sweongyo int c, mntflags, set_gid, set_uid, set_mask, set_dirmask; 81191983Sweongyo int optflags = 0; 82191983Sweongyo char *dev, *dir, mntpath[MAXPATHLEN], *csp; 83191983Sweongyo char fstype[] = "msdosfs"; 84191983Sweongyo char *cs_dos = NULL; 85191983Sweongyo char *cs_local = NULL; 86191983Sweongyo mode_t mask = 0, dirmask = 0; 87191983Sweongyo uid_t uid = 0; 88191983Sweongyo gid_t gid = 0; 89191983Sweongyo getmnt_silent = 1; 90191983Sweongyo 91191983Sweongyo mntflags = set_gid = set_uid = set_mask = set_dirmask = 0; 92191983Sweongyo 93191983Sweongyo while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) { 94191983Sweongyo switch (c) { 95191983Sweongyo case 's': 96191983Sweongyo build_iovec(&iov, &iovlen, "shortnames", NULL, (size_t)-1); 97191983Sweongyo break; 98191983Sweongyo case 'l': 99191983Sweongyo build_iovec(&iov, &iovlen, "longnames", NULL, (size_t)-1); 100191983Sweongyo break; 101191983Sweongyo case '9': 102191983Sweongyo build_iovec_argf(&iov, &iovlen, "nowin95", "", (size_t)-1); 103191983Sweongyo break; 104191983Sweongyo case 'u': 105191983Sweongyo uid = a_uid(optarg); 106191983Sweongyo set_uid = 1; 107191983Sweongyo break; 108191983Sweongyo case 'g': 109191983Sweongyo gid = a_gid(optarg); 110191983Sweongyo set_gid = 1; 111191983Sweongyo break; 112191983Sweongyo case 'm': 113191983Sweongyo mask = a_mask(optarg); 114191983Sweongyo set_mask = 1; 115191983Sweongyo break; 116191983Sweongyo case 'M': 117191983Sweongyo dirmask = a_mask(optarg); 118191983Sweongyo set_dirmask = 1; 119192984Sthompsa break; 120191983Sweongyo case 'L': { 121191983Sweongyo const char *quirk = NULL; 122192984Sthompsa if (setlocale(LC_CTYPE, optarg) == NULL) 123191983Sweongyo err(EX_CONFIG, "%s", optarg); 124191983Sweongyo csp = strchr(optarg,'.'); 125191983Sweongyo if (!csp) 126191983Sweongyo err(EX_CONFIG, "%s", optarg); 127191983Sweongyo quirk = kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT); 128191983Sweongyo build_iovec_argf(&iov, &iovlen, "cs_local", quirk); 129191983Sweongyo cs_local = strdup(quirk); 130191983Sweongyo } 131191983Sweongyo break; 132191983Sweongyo case 'D': 133191983Sweongyo cs_dos = strdup(optarg); 134191983Sweongyo build_iovec_argf(&iov, &iovlen, "cs_dos", cs_dos, (size_t)-1); 135191983Sweongyo break; 136191983Sweongyo case 'o': { 137191983Sweongyo char *p = NULL; 138191983Sweongyo char *val = strdup(""); 139191983Sweongyo getmntopts(optarg, mopts, &mntflags, &optflags); 140191983Sweongyo p = strchr(optarg, '='); 141234753Sdim if (p != NULL) { 142234753Sdim free(val); 143234753Sdim *p = '\0'; 144191983Sweongyo val = p + 1; 145191983Sweongyo } 146191983Sweongyo build_iovec(&iov, &iovlen, optarg, val, (size_t)-1); 147191983Sweongyo } 148191983Sweongyo break; 149191983Sweongyo case 'W': 150191983Sweongyo if (strcmp(optarg, "iso22dos") == 0) { 151191983Sweongyo cs_local = strdup("ISO8859-2"); 152191983Sweongyo cs_dos = strdup("CP852"); 153191983Sweongyo } else if (strcmp(optarg, "iso72dos") == 0) { 154191983Sweongyo cs_local = strdup("ISO8859-7"); 155191983Sweongyo cs_dos = strdup("CP737"); 156191983Sweongyo } else if (strcmp(optarg, "koi2dos") == 0) { 157191983Sweongyo cs_local = strdup("KOI8-R"); 158191983Sweongyo cs_dos = strdup("CP866"); 159191983Sweongyo } else if (strcmp(optarg, "koi8u2dos") == 0) { 160191983Sweongyo cs_local = strdup("KOI8-U"); 161191983Sweongyo cs_dos = strdup("CP866"); 162191983Sweongyo } else { 163191983Sweongyo err(EX_NOINPUT, "%s", optarg); 164191983Sweongyo } 165191983Sweongyo build_iovec(&iov, &iovlen, "cs_local", cs_local, (size_t)-1); 166191983Sweongyo build_iovec(&iov, &iovlen, "cs_dos", cs_dos, (size_t)-1); 167191983Sweongyo break; 168191983Sweongyo case '?': 169191983Sweongyo default: 170191983Sweongyo usage(); 171191983Sweongyo break; 172191983Sweongyo } 173223486Shselasky } 174191983Sweongyo 175191983Sweongyo if (optind + 2 != argc) 176191983Sweongyo usage(); 177191983Sweongyo 178191983Sweongyo if (set_mask && !set_dirmask) { 179191983Sweongyo dirmask = mask; 180191983Sweongyo set_dirmask = 1; 181191983Sweongyo } 182191983Sweongyo else if (set_dirmask && !set_mask) { 183191983Sweongyo mask = dirmask; 184191983Sweongyo set_mask = 1; 185213804Shselasky } 186191983Sweongyo 187191983Sweongyo dev = argv[optind]; 188209447Sthompsa dir = argv[optind + 1]; 189191983Sweongyo 190191983Sweongyo if (cs_local != NULL) { 191191983Sweongyo if (set_charset(&iov, &iovlen, cs_local, cs_dos) == -1) 192191983Sweongyo err(EX_OSERR, "msdosfs_iconv"); 193191983Sweongyo build_iovec_argf(&iov, &iovlen, "kiconv", ""); 194191983Sweongyo } else if (cs_dos != NULL) { 195191983Sweongyo build_iovec_argf(&iov, &iovlen, "cs_local", "ISO8859-1"); 196193045Sthompsa if (set_charset(&iov, &iovlen, "ISO8859-1", cs_dos) == -1) 197193045Sthompsa err(EX_OSERR, "msdosfs_iconv"); 198191983Sweongyo build_iovec_argf(&iov, &iovlen, "kiconv", ""); 199192984Sthompsa } 200191983Sweongyo 201191983Sweongyo /* 202191983Sweongyo * Resolve the mountpoint with realpath(3) and remove unnecessary 203191983Sweongyo * slashes from the devicename if there are any. 204259454Shselasky */ 205191983Sweongyo (void)checkpath(dir, mntpath); 206191983Sweongyo (void)rmslashes(dev, dev); 207191983Sweongyo 208191983Sweongyo if (!set_gid || !set_uid || !set_mask) { 209191983Sweongyo if (stat(mntpath, &sb) == -1) 210191983Sweongyo err(EX_OSERR, "stat %s", mntpath); 211191983Sweongyo 212191983Sweongyo if (!set_uid) 213191983Sweongyo uid = sb.st_uid; 214191983Sweongyo if (!set_gid) 215191983Sweongyo gid = sb.st_gid; 216259454Shselasky if (!set_mask) 217191983Sweongyo mask = dirmask = 218191983Sweongyo sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 219191983Sweongyo } 220191983Sweongyo 221191983Sweongyo build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1); 222191983Sweongyo build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t)-1); 223191983Sweongyo build_iovec(&iov, &iovlen, "from", dev, (size_t)-1); 224191983Sweongyo build_iovec_argf(&iov, &iovlen, "uid", "%d", uid); 225191983Sweongyo build_iovec_argf(&iov, &iovlen, "gid", "%u", gid); 226191983Sweongyo build_iovec_argf(&iov, &iovlen, "mask", "%u", mask); 227191983Sweongyo build_iovec_argf(&iov, &iovlen, "dirmask", "%u", dirmask); 228192984Sthompsa 229191983Sweongyo if (nmount(iov, iovlen, mntflags) < 0) 230192499Sthompsa err(1, "%s", dev); 231191983Sweongyo 232191983Sweongyo exit (0); 233191983Sweongyo} 234191983Sweongyo 235191983Sweongyogid_t 236191983Sweongyoa_gid(s) 237223486Shselasky char *s; 238191983Sweongyo{ 239191983Sweongyo struct group *gr; 240191983Sweongyo char *gname; 241191983Sweongyo gid_t gid; 242191983Sweongyo 243191983Sweongyo if ((gr = getgrnam(s)) != NULL) 244191983Sweongyo gid = gr->gr_gid; 245191983Sweongyo else { 246191983Sweongyo for (gname = s; *s && isdigit(*s); ++s); 247192984Sthompsa if (!*s) 248191983Sweongyo gid = atoi(gname); 249191983Sweongyo else 250191983Sweongyo errx(EX_NOUSER, "unknown group id: %s", gname); 251191983Sweongyo } 252191983Sweongyo return (gid); 253191983Sweongyo} 254191983Sweongyo 255194228Sthompsauid_t 256191983Sweongyoa_uid(s) 257191983Sweongyo char *s; 258191983Sweongyo{ 259191983Sweongyo struct passwd *pw; 260191983Sweongyo char *uname; 261191983Sweongyo uid_t uid; 262194228Sthompsa 263191983Sweongyo if ((pw = getpwnam(s)) != NULL) 264191983Sweongyo uid = pw->pw_uid; 265191983Sweongyo else { 266194228Sthompsa for (uname = s; *s && isdigit(*s); ++s); 267259454Shselasky if (!*s) 268191983Sweongyo uid = atoi(uname); 269191983Sweongyo else 270259454Shselasky errx(EX_NOUSER, "unknown user id: %s", uname); 271259454Shselasky } 272259454Shselasky return (uid); 273259454Shselasky} 274259454Shselasky 275259454Shselaskymode_t 276259454Shselaskya_mask(s) 277259454Shselasky char *s; 278259454Shselasky{ 279259454Shselasky int done, rv; 280259454Shselasky char *ep; 281259454Shselasky 282259454Shselasky done = 0; 283191983Sweongyo rv = -1; 284191983Sweongyo if (*s >= '0' && *s <= '7') { 285191983Sweongyo done = 1; 286191983Sweongyo rv = strtol(optarg, &ep, 8); 287191983Sweongyo } 288191983Sweongyo if (!done || rv < 0 || *ep) 289191983Sweongyo errx(EX_USAGE, "invalid file mode: %s", s); 290191983Sweongyo return (rv); 291191983Sweongyo} 292191983Sweongyo 293191983Sweongyovoid 294191983Sweongyousage() 295191983Sweongyo{ 296191983Sweongyo fprintf(stderr, "%s\n%s\n%s\n", 297191983Sweongyo "usage: mount_msdosfs [-9ls] [-D DOS_codepage] [-g gid] [-L locale]", 298191983Sweongyo " [-M mask] [-m mask] [-o options] [-u uid]", 299191983Sweongyo " [-W table] special node"); 300199816Sthompsa exit(EX_USAGE); 301191983Sweongyo} 302191983Sweongyo 303191983Sweongyoint 304191983Sweongyoset_charset(struct iovec **iov, int *iovlen, const char *cs_local, const char *cs_dos) 305191983Sweongyo{ 306191983Sweongyo int error; 307191983Sweongyo 308191983Sweongyo if (modfind("msdosfs_iconv") < 0) 309191983Sweongyo if (kldload("msdosfs_iconv") < 0 || modfind("msdosfs_iconv") < 0) { 310191983Sweongyo warnx("cannot find or load \"msdosfs_iconv\" kernel module"); 311191983Sweongyo return (-1); 312191983Sweongyo } 313191983Sweongyo 314191983Sweongyo build_iovec_argf(iov, iovlen, "cs_win", ENCODING_UNICODE); 315191983Sweongyo error = kiconv_add_xlat16_cspairs(ENCODING_UNICODE, cs_local); 316191983Sweongyo if (error) 317191983Sweongyo return (-1); 318191983Sweongyo if (cs_dos != NULL) { 319191983Sweongyo error = kiconv_add_xlat16_cspairs(cs_dos, cs_local); 320191983Sweongyo if (error) 321191983Sweongyo return (-1); 322191983Sweongyo } else { 323191983Sweongyo build_iovec_argf(iov, iovlen, "cs_dos", cs_local); 324191983Sweongyo error = kiconv_add_xlat16_cspair(cs_local, cs_local, 325191983Sweongyo KICONV_FROM_UPPER | KICONV_LOWER); 326191983Sweongyo if (error) 327191983Sweongyo return (-1); 328191983Sweongyo } 329191983Sweongyo 330191983Sweongyo return (0); 331191983Sweongyo} 332191983Sweongyo