1 /*	$NetBSD: mount_linux.c,v 1.1.1.2 2009/03/20 20:26:50 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1997-2009 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 #ifdef HAVE_NFS_ARGS_T_PSEUDOFLAVOR
332   mnt_data->pseudoflavor = 0;
333 #endif /* HAVE_NFS_ARGS_T_PSEUDOFLAVOR */
334 
335 #ifdef HAVE_NFS_ARGS_T_CONTEXT
336   memset(mnt_data->context, 0, sizeof(mnt_data->context));
337 #endif /* HAVE_NFS_ARGS_T_CONTEXT */
338 
339   mnt_data->fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
340   if (mnt_data->fd < 0) {
341     plog(XLOG_ERROR, "Can't create socket for kernel");
342     return 1;
343   }
344   if (bindresvport(mnt_data->fd, NULL) < 0) {
345     plog(XLOG_ERROR, "Can't bind to reserved port");
346     errorcode = 1;
347     goto out;
348   }
349   /*
350    * connect() the socket for kernels 1.3.10 and below
351    * only to avoid problems with multihomed hosts.
352    */
353   if (linux_version_code() <= 0x01030a) {
354     int ret = connect(mnt_data->fd,
355 		      (struct sockaddr *) &mnt_data->addr,
356 		      sizeof(mnt_data->addr));
357     if (ret < 0) {
358       plog(XLOG_ERROR, "Can't connect socket for kernel");
359       errorcode = 1;
360       goto out;
361     }
362   }
363   if (amuDebug(D_FULL)) {
364     plog(XLOG_DEBUG, "mount_linux_nfs: type %s\n", type);
365     plog(XLOG_DEBUG, "mount_linux_nfs: version %d\n", mnt_data->version);
366     plog(XLOG_DEBUG, "mount_linux_nfs: fd %d\n", mnt_data->fd);
367     plog(XLOG_DEBUG, "mount_linux_nfs: hostname %s\n",
368 	 inet_ntoa(mnt_data->addr.sin_addr));
369     plog(XLOG_DEBUG, "mount_linux_nfs: port %d\n",
370 	 htons(mnt_data->addr.sin_port));
371   }
372   if (amuDebug(D_TRACE)) {
373     plog(XLOG_DEBUG, "mount_linux_nfs: Generic mount flags 0x%x", MS_MGC_VAL | flags);
374     plog(XLOG_DEBUG, "mount_linux_nfs: updated nfs_args...");
375     print_nfs_args(mnt_data, 0);
376   }
377 
378   errorcode = do_mount_linux(type, mnt, flags, data);
379 
380  out:
381   /*
382    * If we failed, (i.e. errorcode != 0), then close the socket
383    * if it is open.
384    */
385   if (errorcode && mnt_data->fd != -1) {
386     /* save errno, may be clobbered by close() call! */
387     int save_errno = errno;
388     close(mnt_data->fd);
389     errno = save_errno;
390   }
391   return errorcode;
392 }
393 
394 
395 int
396 mount_linux_nonfs(MTYPE_TYPE type, mntent_t *mnt, int flags, caddr_t data)
397 {
398   char *extra_opts = NULL;
399   char *tmp_opts = NULL;
400   char *sub_type = NULL;
401   char *loopdev = NULL;
402   int noauto = 0;
403   int errorcode;
404 
405   sub_type = hasmnteq(mnt, "type");
406   if (sub_type) {
407     sub_type = strdup(sub_type);
408     if (sub_type) {		/* the strdup malloc might have failed */
409       type = strpbrk(sub_type, ",:;\n\t");
410       if (type == NULL)
411 	type = MOUNT_TYPE_UFS;
412       else {
413 	*type = '\0';
414 	type = sub_type;
415       }
416     } else {
417       plog(XLOG_ERROR, "strdup returned null in mount_linux_nonfs");
418     }
419   }
420 
421   if (!hasmntopt(mnt, "type"))
422     mnt->mnt_type = type;
423 
424   tmp_opts = parse_opts(type, mnt->mnt_opts, &flags, &extra_opts, &noauto);
425 
426 #ifdef MOUNT_TYPE_LOFS
427   if (STREQ(type, MOUNT_TYPE_LOFS)) {
428 # ifndef MNT2_GEN_OPT_BIND
429     size_t l;
430     /* this is basically a hack to support fist lofs */
431     XFREE(extra_opts);
432     l = strlen(mnt->mnt_fsname) + sizeof("dir=") + 1;
433     extra_opts = (char *) xmalloc(l);
434     xsnprintf(extra_opts, l, sizeof(extra_opts), "dir=%s", mnt->mnt_fsname);
435 # else /* MNT2_GEN_OPT_BIND */
436     /* use bind mounts for lofs */
437     flags |= MNT2_GEN_OPT_BIND;
438 # endif /* MNT2_GEN_OPT_BIND */
439     errorcode = do_mount_linux(type, mnt, flags, extra_opts);
440   } else /* end of "if type is LOFS" */
441 #endif /* MOUNT_TYPE_LOFS */
442 
443   {
444 #ifdef HAVE_LOOP_DEVICE
445     /*
446      * If the mounted "device" is actually a regular file,
447      # try to attach a loop device to it.
448      */
449     struct stat buf;
450     char *old_fsname = NULL;
451     if (stat(mnt->mnt_fsname, &buf) == 0 &&
452 	S_ISREG(buf.st_mode)) {
453       if ((loopdev = setup_loop_device(mnt->mnt_fsname)) != NULL) {
454 	char *str;
455 	size_t l;
456 
457 	plog(XLOG_INFO, "setup loop device %s over %s OK", loopdev, mnt->mnt_fsname);
458 	old_fsname = mnt->mnt_fsname;
459 	mnt->mnt_fsname = loopdev;
460 	/* XXX: hack, append loop=/dev/loopX to mnttab opts */
461 	l = strlen(mnt->mnt_opts) + 7 + strlen(loopdev);
462 	str = (char *) xmalloc(l);
463 	if (str) {
464 	  xsnprintf(str, l, "%s,loop=%s", mnt->mnt_opts, loopdev);
465 	  XFREE(mnt->mnt_opts);
466 	  mnt->mnt_opts = str;
467 	}
468       } else {
469 	plog(XLOG_ERROR, "failed to set up a loop device: %m");
470 	errorcode = 1;
471 	goto out;
472       }
473     }
474 #endif /* HAVE_LOOP_DEVICE */
475 
476     errorcode = do_mount_linux(type, mnt, flags, extra_opts);
477 
478 #ifdef HAVE_LOOP_DEVICE
479     /* if mount failed and we used a loop device, then undo it */
480     if (errorcode != 0 && loopdev != NULL) {
481       if (delete_loop_device(loopdev) < 0)
482 	plog(XLOG_WARNING, "mount() failed to release loop device %s: %m", loopdev);
483       else
484 	plog(XLOG_INFO, "mount() released loop device %s OK", loopdev);
485     }
486     if (old_fsname)
487       mnt->mnt_fsname = old_fsname;
488 #endif /* HAVE_LOOP_DEVICE */
489   }
490 
491   /*
492    * Free all allocated space and return errorcode.
493    */
494 out:
495 if (loopdev)
496      XFREE(loopdev);
497   if (extra_opts != NULL)
498     XFREE(extra_opts);
499   if (tmp_opts != NULL)
500     XFREE(tmp_opts);
501   if (sub_type != NULL)
502     XFREE(sub_type);
503   return errorcode;
504 }
505 
506 
507 int
508 mount_linux(MTYPE_TYPE type, mntent_t *mnt, int flags, caddr_t data)
509 {
510   int errorcode;
511 
512   if (mnt->mnt_opts && STREQ(mnt->mnt_opts, "defaults"))
513     mnt->mnt_opts = NULL;
514 
515   if (type == NULL)
516     type = index(mnt->mnt_fsname, ':') ? MOUNT_TYPE_NFS : MOUNT_TYPE_UFS;
517 
518   if (STREQ(type, MOUNT_TYPE_NFS))
519     errorcode = mount_linux_nfs(type, mnt, flags, data);
520   else				/* non-NFS mounts */
521     errorcode = mount_linux_nonfs(type, mnt, flags, data);
522 
523   return errorcode;
524 }
525 
526 
527 /****************************************************************************/
528 /*
529  * NFS error numbers and Linux errno's are two different things!  Linux is
530  * `worse' than other OSes in the respect that it loudly complains about
531  * undefined NFS return value ("bad NFS return value..").  So we should
532  * translate ANY possible Linux errno to their NFS equivalent.  Just, there
533  * aren't much NFS numbers, so most go to EINVAL or EIO.  The mapping below
534  * should fit at least for Linux/i386 and Linux/68k.  I haven't checked
535  * other architectures yet.
536  */
537 
538 #define NE_PERM		1
539 #define NE_NOENT	2
540 #define NE_IO		5
541 #define NE_NXIO		6
542 #define NE_AGAIN	11
543 #define NE_ACCES	13
544 #define NE_EXIST	17
545 #define NE_NODEV	19
546 #define NE_NOTDIR	20
547 #define NE_ISDIR	21
548 #define NE_INVAL	22
549 #define NE_FBIG		27
550 #define NE_NOSPC	28
551 #define NE_ROFS		30
552 #define NE_OPNOTSUPP	45
553 #define NE_NAMETOOLONG	63
554 #define NE_NOTEMPTY	66
555 #define NE_DQUOT	69
556 #define NE_STALE	70
557 #define NE_REMOTE	71
558 
559 #define NFS_LOMAP	0
560 #define NFS_HIMAP	122
561 
562 /*
563  * The errno's below are correct for Linux/i386. One day, somebody
564  * with lots of energy ought to verify them against the other ports...
565  */
566 static int nfs_errormap[] = {
567 	0,		/* success(0)		*/
568 	NE_PERM,	/* EPERM (1)		*/
569 	NE_NOENT,	/* ENOENT (2)		*/
570 	NE_INVAL,	/* ESRCH (3)		*/
571 	NE_IO,		/* EINTR (4)		*/
572 	NE_IO,		/* EIO (5)		*/
573 	NE_NXIO,	/* ENXIO (6)		*/
574 	NE_INVAL,	/* E2BIG (7)		*/
575 	NE_INVAL,	/* ENOEXEC (8)		*/
576 	NE_INVAL,	/* EBADF (9)		*/
577 	NE_IO,		/* ECHILD (10)		*/
578 	NE_AGAIN,	/* EAGAIN (11)		*/
579 	NE_IO,		/* ENOMEM (12)		*/
580 	NE_ACCES,	/* EACCES (13)		*/
581 	NE_INVAL,	/* EFAULT (14)		*/
582 	NE_INVAL,	/* ENOTBLK (15)		*/
583 	NE_IO,		/* EBUSY (16)		*/
584 	NE_EXIST,	/* EEXIST (17)		*/
585 	NE_INVAL,	/* EXDEV (18)		*/
586 	NE_NODEV,	/* ENODEV (19)		*/
587 	NE_NOTDIR,	/* ENOTDIR (20)		*/
588 	NE_ISDIR,	/* EISDIR (21)		*/
589 	NE_INVAL,	/* EINVAL (22)		*/
590 	NE_IO,		/* ENFILE (23)		*/
591 	NE_IO,		/* EMFILE (24)		*/
592 	NE_INVAL,	/* ENOTTY (25)		*/
593 	NE_ACCES,	/* ETXTBSY (26)		*/
594 	NE_FBIG,	/* EFBIG (27)		*/
595 	NE_NOSPC,	/* ENOSPC (28)		*/
596 	NE_INVAL,	/* ESPIPE (29)		*/
597 	NE_ROFS,	/* EROFS (30)		*/
598 	NE_INVAL,	/* EMLINK (31)		*/
599 	NE_INVAL,	/* EPIPE (32)		*/
600 	NE_INVAL,	/* EDOM (33)		*/
601 	NE_INVAL,	/* ERANGE (34)		*/
602 	NE_INVAL,	/* EDEADLK (35)		*/
603 	NE_NAMETOOLONG,	/* ENAMETOOLONG (36)	*/
604 	NE_INVAL,	/* ENOLCK (37)		*/
605 	NE_INVAL,	/* ENOSYS (38)		*/
606 	NE_NOTEMPTY,	/* ENOTEMPTY (39)	*/
607 	NE_INVAL,	/* ELOOP (40)		*/
608 	NE_INVAL,	/* unused (41)		*/
609 	NE_INVAL,	/* ENOMSG (42)		*/
610 	NE_INVAL,	/* EIDRM (43)		*/
611 	NE_INVAL,	/* ECHRNG (44)		*/
612 	NE_INVAL,	/* EL2NSYNC (45)	*/
613 	NE_INVAL,	/* EL3HLT (46)		*/
614 	NE_INVAL,	/* EL3RST (47)		*/
615 	NE_INVAL,	/* ELNRNG (48)		*/
616 	NE_INVAL,	/* EUNATCH (49)		*/
617 	NE_INVAL,	/* ENOCSI (50)		*/
618 	NE_INVAL,	/* EL2HLT (51)		*/
619 	NE_INVAL,	/* EBADE (52)		*/
620 	NE_INVAL,	/* EBADR (53)		*/
621 	NE_INVAL,	/* EXFULL (54)		*/
622 	NE_INVAL,	/* ENOANO (55)		*/
623 	NE_INVAL,	/* EBADRQC (56)		*/
624 	NE_INVAL,	/* EBADSLT (57)		*/
625 	NE_INVAL,	/* unused (58)		*/
626 	NE_INVAL,	/* EBFONT (59)		*/
627 	NE_INVAL,	/* ENOSTR (60)		*/
628 	NE_INVAL,	/* ENODATA (61)		*/
629 	NE_INVAL,	/* ETIME (62)		*/
630 	NE_INVAL,	/* ENOSR (63)		*/
631 	NE_INVAL,	/* ENONET (64)		*/
632 	NE_INVAL,	/* ENOPKG (65)		*/
633 	NE_INVAL,	/* EREMOTE (66)		*/
634 	NE_INVAL,	/* ENOLINK (67)		*/
635 	NE_INVAL,	/* EADV (68)		*/
636 	NE_INVAL,	/* ESRMNT (69)		*/
637 	NE_IO,		/* ECOMM (70)		*/
638 	NE_IO,		/* EPROTO (71)		*/
639 	NE_IO,		/* EMULTIHOP (72)	*/
640 	NE_IO,		/* EDOTDOT (73)		*/
641 	NE_INVAL,	/* EBADMSG (74)		*/
642 	NE_INVAL,	/* EOVERFLOW (75)	*/
643 	NE_INVAL,	/* ENOTUNIQ (76)	*/
644 	NE_INVAL,	/* EBADFD (77)		*/
645 	NE_IO,		/* EREMCHG (78)		*/
646 	NE_IO,		/* ELIBACC (79)		*/
647 	NE_IO,		/* ELIBBAD (80)		*/
648 	NE_IO,		/* ELIBSCN (81)		*/
649 	NE_IO,		/* ELIBMAX (82)		*/
650 	NE_IO,		/* ELIBEXEC (83)	*/
651 	NE_INVAL,	/* EILSEQ (84)		*/
652 	NE_INVAL,	/* ERESTART (85)	*/
653 	NE_INVAL,	/* ESTRPIPE (86)	*/
654 	NE_INVAL,	/* EUSERS (87)		*/
655 	NE_INVAL,	/* ENOTSOCK (88)	*/
656 	NE_INVAL,	/* EDESTADDRREQ (89)	*/
657 	NE_INVAL,	/* EMSGSIZE (90)	*/
658 	NE_INVAL,	/* EPROTOTYPE (91)	*/
659 	NE_INVAL,	/* ENOPROTOOPT (92)	*/
660 	NE_INVAL,	/* EPROTONOSUPPORT (93) */
661 	NE_INVAL,	/* ESOCKTNOSUPPORT (94) */
662 	NE_INVAL,	/* EOPNOTSUPP (95)	*/
663 	NE_INVAL,	/* EPFNOSUPPORT (96)	*/
664 	NE_INVAL,	/* EAFNOSUPPORT (97)	*/
665 	NE_INVAL,	/* EADDRINUSE (98)	*/
666 	NE_INVAL,	/* EADDRNOTAVAIL (99)	*/
667 	NE_IO,		/* ENETDOWN (100)	*/
668 	NE_IO,		/* ENETUNREACH (101)	*/
669 	NE_IO,		/* ENETRESET (102)	*/
670 	NE_IO,		/* ECONNABORTED (103)	*/
671 	NE_IO,		/* ECONNRESET (104)	*/
672 	NE_IO,		/* ENOBUFS (105)	*/
673 	NE_IO,		/* EISCONN (106)	*/
674 	NE_IO,		/* ENOTCONN (107)	*/
675 	NE_IO,		/* ESHUTDOWN (108)	*/
676 	NE_IO,		/* ETOOMANYREFS (109)	*/
677 	NE_IO,		/* ETIMEDOUT (110)	*/
678 	NE_IO,		/* ECONNREFUSED (111)	*/
679 	NE_IO,		/* EHOSTDOWN (112)	*/
680 	NE_IO,		/* EHOSTUNREACH (113)	*/
681 	NE_IO,		/* EALREADY (114)	*/
682 	NE_IO,		/* EINPROGRESS (115)	*/
683 	NE_STALE,	/* ESTALE (116)		*/
684 	NE_IO,		/* EUCLEAN (117)	*/
685 	NE_INVAL,	/* ENOTNAM (118)	*/
686 	NE_INVAL,	/* ENAVAIL (119)	*/
687 	NE_INVAL,	/* EISNAM (120)		*/
688 	NE_IO,		/* EREMOTEIO (121)	*/
689 	NE_DQUOT,	/* EDQUOT (122)		*/
690 };
691 
692 
693 int
694 linux_nfs_error(int e)
695 {
696   int ret = (nfsstat) NE_IO;
697 
698   if (e < NFS_LOMAP || e > NFS_HIMAP)
699     ret = (nfsstat) NE_IO;
700   else
701     ret = nfs_errormap[e - NFS_LOMAP];
702   dlog("linux_nfs_error: map error %d to NFS error %d", e, ret);
703   return (nfsstat) ret;
704 }
705 
706 
707 #ifdef HAVE_LOOP_DEVICE
708 /****************************************************************************/
709 /*** LOOP DEVICE SUPPORT						  ***/
710 /*** Loop Device setup code taken from mount-2.11g-5.src.rpm, which was   ***/
711 /*** originally written bt Ted T'so and others.				  ***/
712 /****************************************************************************/
713 
714 #define PROC_DEVICES	"/proc/devices"
715 
716 #if not_used_yet
717 static int
718 show_loop(char *device)
719 {
720   struct loop_info loopinfo;
721   int fd;
722 
723   if ((fd = open(device, O_RDONLY)) < 0) {
724     dlog("loop: can't open device %s: %m", device);
725     return -2;
726   }
727   if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) < 0) {
728     dlog("loop: can't get info on device %s: %m", device);
729     close(fd);
730     return -1;
731   }
732   dlog("show_loop: %s: [%04x]:%ld (%s)",
733        device, loopinfo.lo_device, loopinfo.lo_inode,
734        loopinfo.lo_name);
735 
736   close(fd);
737 
738   return 0;
739 }
740 
741 
742 static int
743 is_loop_device(const char *device)
744 {
745   struct stat statbuf;
746   int loopmajor = 7;
747 
748   return (loopmajor && stat(device, &statbuf) == 0 &&
749 	  S_ISBLK(statbuf.st_mode) &&
750 	  (statbuf.st_rdev>>8) == loopmajor);
751 }
752 #endif /* not_used_yet */
753 
754 
755 /*
756  * Just creating a device, say in /tmp, is probably a bad idea - people
757  * might have problems with backup or so.  So, we just try /dev/loop[0-7].
758  */
759 static char *
760 find_unused_loop_device(void)
761 {
762   char dev[20];
763   char *loop_formats[] = { "/dev/loop%d", "/dev/loop/%d" };
764   int i, j, fd, somedev = 0, someloop = 0, loop_known = 0;
765   struct stat statbuf;
766   struct loop_info loopinfo;
767   FILE *procdev;
768 
769 #define LOOP_FMT_SIZE(a) (sizeof(a)/sizeof(a[0]))
770   for (j = 0; j < (int) LOOP_FMT_SIZE(loop_formats); j++) {
771     for (i = 0; i < 256; i++) {
772       xsnprintf(dev, sizeof(dev), loop_formats[j], i);
773       if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) {
774 	somedev++;
775 	fd = open(dev, O_RDONLY);
776 	if (fd >= 0) {
777 	  if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) == 0)
778 	    someloop++;		/* in use */
779 	  else if (errno == ENXIO) {
780 	    close(fd);
781 	    return strdup(dev); /* probably free */
782 	  }
783 	  close(fd);
784 	}
785 	continue;		/* continue trying as long as devices exist */
786       }
787       break;
788     }
789   }
790 
791   /* Nothing found. Why not? */
792   if ((procdev = fopen(PROC_DEVICES, "r")) != NULL) {
793     char line[100];
794     while (fgets(line, sizeof(line), procdev))
795       if (strstr(line, " loop\n")) {
796 	loop_known = 1;
797 	break;
798       }
799     fclose(procdev);
800     if (!loop_known)
801       loop_known = -1;
802   }
803 
804   if (!somedev) {
805     dlog("Could not find any device /dev/loop#");
806   } else if (!someloop) {
807     if (loop_known == 1) {
808       dlog("Could not find any loop device.");
809       dlog("...Maybe /dev/loop# has a wrong major number?");
810     }
811     else if (loop_known == -1) {
812       dlog("Could not find any loop device, and, according to %s,", PROC_DEVICES);
813       dlog("...this kernel does not know about the loop device.");
814       dlog("... (If so, then recompile or `insmod loop.o'.)");
815     } else {
816       dlog("Could not find any loop device. Maybe this kernel does not know,");
817       dlog("...about the loop device (then recompile or `insmod loop.o'), or");
818       dlog("...maybe /dev/loop# has the wrong major number?");
819     }
820   } else {
821     dlog("Could not find any free loop device!");
822   }
823   return NULL;
824 }
825 
826 
827 /* returns 0 if OK, -1 otherwise */
828 char *
829 setup_loop_device(const char *file)
830 {
831   struct loop_info loopinfo;
832   int fd, ffd, mode, err = -1;
833   char *device = find_unused_loop_device();
834 
835   if (!device) {
836     dlog("no unused loop device");
837     goto out;
838   }
839 
840   mode = O_RDWR | O_LARGEFILE;
841   if ((ffd = open(file, mode)) < 0) {
842     if (errno == EROFS) {
843       mode = O_RDONLY | O_LARGEFILE;
844       ffd = open(file, mode);
845     }
846     if (ffd < 0) {
847       dlog("%s: %m", file);
848       goto out;
849     }
850   }
851   if ((fd = open(device, mode)) < 0) {
852     dlog("%s: %m", device);
853     goto out_close;
854   }
855 
856   memset(&loopinfo, 0, sizeof(loopinfo));
857   xstrlcpy(loopinfo.lo_name, file, LO_NAME_SIZE);
858   loopinfo.lo_offset = 0;
859 
860   if (ioctl(fd, LOOP_SET_FD, ffd) < 0) {
861     dlog("ioctl: LOOP_SET_FD: %m");
862     goto out_close_all;
863   }
864   if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) {
865     (void) ioctl(fd, LOOP_CLR_FD, 0);
866     dlog("ioctl: LOOP_SET_STATUS: %m");
867     goto out_close_all;
868   }
869 
870   /* if gets here, all is OK */
871   err = 0;
872 
873 out_close_all:
874   close(fd);
875 out_close:
876   close(ffd);
877 out:
878 
879   if (err) {
880     XFREE(device);
881     return NULL;
882   } else {
883     dlog("setup_loop_device(%s,%s): success", device, file);
884     return device;
885   }
886 }
887 
888 
889 int
890 delete_loop_device(const char *device)
891 {
892   int fd;
893 
894   if ((fd = open(device, O_RDONLY)) < 0) {
895     dlog("delete_loop_device: can't delete device %s: %m", device);
896     return -1;
897   }
898   if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
899     dlog("ioctl: LOOP_CLR_FD: %m");
900     return -1;
901   }
902   close(fd);
903   dlog("delete_loop_device(%s): success", device);
904   return 0;
905 }
906 #endif /* HAVE_LOOP_DEVICE */
907 
908 
909 /****************************************************************************/
910