Home | History | Annotate | Line # | Download | only in mount
mount_linux.c revision 1.1.1.1.4.2
      1 /*	$NetBSD: mount_linux.c,v 1.1.1.1.4.2 2008/10/19 22:39:35 haad Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997-2007 Erez Zadok
      5  * Copyright (c) 1990 Jan-Simon Pendry
      6  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
      7  * Copyright (c) 1990 The Regents of the University of California.
      8  * All rights reserved.
      9  *
     10  * This code is derived from software contributed to Berkeley by
     11  * Jan-Simon Pendry at Imperial College, London.
     12  *
     13  * Redistribution and use in source and binary forms, with or without
     14  * modification, are permitted provided that the following conditions
     15  * are met:
     16  * 1. Redistributions of source code must retain the above copyright
     17  *    notice, this list of conditions and the following disclaimer.
     18  * 2. Redistributions in binary form must reproduce the above copyright
     19  *    notice, this list of conditions and the following disclaimer in the
     20  *    documentation and/or other materials provided with the distribution.
     21  * 3. All advertising materials mentioning features or use of this software
     22  *    must display the following acknowledgment:
     23  *      This product includes software developed by the University of
     24  *      California, Berkeley and its contributors.
     25  * 4. Neither the name of the University nor the names of its contributors
     26  *    may be used to endorse or promote products derived from this software
     27  *    without specific prior written permission.
     28  *
     29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     39  * SUCH DAMAGE.
     40  *
     41  *
     42  * File: am-utils/conf/mount/mount_linux.c
     43  */
     44 
     45 /*
     46  * Linux mount helper.
     47  */
     48 
     49 #ifdef HAVE_CONFIG_H
     50 # include <config.h>
     51 #endif /* HAVE_CONFIG_H */
     52 #include <am_defs.h>
     53 #include <amu.h>
     54 
     55 
     56 #ifndef MOUNT_TYPE_UFS
     57 /*
     58  * Autoconf didn't find any disk-based f/s on this system,
     59  * So provide some default definition for this file to compile.
     60  */
     61 # define MOUNT_TYPE_UFS		"no_disk_fs"
     62 #endif /* not MOUNT_TYPE_UFS */
     63 
     64 struct opt_map {
     65   const char *opt;		/* option name */
     66   int inv;			/* true if flag value should be inverted */
     67   int mask;			/* flag mask value */
     68 };
     69 
     70 const struct opt_map opt_map[] =
     71 {
     72   {"defaults",		0,	0},
     73   {MNTTAB_OPT_RO,	0,	MNT2_GEN_OPT_RDONLY},
     74   {MNTTAB_OPT_RW,	1,	MNT2_GEN_OPT_RDONLY},
     75   {MNTTAB_OPT_EXEC,	1,	MNT2_GEN_OPT_NOEXEC},
     76   {MNTTAB_OPT_NOEXEC,	0,	MNT2_GEN_OPT_NOEXEC},
     77   {MNTTAB_OPT_SUID,	1,	MNT2_GEN_OPT_NOSUID},
     78   {MNTTAB_OPT_NOSUID,	0,	MNT2_GEN_OPT_NOSUID},
     79 #ifdef MNT2_GEN_OPT_NODEV
     80   {MNTTAB_OPT_NODEV,	0,	MNT2_GEN_OPT_NODEV},
     81 #endif /* MNT2_GEN_OPT_NODEV */
     82 #ifdef MNT2_GEN_OPT_SYNC
     83   {MNTTAB_OPT_SYNC,	0,	MNT2_GEN_OPT_SYNC},
     84   {MNTTAB_OPT_ASYNC,	1,	MNT2_GEN_OPT_SYNC},
     85 #endif /* MNT2_GEN_OPT_SYNC */
     86 #ifdef MNT2_GEN_OPT_NOSUB
     87   {MNTTAB_OPT_SUB,	1,	MNT2_GEN_OPT_NOSUB},
     88   {MNTTAB_OPT_NOSUB,	0,	MNT2_GEN_OPT_NOSUB},
     89 #endif /* MNT2_GEN_OPT_NOSUB */
     90   {NULL,		0,	0}
     91 };
     92 
     93 struct fs_opts {
     94   const char *opt;
     95   int type;			/* XXX: Ion, what is this for? */
     96 };
     97 
     98 const struct fs_opts iso_opts[] = {
     99   { "map",	0 },
    100   { "norock",	0 },
    101   { "cruft",	0 },
    102   { "unhide",	0 },
    103   { "conv",	1 },
    104   { "block",	1 },
    105   { "mode",	1 },
    106   { "gid",	1 },
    107   { "uid",	1 },
    108   { NULL,	0 }
    109 };
    110 
    111 const struct fs_opts dos_opts[] = {
    112   { "check",	1 },
    113   { "conv",	1 },
    114   { "uid",	1 },
    115   { "gid",	1 },
    116   { "umask",	1 },
    117   { "debug",	0 },
    118   { "fat",	1 },
    119   { "quiet",	0 },
    120   { "blocksize",1 },
    121   { NULL,	0 }
    122 };
    123 
    124 const struct fs_opts autofs_opts[] = {
    125   { "fd",	1 },
    126   { "pgrp",	1 },
    127   { "minproto",	1 },
    128   { "maxproto",	1 },
    129   { NULL,	0 }
    130 };
    131 
    132 const struct fs_opts null_opts[] = {
    133   { NULL,	0 }
    134 };
    135 
    136 
    137 /*
    138  * New parser for linux-specific mounts.
    139  * Should now handle fs-type specific mount-options correctly.
    140  * Currently implemented: msdos, iso9660.
    141  */
    142 static char *
    143 parse_opts(char *type, const char *optstr, int *flags, char **xopts, int *noauto)
    144 {
    145   const struct opt_map *std_opts;
    146   const struct fs_opts *dev_opts;
    147   char *opt, *topts, *xoptstr;
    148   size_t l;
    149 
    150   if (optstr == NULL)
    151     return NULL;
    152 
    153   xoptstr = strdup(optstr);	/* because strtok is destructive below */
    154 
    155   *noauto = 0;
    156   l = strlen(optstr) + 2;
    157   *xopts = (char *) xmalloc(l);
    158   topts = (char *) xmalloc(l);
    159   *topts = '\0';
    160   **xopts = '\0';
    161 
    162   for (opt = strtok(xoptstr, ","); opt; opt = strtok(NULL, ",")) {
    163     /*
    164      * First, parse standard options
    165      */
    166     std_opts = opt_map;
    167     while (std_opts->opt &&
    168 	   !NSTREQ(std_opts->opt, opt, strlen(std_opts->opt)))
    169       ++std_opts;
    170     if (!(*noauto = STREQ(opt, MNTTAB_OPT_NOAUTO)) || std_opts->opt) {
    171       xstrlcat(topts, opt, l);
    172       xstrlcat(topts, ",", l);
    173       if (std_opts->inv)
    174 	*flags &= ~std_opts->mask;
    175       else
    176 	*flags |= std_opts->mask;
    177     }
    178     /*
    179      * Next, select which fs-type is to be used
    180      * and parse the fs-specific options
    181      */
    182 #ifdef MOUNT_TYPE_AUTOFS
    183     if (STREQ(type, MOUNT_TYPE_AUTOFS)) {
    184       dev_opts = autofs_opts;
    185       goto do_opts;
    186     }
    187 #endif /* MOUNT_TYPE_AUTOFS */
    188 #ifdef MOUNT_TYPE_PCFS
    189     if (STREQ(type, MOUNT_TYPE_PCFS)) {
    190       dev_opts = dos_opts;
    191       goto do_opts;
    192     }
    193 #endif /* MOUNT_TYPE_PCFS */
    194 #ifdef MOUNT_TYPE_CDFS
    195     if (STREQ(type, MOUNT_TYPE_CDFS)) {
    196       dev_opts = iso_opts;
    197       goto do_opts;
    198     }
    199 #endif /* MOUNT_TYPE_CDFS */
    200 #ifdef MOUNT_TYPE_LOFS
    201     if (STREQ(type, MOUNT_TYPE_LOFS)) {
    202       dev_opts = null_opts;
    203       goto do_opts;
    204     }
    205 #endif /* MOUNT_TYPE_LOFS */
    206     plog(XLOG_FATAL, "linux mount: unknown fs-type: %s\n", type);
    207     XFREE(xoptstr);
    208     XFREE(*xopts);
    209     XFREE(topts);
    210     return NULL;
    211 
    212 do_opts:
    213     while (dev_opts->opt &&
    214 	   (!NSTREQ(dev_opts->opt, opt, strlen(dev_opts->opt)))) {
    215       ++dev_opts;
    216     }
    217     if (dev_opts->opt && *xopts) {
    218       xstrlcat(*xopts, opt, l);
    219       xstrlcat(*xopts, ",", l);
    220     }
    221   }
    222   /*
    223    * All other options are discarded
    224    */
    225   if (strlen(*xopts))
    226     *(*xopts + strlen(*xopts)-1) = '\0';
    227   if (strlen(topts))
    228     topts[strlen(topts)-1] = '\0';
    229   XFREE(xoptstr);
    230   return topts;
    231 }
    232 
    233 
    234 /*
    235  * Returns combined linux kernel version number.  For a kernel numbered
    236  * x.y.z, returns x*65535+y*256+z.
    237  */
    238 int
    239 linux_version_code(void)
    240 {
    241   struct utsname my_utsname;
    242   static int release = 0;
    243 
    244   if ( 0 == release && 0 == uname(&my_utsname)) {
    245     release = 65536 * atoi(strtok(my_utsname.release, "."))
    246       + 256 * atoi(strtok(NULL, "."))
    247       + atoi(strtok(NULL, "."));
    248   }
    249   return release;
    250 }
    251 
    252 
    253 int
    254 do_mount_linux(MTYPE_TYPE type, mntent_t *mnt, int flags, caddr_t data)
    255 {
    256   if (amuDebug(D_FULL)) {
    257     plog(XLOG_DEBUG, "do_mount_linux: fsname %s\n", mnt->mnt_fsname);
    258     plog(XLOG_DEBUG, "do_mount_linux: type (mntent) %s\n", mnt->mnt_type);
    259     plog(XLOG_DEBUG, "do_mount_linux: opts %s\n", mnt->mnt_opts);
    260     plog(XLOG_DEBUG, "do_mount_linux: dir %s\n", mnt->mnt_dir);
    261   }
    262 
    263   /*
    264    * If we have an nfs mount, the 5th argument to system mount() must be the
    265    * nfs_mount_data structure, otherwise it is the return from parse_opts()
    266    */
    267   return mount(mnt->mnt_fsname,
    268 	       mnt->mnt_dir,
    269 	       type,
    270 	       MS_MGC_VAL | flags,
    271 	       data);
    272 }
    273 
    274 
    275 int
    276 mount_linux_nfs(MTYPE_TYPE type, mntent_t *mnt, int flags, caddr_t data)
    277 {
    278   nfs_args_t *mnt_data = (nfs_args_t *) data;
    279   int errorcode;
    280 
    281   /* Fake some values for linux */
    282   mnt_data->version = NFS_MOUNT_VERSION;
    283   if (!mnt_data->timeo) {
    284 #ifdef MNT2_NFS_OPT_TCP
    285     if (mnt_data->flags & MNT2_NFS_OPT_TCP)
    286       mnt_data->timeo = 600;
    287     else
    288 #endif /* MNT2_NFS_OPT_TCP */
    289       mnt_data->timeo = 7;
    290   }
    291   if (!mnt_data->retrans)
    292     mnt_data->retrans = 3;
    293 
    294 #ifdef MNT2_NFS_OPT_NOAC
    295   if (!(mnt_data->flags & MNT2_NFS_OPT_NOAC)) {
    296     if (!mnt_data->acregmin)
    297       mnt_data->acregmin = 3;
    298     if (!mnt_data->acregmax)
    299       mnt_data->acregmax = 60;
    300     if (!mnt_data->acdirmin)
    301       mnt_data->acdirmin = 30;
    302     if (!mnt_data->acdirmax)
    303       mnt_data->acdirmax = 60;
    304   }
    305 #endif /* MNT2_NFS_OPT_NOAC */
    306 
    307   /*
    308    * in nfs structure implementation version 4, the old
    309    * filehandle field was renamed "old_root" and left as 3rd field,
    310    * while a new field called "root" was added to the end of the
    311    * structure. Both of them however need a copy of the file handle
    312    * for NFSv2 mounts.
    313    */
    314 #ifdef MNT2_NFS_OPT_VER3
    315   if (mnt_data->flags & MNT2_NFS_OPT_VER3)
    316     memset(mnt_data->old_root.data, 0, FHSIZE);
    317   else
    318 #endif /* MNT2_NFS_OPT_VER3 */
    319     memcpy(mnt_data->old_root.data, mnt_data->root.data, FHSIZE);
    320 
    321 #ifdef HAVE_NFS_ARGS_T_BSIZE
    322   /* linux mount version 3 */
    323   mnt_data->bsize = 0;			/* let the kernel decide */
    324 #endif /* HAVE_NFS_ARGS_T_BSIZE */
    325 
    326 #ifdef HAVE_NFS_ARGS_T_NAMLEN
    327   /* linux mount version 2 */
    328   mnt_data->namlen = NAME_MAX;		/* 256 bytes */
    329 #endif /* HAVE_NFS_ARGS_T_NAMELEN */
    330 
    331   mnt_data->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    332   if (mnt_data->fd < 0) {
    333     plog(XLOG_ERROR, "Can't create socket for kernel");
    334     return 1;
    335   }
    336   if (bindresvport(mnt_data->fd, NULL) < 0) {
    337     plog(XLOG_ERROR, "Can't bind to reserved port");
    338     errorcode = 1;
    339     goto out;
    340   }
    341   /*
    342    * connect() the socket for kernels 1.3.10 and below
    343    * only to avoid problems with multihomed hosts.
    344    */
    345   if (linux_version_code() <= 0x01030a) {
    346     int ret = connect(mnt_data->fd,
    347 		      (struct sockaddr *) &mnt_data->addr,
    348 		      sizeof(mnt_data->addr));
    349     if (ret < 0) {
    350       plog(XLOG_ERROR, "Can't connect socket for kernel");
    351       errorcode = 1;
    352       goto out;
    353     }
    354   }
    355   if (amuDebug(D_FULL)) {
    356     plog(XLOG_DEBUG, "mount_linux_nfs: type %s\n", type);
    357     plog(XLOG_DEBUG, "mount_linux_nfs: version %d\n", mnt_data->version);
    358     plog(XLOG_DEBUG, "mount_linux_nfs: fd %d\n", mnt_data->fd);
    359     plog(XLOG_DEBUG, "mount_linux_nfs: hostname %s\n",
    360 	 inet_ntoa(mnt_data->addr.sin_addr));
    361     plog(XLOG_DEBUG, "mount_linux_nfs: port %d\n",
    362 	 htons(mnt_data->addr.sin_port));
    363   }
    364   if (amuDebug(D_TRACE)) {
    365     plog(XLOG_DEBUG, "mount_linux_nfs: Generic mount flags 0x%x", MS_MGC_VAL | flags);
    366     plog(XLOG_DEBUG, "mount_linux_nfs: updated nfs_args...");
    367     print_nfs_args(mnt_data, 0);
    368   }
    369 
    370   errorcode = do_mount_linux(type, mnt, flags, data);
    371 
    372  out:
    373   /*
    374    * If we failed, (i.e. errorcode != 0), then close the socket
    375    * if it is open.
    376    */
    377   if (errorcode && mnt_data->fd != -1) {
    378     /* save errno, may be clobbered by close() call! */
    379     int save_errno = errno;
    380     close(mnt_data->fd);
    381     errno = save_errno;
    382   }
    383   return errorcode;
    384 }
    385 
    386 
    387 int
    388 mount_linux_nonfs(MTYPE_TYPE type, mntent_t *mnt, int flags, caddr_t data)
    389 {
    390   char *extra_opts = NULL;
    391   char *tmp_opts = NULL;
    392   char *sub_type = NULL;
    393   char *loopdev = NULL;
    394   int noauto = 0;
    395   int errorcode;
    396 
    397   sub_type = hasmnteq(mnt, "type");
    398   if (sub_type) {
    399     sub_type = strdup(sub_type);
    400     if (sub_type) {		/* the strdup malloc might have failed */
    401       type = strpbrk(sub_type, ",:;\n\t");
    402       if (type == NULL)
    403 	type = MOUNT_TYPE_UFS;
    404       else {
    405 	*type = '\0';
    406 	type = sub_type;
    407       }
    408     } else {
    409       plog(XLOG_ERROR, "strdup returned null in mount_linux_nonfs");
    410     }
    411   }
    412 
    413   if (!hasmntopt(mnt, "type"))
    414     mnt->mnt_type = type;
    415 
    416   tmp_opts = parse_opts(type, mnt->mnt_opts, &flags, &extra_opts, &noauto);
    417 
    418 #ifdef MOUNT_TYPE_LOFS
    419   if (STREQ(type, MOUNT_TYPE_LOFS)) {
    420 # ifndef MNT2_GEN_OPT_BIND
    421     size_t l;
    422     /* this is basically a hack to support fist lofs */
    423     XFREE(extra_opts);
    424     l = strlen(mnt->mnt_fsname) + sizeof("dir=") + 1;
    425     extra_opts = (char *) xmalloc(l);
    426     xsnprintf(extra_opts, l, sizeof(extra_opts), "dir=%s", mnt->mnt_fsname);
    427 # else /* MNT2_GEN_OPT_BIND */
    428     /* use bind mounts for lofs */
    429     flags |= MNT2_GEN_OPT_BIND;
    430 # endif /* MNT2_GEN_OPT_BIND */
    431     errorcode = do_mount_linux(type, mnt, flags, extra_opts);
    432   } else /* end of "if type is LOFS" */
    433 #endif /* MOUNT_TYPE_LOFS */
    434 
    435   {
    436 #ifdef HAVE_LOOP_DEVICE
    437     /*
    438      * If the mounted "device" is actually a regular file,
    439      # try to attach a loop device to it.
    440      */
    441     struct stat buf;
    442     char *old_fsname = NULL;
    443     if (stat(mnt->mnt_fsname, &buf) == 0 &&
    444 	S_ISREG(buf.st_mode)) {
    445       if ((loopdev = setup_loop_device(mnt->mnt_fsname)) != NULL) {
    446 	char *str;
    447 	size_t l;
    448 
    449 	plog(XLOG_INFO, "setup loop device %s over %s OK", loopdev, mnt->mnt_fsname);
    450 	old_fsname = mnt->mnt_fsname;
    451 	mnt->mnt_fsname = loopdev;
    452 	/* XXX: hack, append loop=/dev/loopX to mnttab opts */
    453 	l = strlen(mnt->mnt_opts) + 7 + strlen(loopdev);
    454 	str = (char *) xmalloc(l);
    455 	if (str) {
    456 	  xsnprintf(str, l, "%s,loop=%s", mnt->mnt_opts, loopdev);
    457 	  XFREE(mnt->mnt_opts);
    458 	  mnt->mnt_opts = str;
    459 	}
    460       } else {
    461 	plog(XLOG_ERROR, "failed to set up a loop device: %m");
    462 	errorcode = 1;
    463 	goto out;
    464       }
    465     }
    466 #endif /* HAVE_LOOP_DEVICE */
    467 
    468     errorcode = do_mount_linux(type, mnt, flags, extra_opts);
    469 
    470 #ifdef HAVE_LOOP_DEVICE
    471     /* if mount failed and we used a loop device, then undo it */
    472     if (errorcode != 0 && loopdev != NULL) {
    473       if (delete_loop_device(loopdev) < 0)
    474 	plog(XLOG_WARNING, "mount() failed to release loop device %s: %m", loopdev);
    475       else
    476 	plog(XLOG_INFO, "mount() released loop device %s OK", loopdev);
    477     }
    478     if (old_fsname)
    479       mnt->mnt_fsname = old_fsname;
    480 #endif /* HAVE_LOOP_DEVICE */
    481   }
    482 
    483   /*
    484    * Free all allocated space and return errorcode.
    485    */
    486 out:
    487 if (loopdev)
    488      XFREE(loopdev);
    489   if (extra_opts != NULL)
    490     XFREE(extra_opts);
    491   if (tmp_opts != NULL)
    492     XFREE(tmp_opts);
    493   if (sub_type != NULL)
    494     XFREE(sub_type);
    495   return errorcode;
    496 }
    497 
    498 
    499 int
    500 mount_linux(MTYPE_TYPE type, mntent_t *mnt, int flags, caddr_t data)
    501 {
    502   int errorcode;
    503 
    504   if (mnt->mnt_opts && STREQ(mnt->mnt_opts, "defaults"))
    505     mnt->mnt_opts = NULL;
    506 
    507   if (type == NULL)
    508     type = index(mnt->mnt_fsname, ':') ? MOUNT_TYPE_NFS : MOUNT_TYPE_UFS;
    509 
    510   if (STREQ(type, MOUNT_TYPE_NFS))
    511     errorcode = mount_linux_nfs(type, mnt, flags, data);
    512   else				/* non-NFS mounts */
    513     errorcode = mount_linux_nonfs(type, mnt, flags, data);
    514 
    515   return errorcode;
    516 }
    517 
    518 
    519 /****************************************************************************/
    520 /*
    521  * NFS error numbers and Linux errno's are two different things!  Linux is
    522  * `worse' than other OSes in the respect that it loudly complains about
    523  * undefined NFS return value ("bad NFS return value..").  So we should
    524  * translate ANY possible Linux errno to their NFS equivalent.  Just, there
    525  * aren't much NFS numbers, so most go to EINVAL or EIO.  The mapping below
    526  * should fit at least for Linux/i386 and Linux/68k.  I haven't checked
    527  * other architectures yet.
    528  */
    529 
    530 #define NE_PERM		1
    531 #define NE_NOENT	2
    532 #define NE_IO		5
    533 #define NE_NXIO		6
    534 #define NE_AGAIN	11
    535 #define NE_ACCES	13
    536 #define NE_EXIST	17
    537 #define NE_NODEV	19
    538 #define NE_NOTDIR	20
    539 #define NE_ISDIR	21
    540 #define NE_INVAL	22
    541 #define NE_FBIG		27
    542 #define NE_NOSPC	28
    543 #define NE_ROFS		30
    544 #define NE_OPNOTSUPP	45
    545 #define NE_NAMETOOLONG	63
    546 #define NE_NOTEMPTY	66
    547 #define NE_DQUOT	69
    548 #define NE_STALE	70
    549 #define NE_REMOTE	71
    550 
    551 #define NFS_LOMAP	0
    552 #define NFS_HIMAP	122
    553 
    554 /*
    555  * The errno's below are correct for Linux/i386. One day, somebody
    556  * with lots of energy ought to verify them against the other ports...
    557  */
    558 static int nfs_errormap[] = {
    559 	0,		/* success(0)		*/
    560 	NE_PERM,	/* EPERM (1)		*/
    561 	NE_NOENT,	/* ENOENT (2)		*/
    562 	NE_INVAL,	/* ESRCH (3)		*/
    563 	NE_IO,		/* EINTR (4)		*/
    564 	NE_IO,		/* EIO (5)		*/
    565 	NE_NXIO,	/* ENXIO (6)		*/
    566 	NE_INVAL,	/* E2BIG (7)		*/
    567 	NE_INVAL,	/* ENOEXEC (8)		*/
    568 	NE_INVAL,	/* EBADF (9)		*/
    569 	NE_IO,		/* ECHILD (10)		*/
    570 	NE_AGAIN,	/* EAGAIN (11)		*/
    571 	NE_IO,		/* ENOMEM (12)		*/
    572 	NE_ACCES,	/* EACCES (13)		*/
    573 	NE_INVAL,	/* EFAULT (14)		*/
    574 	NE_INVAL,	/* ENOTBLK (15)		*/
    575 	NE_IO,		/* EBUSY (16)		*/
    576 	NE_EXIST,	/* EEXIST (17)		*/
    577 	NE_INVAL,	/* EXDEV (18)		*/
    578 	NE_NODEV,	/* ENODEV (19)		*/
    579 	NE_NOTDIR,	/* ENOTDIR (20)		*/
    580 	NE_ISDIR,	/* EISDIR (21)		*/
    581 	NE_INVAL,	/* EINVAL (22)		*/
    582 	NE_IO,		/* ENFILE (23)		*/
    583 	NE_IO,		/* EMFILE (24)		*/
    584 	NE_INVAL,	/* ENOTTY (25)		*/
    585 	NE_ACCES,	/* ETXTBSY (26)		*/
    586 	NE_FBIG,	/* EFBIG (27)		*/
    587 	NE_NOSPC,	/* ENOSPC (28)		*/
    588 	NE_INVAL,	/* ESPIPE (29)		*/
    589 	NE_ROFS,	/* EROFS (30)		*/
    590 	NE_INVAL,	/* EMLINK (31)		*/
    591 	NE_INVAL,	/* EPIPE (32)		*/
    592 	NE_INVAL,	/* EDOM (33)		*/
    593 	NE_INVAL,	/* ERANGE (34)		*/
    594 	NE_INVAL,	/* EDEADLK (35)		*/
    595 	NE_NAMETOOLONG,	/* ENAMETOOLONG (36)	*/
    596 	NE_INVAL,	/* ENOLCK (37)		*/
    597 	NE_INVAL,	/* ENOSYS (38)		*/
    598 	NE_NOTEMPTY,	/* ENOTEMPTY (39)	*/
    599 	NE_INVAL,	/* ELOOP (40)		*/
    600 	NE_INVAL,	/* unused (41)		*/
    601 	NE_INVAL,	/* ENOMSG (42)		*/
    602 	NE_INVAL,	/* EIDRM (43)		*/
    603 	NE_INVAL,	/* ECHRNG (44)		*/
    604 	NE_INVAL,	/* EL2NSYNC (45)	*/
    605 	NE_INVAL,	/* EL3HLT (46)		*/
    606 	NE_INVAL,	/* EL3RST (47)		*/
    607 	NE_INVAL,	/* ELNRNG (48)		*/
    608 	NE_INVAL,	/* EUNATCH (49)		*/
    609 	NE_INVAL,	/* ENOCSI (50)		*/
    610 	NE_INVAL,	/* EL2HLT (51)		*/
    611 	NE_INVAL,	/* EBADE (52)		*/
    612 	NE_INVAL,	/* EBADR (53)		*/
    613 	NE_INVAL,	/* EXFULL (54)		*/
    614 	NE_INVAL,	/* ENOANO (55)		*/
    615 	NE_INVAL,	/* EBADRQC (56)		*/
    616 	NE_INVAL,	/* EBADSLT (57)		*/
    617 	NE_INVAL,	/* unused (58)		*/
    618 	NE_INVAL,	/* EBFONT (59)		*/
    619 	NE_INVAL,	/* ENOSTR (60)		*/
    620 	NE_INVAL,	/* ENODATA (61)		*/
    621 	NE_INVAL,	/* ETIME (62)		*/
    622 	NE_INVAL,	/* ENOSR (63)		*/
    623 	NE_INVAL,	/* ENONET (64)		*/
    624 	NE_INVAL,	/* ENOPKG (65)		*/
    625 	NE_INVAL,	/* EREMOTE (66)		*/
    626 	NE_INVAL,	/* ENOLINK (67)		*/
    627 	NE_INVAL,	/* EADV (68)		*/
    628 	NE_INVAL,	/* ESRMNT (69)		*/
    629 	NE_IO,		/* ECOMM (70)		*/
    630 	NE_IO,		/* EPROTO (71)		*/
    631 	NE_IO,		/* EMULTIHOP (72)	*/
    632 	NE_IO,		/* EDOTDOT (73)		*/
    633 	NE_INVAL,	/* EBADMSG (74)		*/
    634 	NE_INVAL,	/* EOVERFLOW (75)	*/
    635 	NE_INVAL,	/* ENOTUNIQ (76)	*/
    636 	NE_INVAL,	/* EBADFD (77)		*/
    637 	NE_IO,		/* EREMCHG (78)		*/
    638 	NE_IO,		/* ELIBACC (79)		*/
    639 	NE_IO,		/* ELIBBAD (80)		*/
    640 	NE_IO,		/* ELIBSCN (81)		*/
    641 	NE_IO,		/* ELIBMAX (82)		*/
    642 	NE_IO,		/* ELIBEXEC (83)	*/
    643 	NE_INVAL,	/* EILSEQ (84)		*/
    644 	NE_INVAL,	/* ERESTART (85)	*/
    645 	NE_INVAL,	/* ESTRPIPE (86)	*/
    646 	NE_INVAL,	/* EUSERS (87)		*/
    647 	NE_INVAL,	/* ENOTSOCK (88)	*/
    648 	NE_INVAL,	/* EDESTADDRREQ (89)	*/
    649 	NE_INVAL,	/* EMSGSIZE (90)	*/
    650 	NE_INVAL,	/* EPROTOTYPE (91)	*/
    651 	NE_INVAL,	/* ENOPROTOOPT (92)	*/
    652 	NE_INVAL,	/* EPROTONOSUPPORT (93) */
    653 	NE_INVAL,	/* ESOCKTNOSUPPORT (94) */
    654 	NE_INVAL,	/* EOPNOTSUPP (95)	*/
    655 	NE_INVAL,	/* EPFNOSUPPORT (96)	*/
    656 	NE_INVAL,	/* EAFNOSUPPORT (97)	*/
    657 	NE_INVAL,	/* EADDRINUSE (98)	*/
    658 	NE_INVAL,	/* EADDRNOTAVAIL (99)	*/
    659 	NE_IO,		/* ENETDOWN (100)	*/
    660 	NE_IO,		/* ENETUNREACH (101)	*/
    661 	NE_IO,		/* ENETRESET (102)	*/
    662 	NE_IO,		/* ECONNABORTED (103)	*/
    663 	NE_IO,		/* ECONNRESET (104)	*/
    664 	NE_IO,		/* ENOBUFS (105)	*/
    665 	NE_IO,		/* EISCONN (106)	*/
    666 	NE_IO,		/* ENOTCONN (107)	*/
    667 	NE_IO,		/* ESHUTDOWN (108)	*/
    668 	NE_IO,		/* ETOOMANYREFS (109)	*/
    669 	NE_IO,		/* ETIMEDOUT (110)	*/
    670 	NE_IO,		/* ECONNREFUSED (111)	*/
    671 	NE_IO,		/* EHOSTDOWN (112)	*/
    672 	NE_IO,		/* EHOSTUNREACH (113)	*/
    673 	NE_IO,		/* EALREADY (114)	*/
    674 	NE_IO,		/* EINPROGRESS (115)	*/
    675 	NE_STALE,	/* ESTALE (116)		*/
    676 	NE_IO,		/* EUCLEAN (117)	*/
    677 	NE_INVAL,	/* ENOTNAM (118)	*/
    678 	NE_INVAL,	/* ENAVAIL (119)	*/
    679 	NE_INVAL,	/* EISNAM (120)		*/
    680 	NE_IO,		/* EREMOTEIO (121)	*/
    681 	NE_DQUOT,	/* EDQUOT (122)		*/
    682 };
    683 
    684 
    685 int
    686 linux_nfs_error(int e)
    687 {
    688   int ret = (nfsstat) NE_IO;
    689 
    690   if (e < NFS_LOMAP || e > NFS_HIMAP)
    691     ret = (nfsstat) NE_IO;
    692   else
    693     ret = nfs_errormap[e - NFS_LOMAP];
    694   dlog("linux_nfs_error: map error %d to NFS error %d", e, ret);
    695   return (nfsstat) ret;
    696 }
    697 
    698 
    699 #ifdef HAVE_LOOP_DEVICE
    700 /****************************************************************************/
    701 /*** LOOP DEVICE SUPPORT						  ***/
    702 /*** Loop Device setup code taken from mount-2.11g-5.src.rpm, which was   ***/
    703 /*** originally written bt Ted T'so and others.				  ***/
    704 /****************************************************************************/
    705 
    706 #define PROC_DEVICES	"/proc/devices"
    707 
    708 #if not_used_yet
    709 static int
    710 show_loop(char *device)
    711 {
    712   struct loop_info loopinfo;
    713   int fd;
    714 
    715   if ((fd = open(device, O_RDONLY)) < 0) {
    716     dlog("loop: can't open device %s: %m", device);
    717     return -2;
    718   }
    719   if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) < 0) {
    720     dlog("loop: can't get info on device %s: %m", device);
    721     close(fd);
    722     return -1;
    723   }
    724   dlog("show_loop: %s: [%04x]:%ld (%s)",
    725        device, loopinfo.lo_device, loopinfo.lo_inode,
    726        loopinfo.lo_name);
    727 
    728   close(fd);
    729 
    730   return 0;
    731 }
    732 
    733 
    734 static int
    735 is_loop_device(const char *device)
    736 {
    737   struct stat statbuf;
    738   int loopmajor = 7;
    739 
    740   return (loopmajor && stat(device, &statbuf) == 0 &&
    741 	  S_ISBLK(statbuf.st_mode) &&
    742 	  (statbuf.st_rdev>>8) == loopmajor);
    743 }
    744 #endif /* not_used_yet */
    745 
    746 
    747 /*
    748  * Just creating a device, say in /tmp, is probably a bad idea - people
    749  * might have problems with backup or so.  So, we just try /dev/loop[0-7].
    750  */
    751 static char *
    752 find_unused_loop_device(void)
    753 {
    754   char dev[20];
    755   char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
    756   int i, j, fd, somedev = 0, someloop = 0, loop_known = 0;
    757   struct stat statbuf;
    758   struct loop_info loopinfo;
    759   FILE *procdev;
    760 
    761 #define LOOP_FMT_SIZE(a) (sizeof(a)/sizeof(a[0]))
    762   for (j = 0; j < (int) LOOP_FMT_SIZE(loop_formats); j++) {
    763     for (i = 0; i < 256; i++) {
    764       xsnprintf(dev, sizeof(dev), loop_formats[j], i);
    765       if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
    766 	somedev++;
    767 	fd = open(dev, O_RDONLY);
    768 	if (fd >= 0) {
    769 	  if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) == 0)
    770 	    someloop++;		/* in use */
    771 	  else if (errno == ENXIO) {
    772 	    close(fd);
    773 	    return strdup(dev); /* probably free */
    774 	  }
    775 	  close(fd);
    776 	}
    777 	continue;		/* continue trying as long as devices exist */
    778       }
    779       break;
    780     }
    781   }
    782 
    783   /* Nothing found. Why not? */
    784   if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
    785     char line[100];
    786     while (fgets(line, sizeof(line), procdev))
    787       if (strstr(line, " loop\n")) {
    788 	loop_known = 1;
    789 	break;
    790       }
    791     fclose(procdev);
    792     if (!loop_known)
    793       loop_known = -1;
    794   }
    795 
    796   if (!somedev) {
    797     dlog("Could not find any device /dev/loop#");
    798   } else if (!someloop) {
    799     if (loop_known == 1) {
    800       dlog("Could not find any loop device.");
    801       dlog("...Maybe /dev/loop# has a wrong major number?");
    802     }
    803     else if (loop_known == -1) {
    804       dlog("Could not find any loop device, and, according to %s,", PROC_DEVICES);
    805       dlog("...this kernel does not know about the loop device.");
    806       dlog("... (If so, then recompile or `insmod loop.o'.)");
    807     } else {
    808       dlog("Could not find any loop device. Maybe this kernel does not know,");
    809       dlog("...about the loop device (then recompile or `insmod loop.o'), or");
    810       dlog("...maybe /dev/loop# has the wrong major number?");
    811     }
    812   } else {
    813     dlog("Could not find any free loop device!");
    814   }
    815   return NULL;
    816 }
    817 
    818 
    819 /* returns 0 if OK, -1 otherwise */
    820 char *
    821 setup_loop_device(const char *file)
    822 {
    823   struct loop_info loopinfo;
    824   int fd, ffd, mode, err = -1;
    825   char *device = find_unused_loop_device();
    826 
    827   if (!device) {
    828     dlog("no unused loop device");
    829     goto out;
    830   }
    831 
    832   mode = O_RDWR | O_LARGEFILE;
    833   if ((ffd = open(file, mode)) < 0) {
    834     if (errno == EROFS) {
    835       mode = O_RDONLY | O_LARGEFILE;
    836       ffd = open(file, mode);
    837     }
    838     if (ffd < 0) {
    839       dlog("%s: %m", file);
    840       goto out;
    841     }
    842   }
    843   if ((fd = open(device, mode)) < 0) {
    844     dlog("%s: %m", device);
    845     goto out_close;
    846   }
    847 
    848   memset(&loopinfo, 0, sizeof(loopinfo));
    849   xstrlcpy(loopinfo.lo_name, file, LO_NAME_SIZE);
    850   loopinfo.lo_offset = 0;
    851 
    852   if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
    853     dlog("ioctl: LOOP_SET_FD: %m");
    854     goto out_close_all;
    855   }
    856   if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
    857     (void) ioctl(fd, LOOP_CLR_FD, 0);
    858     dlog("ioctl: LOOP_SET_STATUS: %m");
    859     goto out_close_all;
    860   }
    861 
    862   /* if gets here, all is OK */
    863   err = 0;
    864 
    865 out_close_all:
    866   close(fd);
    867 out_close:
    868   close(ffd);
    869 out:
    870 
    871   if (err) {
    872     XFREE(device);
    873     return NULL;
    874   } else {
    875     dlog("setup_loop_device(%s,%s): success", device, file);
    876     return device;
    877   }
    878 }
    879 
    880 
    881 int
    882 delete_loop_device(const char *device)
    883 {
    884   int fd;
    885 
    886   if ((fd = open(device, O_RDONLY)) < 0) {
    887     dlog("delete_loop_device: can't delete device %s: %m", device);
    888     return -1;
    889   }
    890   if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
    891     dlog("ioctl: LOOP_CLR_FD: %m");
    892     return -1;
    893   }
    894   close(fd);
    895   dlog("delete_loop_device(%s): success", device);
    896   return 0;
    897 }
    898 #endif /* HAVE_LOOP_DEVICE */
    899 
    900 
    901 /****************************************************************************/
    902