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