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