1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <alloca.h> 30 #include <assert.h> 31 #include <ctype.h> 32 #include <fcntl.h> 33 #include <errno.h> 34 #include <signal.h> 35 #include <string.h> 36 #include <strings.h> 37 #include <nfs/mount.h> 38 #include <sys/types.h> 39 #include <sys/mount.h> 40 #include <sys/param.h> 41 #include <sys/stat.h> 42 #include <sys/types.h> 43 #include <unistd.h> 44 45 #include <sys/lx_autofs.h> 46 #include <sys/lx_debug.h> 47 #include <sys/lx_misc.h> 48 #include <sys/lx_mount.h> 49 50 /* 51 * support definitions 52 */ 53 union fh_buffer { 54 struct nfs_fid fh2; 55 struct nfs_fh3 fh3; 56 char fh_data[NFS3_FHSIZE + 2]; 57 }; 58 59 typedef enum mount_opt_type { 60 MOUNT_OPT_INVALID = 0, 61 MOUNT_OPT_NORMAL = 1, /* option value: none */ 62 MOUNT_OPT_UINT = 2 /* option value: unsigned int */ 63 } mount_opt_type_t; 64 65 typedef struct mount_opt { 66 char *mo_name; 67 mount_opt_type_t mo_type; 68 } mount_opt_t; 69 70 71 /* 72 * Globals 73 */ 74 mount_opt_t lofs_options[] = { 75 { NULL, MOUNT_OPT_INVALID } 76 }; 77 78 mount_opt_t lx_proc_options[] = { 79 { NULL, MOUNT_OPT_INVALID } 80 }; 81 82 mount_opt_t lx_autofs_options[] = { 83 { LX_MNTOPT_FD, MOUNT_OPT_UINT }, 84 { LX_MNTOPT_PGRP, MOUNT_OPT_UINT }, 85 { LX_MNTOPT_MINPROTO, MOUNT_OPT_UINT }, 86 { LX_MNTOPT_MAXPROTO, MOUNT_OPT_UINT }, 87 }; 88 89 90 /* 91 * i_lx_opt_verify() - Check the mount options. 92 * 93 * You might wonder why we're being so strict about the mount options 94 * we allow. The reason is that normally all mount option verification 95 * is done by the Solaris userland mount command. Once mount options 96 * are passed to the kernel, invalid options are simply ignored. So 97 * if we actually want to catch requests for functionality that we 98 * don't support, or if we want to make sure that we don't randomly 99 * enable options that we haven't check to make sure they have the 100 * same syntax on Linux and Solaris, we need to reject any options 101 * we don't know to be ok here. 102 */ 103 static int 104 i_lx_opt_verify(char *opts, mount_opt_t *mop) 105 { 106 int opts_len = strlen(opts); 107 char *opts_tmp, *opt; 108 int opt_len, i; 109 110 assert((opts != NULL) && (mop != NULL)); 111 112 /* If no options were specified, there's no problem. */ 113 if (opts_len == 0) 114 return (1); 115 116 /* If no options are allowed, fail. */ 117 if (mop[0].mo_name == NULL) 118 return (0); 119 120 /* Don't accept leading or trailing ','. */ 121 if ((opts[0] == ',') || (opts[opts_len] == ',')) 122 return (0); 123 124 /* Don't accept sequential ','. */ 125 for (i = 1; i < opts_len; i++) 126 if ((opts[i - 1] == ',') && (opts[i] == ',')) 127 return (0); 128 129 /* 130 * We're going to use strtok() which modifies the target 131 * string so make a temporary copy. 132 */ 133 opts_tmp = SAFE_ALLOCA(opts_len); 134 if (opts_tmp == NULL) 135 return (-1); 136 bcopy(opts, opts_tmp, opts_len + 1); 137 138 /* Verify each prop one at a time. */ 139 opt = strtok(opts_tmp, ","); 140 opt_len = strlen(opt); 141 for (;;) { 142 143 /* Check for matching option/value pair. */ 144 for (i = 0; mop[i].mo_name != NULL; i++) { 145 char *ovalue; 146 int ovalue_len, mo_len; 147 148 /* If the options is too short don't bother comparing */ 149 mo_len = strlen(mop[i].mo_name); 150 if (opt_len < mo_len) { 151 /* Keep trying to find a match. */ 152 continue; 153 } 154 155 /* Compare the option to an allowed option. */ 156 if (strncmp(mop[i].mo_name, opt, mo_len) != 0) { 157 /* Keep trying to find a match. */ 158 continue; 159 } 160 161 if (mop[i].mo_type == MOUNT_OPT_NORMAL) { 162 /* The option doesn't take a value. */ 163 if (opt_len == mo_len) { 164 /* This option is ok. */ 165 break; 166 } else { 167 /* Keep trying to find a match. */ 168 continue; 169 } 170 } 171 172 /* This options takes a value. */ 173 if ((opt_len == mo_len) || (opt[mo_len] != '=')) { 174 /* Keep trying to find a match. */ 175 continue; 176 } 177 178 /* We have an option match. Verify option value. */ 179 ovalue = &opt[mo_len] + 1; 180 ovalue_len = strlen(ovalue); 181 182 /* Value can't be zero length string. */ 183 if (ovalue_len == 0) 184 return (0); 185 186 if (mop[i].mo_type == MOUNT_OPT_UINT) { 187 int j; 188 /* Verify that value is an unsigned int. */ 189 for (j = 0; j < ovalue_len; j++) 190 if (!isdigit(ovalue[j])) 191 return (0); 192 } else { 193 /* Unknown option type specified. */ 194 assert(0); 195 } 196 197 /* The option is ok. */ 198 break; 199 } 200 201 /* If there were no matches this is an unsupported option. */ 202 if (mop[i].mo_name == NULL) 203 return (0); 204 205 /* This option is ok, move onto the next option. */ 206 if ((opt = strtok(NULL, ",")) == NULL) 207 break; 208 opt_len = strlen(opt); 209 }; 210 211 /* We verified all the options. */ 212 return (1); 213 } 214 215 static int 216 i_add_option(char *option, char *buf, size_t buf_size) 217 { 218 char *fmt_str = NULL; 219 220 assert((option != NULL) && (strlen(option) > 0)); 221 assert((buf != NULL) && (buf_size > 0)); 222 223 if (buf[0] == '\0') { 224 fmt_str = "%s"; 225 } else { 226 fmt_str = ",%s"; 227 } 228 229 buf_size -= strlen(buf); 230 buf += strlen(buf); 231 232 /*LINTED*/ 233 if (snprintf(buf, buf_size, fmt_str, option) > (buf_size - 1)) 234 return (-EOVERFLOW); 235 return (0); 236 } 237 238 static int 239 i_add_option_int(char *option, int val, char *buf, size_t buf_size) 240 { 241 char *fmt_str = NULL; 242 243 assert((option != NULL) && (strlen(option) > 0)); 244 assert((buf != NULL) && (buf_size > 0)); 245 246 if (buf[0] == '\0') { 247 fmt_str = "%s=%d"; 248 } else { 249 fmt_str = ",%s=%d"; 250 } 251 252 buf_size -= strlen(buf); 253 buf += strlen(buf); 254 255 /*LINTED*/ 256 if (snprintf(buf, buf_size, fmt_str, option, val) > (buf_size - 1)) 257 return (-EOVERFLOW); 258 return (0); 259 } 260 261 static int 262 i_make_nfs_args(lx_nfs_mount_data_t *lx_nmd, struct nfs_args *nfs_args, 263 struct netbuf *nfs_args_addr, struct knetconfig *nfs_args_knconf, 264 union fh_buffer *nfs_args_fh, struct sec_data *nfs_args_secdata, 265 char *fstype, char *options, int options_size) 266 { 267 struct stat statbuf; 268 int i, rv, use_tcp; 269 270 /* Sanity check the incomming Linux request. */ 271 if ((lx_nmd->nmd_rsize < 0) || (lx_nmd->nmd_wsize < 0) || 272 (lx_nmd->nmd_timeo < 0) || (lx_nmd->nmd_retrans < 0) || 273 (lx_nmd->nmd_acregmin < 0) || (lx_nmd->nmd_acregmax < 0) || 274 (lx_nmd->nmd_acdirmax < 0)) { 275 return (-EINVAL); 276 } 277 278 /* 279 * Additional sanity checks of incomming request. 280 * 281 * Some of the sanity checks below should probably return 282 * EINVAL (or some other error code) instead or ENOTSUP, 283 * but without experiminting on Linux to see how it 284 * deals with certain strange values there is no way 285 * to really know what we should return, hence we return 286 * ENOTSUP to tell us that eventually if we see some 287 * application hitting the problem we can go to a real 288 * Linux system, figure out how it deals with the situation 289 * and update our code to handle it in the same fashion. 290 */ 291 if (lx_nmd->nmd_version != 4) { 292 lx_unsupported("unsupported nfs mount request, " 293 "unrecognized NFS mount structure: %d\n", 294 lx_nmd->nmd_version); 295 return (-ENOTSUP); 296 } 297 if ((lx_nmd->nmd_flags & ~LX_NFS_MOUNT_SUPPORTED) != 0) { 298 lx_unsupported("unsupported nfs mount request, " 299 "flags: 0x%x\n", lx_nmd->nmd_flags); 300 return (-ENOTSUP); 301 } 302 if (lx_nmd->nmd_addr.sin_family != AF_INET) { 303 lx_unsupported("unsupported nfs mount request, " 304 "transport address family: 0x%x\n", 305 lx_nmd->nmd_addr.sin_family); 306 return (-ENOTSUP); 307 } 308 for (i = 0; i < LX_NMD_MAXHOSTNAMELEN; i++) { 309 if (lx_nmd->nmd_hostname[i] == '\0') 310 break; 311 } 312 if (i == 0) { 313 lx_unsupported("unsupported nfs mount request, " 314 "no hostname specified\n"); 315 return (-ENOTSUP); 316 } 317 if (i == LX_NMD_MAXHOSTNAMELEN) { 318 lx_unsupported("unsupported nfs mount request, " 319 "hostname not terminated\n"); 320 return (-ENOTSUP); 321 } 322 if (lx_nmd->nmd_namlen < i) { 323 lx_unsupported("unsupported nfs mount request, " 324 "invalid namlen value: 0x%x\n", lx_nmd->nmd_namlen); 325 return (-ENOTSUP); 326 } 327 if (lx_nmd->nmd_bsize != 0) { 328 lx_unsupported("unsupported nfs mount request, " 329 "bsize value: 0x%x\n", lx_nmd->nmd_bsize); 330 return (-ENOTSUP); 331 } 332 333 /* Initialize and clear the output structure pointers passed in. */ 334 bzero(nfs_args, sizeof (*nfs_args)); 335 bzero(nfs_args_addr, sizeof (*nfs_args_addr)); 336 bzero(nfs_args_knconf, sizeof (*nfs_args_knconf)); 337 bzero(nfs_args_fh, sizeof (*nfs_args_fh)); 338 bzero(nfs_args_secdata, sizeof (*nfs_args_secdata)); 339 nfs_args->addr = nfs_args_addr; 340 nfs_args->knconf = nfs_args_knconf; 341 nfs_args->fh = (caddr_t)nfs_args_fh; 342 nfs_args->nfs_ext_u.nfs_extB.secdata = nfs_args_secdata; 343 344 /* Check if we're using tcp. */ 345 use_tcp = (lx_nmd->nmd_flags & LX_NFS_MOUNT_TCP) ? 1 : 0; 346 347 /* 348 * These seem to be the default flags used by Solaris for v2 and v3 349 * nfs mounts. 350 * 351 * Don't bother with NFSMNT_TRYRDMA since we always specify a 352 * transport (either udp or tcp). 353 */ 354 nfs_args->flags = NFSMNT_NEWARGS | NFSMNT_KNCONF | NFSMNT_INT | 355 NFSMNT_HOSTNAME; 356 357 /* Translate some Linux mount flags into Solaris mount flags. */ 358 if (lx_nmd->nmd_flags & LX_NFS_MOUNT_SOFT) 359 nfs_args->flags |= NFSMNT_SOFT; 360 if (lx_nmd->nmd_flags & LX_NFS_MOUNT_INTR) 361 nfs_args->flags |= NFSMNT_INT; 362 if (lx_nmd->nmd_flags & LX_NFS_MOUNT_POSIX) 363 nfs_args->flags |= NFSMNT_POSIX; 364 if (lx_nmd->nmd_flags & LX_NFS_MOUNT_NOCTO) 365 nfs_args->flags |= NFSMNT_NOCTO; 366 if (lx_nmd->nmd_flags & LX_NFS_MOUNT_NOAC) 367 nfs_args->flags |= NFSMNT_NOAC; 368 if (lx_nmd->nmd_flags & LX_NFS_MOUNT_NONLM) 369 nfs_args->flags |= NFSMNT_LLOCK; 370 371 if ((lx_nmd->nmd_flags & LX_NFS_MOUNT_VER3) != 0) { 372 (void) strcpy(fstype, "nfs3"); 373 if ((rv = i_add_option_int("vers", 3, 374 options, options_size)) != 0) 375 return (rv); 376 377 if (lx_nmd->nmd_root.lx_fh3_length > 378 sizeof (nfs_args_fh->fh3.fh3_u.data)) { 379 lx_unsupported("unsupported nfs mount request, " 380 "nfs file handle length: 0x%x\n", 381 lx_nmd->nmd_root.lx_fh3_length); 382 return (-ENOTSUP); 383 } 384 385 /* Set the v3 file handle info. */ 386 nfs_args_fh->fh3.fh3_length = lx_nmd->nmd_root.lx_fh3_length; 387 bcopy(&lx_nmd->nmd_root.lx_fh3_data, 388 nfs_args_fh->fh3.fh3_u.data, 389 lx_nmd->nmd_root.lx_fh3_length); 390 } else { 391 /* 392 * Assume nfs v2. Note that this could also be a v1 393 * mount request but there doesn't seem to be any difference 394 * in the parameters passed to the Linux mount system 395 * call for v1 or v2 mounts so there is no way of really 396 * knowing. 397 */ 398 (void) strcpy(fstype, "nfs"); 399 if ((rv = i_add_option_int("vers", 2, 400 options, options_size)) != 0) 401 return (rv); 402 403 /* Solaris seems to add this flag when using v2. */ 404 nfs_args->flags |= NFSMNT_SECDEFAULT; 405 406 /* Set the v2 file handle info. */ 407 bcopy(&lx_nmd->nmd_old_root, 408 nfs_args_fh, sizeof (nfs_args_fh->fh2)); 409 } 410 411 /* 412 * We can't use getnetconfig() here because there is no netconfig 413 * database in linux. 414 */ 415 nfs_args_knconf->knc_protofmly = "inet"; 416 if (use_tcp) { 417 /* 418 * TCP uses NC_TPI_COTS_ORD semantics. 419 * See /etc/netconfig. 420 */ 421 nfs_args_knconf->knc_semantics = NC_TPI_COTS_ORD; 422 nfs_args_knconf->knc_proto = "tcp"; 423 if ((rv = i_add_option("proto=tcp", 424 options, options_size)) != 0) 425 return (rv); 426 if (stat("/dev/tcp", &statbuf) != 0) 427 return (-errno); 428 nfs_args_knconf->knc_rdev = statbuf.st_rdev; 429 } else { 430 /* 431 * Assume UDP. UDP uses NC_TPI_CLTS semantics. 432 * See /etc/netconfig. 433 */ 434 nfs_args_knconf->knc_semantics = NC_TPI_CLTS; 435 nfs_args_knconf->knc_proto = "udp"; 436 if ((rv = i_add_option("proto=udp", 437 options, options_size)) != 0) 438 return (rv); 439 if (stat("/dev/udp", &statbuf) != 0) 440 return (-errno); 441 nfs_args_knconf->knc_rdev = statbuf.st_rdev; 442 } 443 444 /* Set the server address. */ 445 nfs_args_addr->maxlen = nfs_args_addr->len = 446 sizeof (struct sockaddr_in); 447 nfs_args_addr->buf = (char *)&lx_nmd->nmd_addr; 448 449 /* Set the server hostname string. */ 450 nfs_args->hostname = lx_nmd->nmd_hostname; 451 452 /* Translate Linux nfs mount parameters into Solaris mount options. */ 453 if (lx_nmd->nmd_rsize != LX_NMD_DEFAULT_RSIZE) { 454 if ((rv = i_add_option_int("rsize", lx_nmd->nmd_rsize, 455 options, options_size)) != 0) 456 return (rv); 457 nfs_args->rsize = lx_nmd->nmd_rsize; 458 nfs_args->flags |= NFSMNT_RSIZE; 459 } 460 if (lx_nmd->nmd_wsize != LX_NMD_DEFAULT_WSIZE) { 461 if ((rv = i_add_option_int("wsize", lx_nmd->nmd_wsize, 462 options, options_size)) != 0) 463 return (rv); 464 nfs_args->wsize = lx_nmd->nmd_wsize; 465 nfs_args->flags |= NFSMNT_WSIZE; 466 } 467 if ((rv = i_add_option_int("timeo", lx_nmd->nmd_timeo, 468 options, options_size)) != 0) 469 return (rv); 470 nfs_args->timeo = lx_nmd->nmd_timeo; 471 nfs_args->flags |= NFSMNT_TIMEO; 472 if ((rv = i_add_option_int("retrans", lx_nmd->nmd_retrans, 473 options, options_size)) != 0) 474 return (rv); 475 nfs_args->retrans = lx_nmd->nmd_retrans; 476 nfs_args->flags |= NFSMNT_RETRANS; 477 if ((rv = i_add_option_int("acregmin", lx_nmd->nmd_acregmin, 478 options, options_size)) != 0) 479 return (rv); 480 nfs_args->acregmin = lx_nmd->nmd_acregmin; 481 nfs_args->flags |= NFSMNT_ACREGMIN; 482 if ((rv = i_add_option_int("acregmax", lx_nmd->nmd_acregmax, 483 options, options_size)) != 0) 484 return (rv); 485 nfs_args->acregmax = lx_nmd->nmd_acregmax; 486 nfs_args->flags |= NFSMNT_ACREGMAX; 487 if ((rv = i_add_option_int("acdirmin", lx_nmd->nmd_acdirmin, 488 options, options_size)) != 0) 489 return (rv); 490 nfs_args->acdirmin = lx_nmd->nmd_acdirmin; 491 nfs_args->flags |= NFSMNT_ACDIRMIN; 492 if ((rv = i_add_option_int("acdirmax", lx_nmd->nmd_acdirmax, 493 options, options_size)) != 0) 494 return (rv); 495 nfs_args->acdirmax = lx_nmd->nmd_acdirmax; 496 nfs_args->flags |= NFSMNT_ACDIRMAX; 497 498 /* We only support nfs with a security type of AUTH_SYS. */ 499 nfs_args->nfs_args_ext = NFS_ARGS_EXTB; 500 nfs_args_secdata->secmod = AUTH_SYS; 501 nfs_args_secdata->rpcflavor = AUTH_SYS; 502 nfs_args_secdata->flags = 0; 503 nfs_args_secdata->uid = 0; 504 nfs_args_secdata->data = NULL; 505 nfs_args->nfs_ext_u.nfs_extB.next = NULL; 506 507 /* 508 * The Linux nfs mount command seems to pass an open socket fd 509 * to the kernel during the mount system call. We don't need 510 * this fd on Solaris so just close it. 511 */ 512 (void) close(lx_nmd->nmd_fd); 513 514 return (0); 515 } 516 517 int 518 lx_mount(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, 519 uintptr_t p5) 520 { 521 /* Linux input arguments. */ 522 const char *sourcep = (const char *)p1; 523 const char *targetp = (const char *)p2; 524 const char *fstypep = (const char *)p3; 525 unsigned int flags = (unsigned int)p4; 526 const void *datap = (const void *)p5; 527 528 /* Variables needed for all mounts. */ 529 char source[MAXPATHLEN], target[MAXPATHLEN]; 530 char fstype[MAXPATHLEN], options[MAXPATHLEN]; 531 int sflags, rv; 532 533 /* Variables needed for nfs mounts. */ 534 lx_nfs_mount_data_t lx_nmd; 535 struct nfs_args nfs_args; 536 struct netbuf nfs_args_addr; 537 struct knetconfig nfs_args_knconf; 538 union fh_buffer nfs_args_fh; 539 struct sec_data nfs_args_secdata; 540 char *sdataptr = NULL; 541 int sdatalen = 0; 542 543 /* Initialize Solaris mount arguments. */ 544 sflags = MS_OPTIONSTR; 545 options[0] = '\0'; 546 sdatalen = 0; 547 548 /* Copy in parameters that are always present. */ 549 rv = uucopystr((void *)sourcep, &source, sizeof (source)); 550 if ((rv == -1) || (rv == sizeof (source))) 551 return (-EFAULT); 552 553 rv = uucopystr((void *)targetp, &target, sizeof (target)); 554 if ((rv == -1) || (rv == sizeof (target))) 555 return (-EFAULT); 556 557 rv = uucopystr((void *)fstypep, &fstype, sizeof (fstype)); 558 if ((rv == -1) || (rv == sizeof (fstype))) 559 return (-EFAULT); 560 561 lx_debug("\tlinux mount source: %s", source); 562 lx_debug("\tlinux mount target: %s", target); 563 lx_debug("\tlinux mount fstype: %s", fstype); 564 565 /* Make sure we support the requested mount flags. */ 566 if ((flags & ~LX_MS_SUPPORTED) != 0) { 567 lx_unsupported( 568 "unsupported mount flags: 0x%x", flags); 569 return (-ENOTSUP); 570 } 571 572 /* Do filesystem specific mount work. */ 573 if (flags & LX_MS_BIND) { 574 575 /* If MS_BIND is set, we turn this into a lofs mount. */ 576 (void) strcpy(fstype, "lofs"); 577 578 /* Copy in Linux mount options. */ 579 if (datap != NULL) { 580 rv = uucopystr((void *)datap, 581 options, sizeof (options)); 582 if ((rv == -1) || (rv == sizeof (options))) 583 return (-EFAULT); 584 } 585 lx_debug("\tlinux mount options: \"%s\"", options); 586 587 /* Verify Linux mount options. */ 588 if (i_lx_opt_verify(options, lofs_options) == 0) { 589 lx_unsupported("unsupported lofs mount options"); 590 return (-ENOTSUP); 591 } 592 } else if (strcmp(fstype, "proc") == 0) { 593 594 /* Translate proc mount requests to lx_proc requests. */ 595 (void) strcpy(fstype, "lx_proc"); 596 597 /* Copy in Linux mount options. */ 598 if (datap != NULL) { 599 rv = uucopystr((void *)datap, 600 options, sizeof (options)); 601 if ((rv == -1) || (rv == sizeof (options))) 602 return (-EFAULT); 603 } 604 lx_debug("\tlinux mount options: \"%s\"", options); 605 606 /* Verify Linux mount options. */ 607 if (i_lx_opt_verify(options, lx_proc_options) == 0) { 608 lx_unsupported("unsupported lx_proc mount options"); 609 return (-ENOTSUP); 610 } 611 } else if (strcmp(fstype, "autofs") == 0) { 612 613 /* Translate proc mount requests to lx_afs requests. */ 614 (void) strcpy(fstype, LX_AUTOFS_NAME); 615 616 /* Copy in Linux mount options. */ 617 if (datap != NULL) { 618 rv = uucopystr((void *)datap, 619 options, sizeof (options)); 620 if ((rv == -1) || (rv == sizeof (options))) 621 return (-EFAULT); 622 } 623 lx_debug("\tlinux mount options: \"%s\"", options); 624 625 /* Verify Linux mount options. */ 626 if (i_lx_opt_verify(options, lx_autofs_options) == 0) { 627 lx_unsupported("unsupported lx_autofs mount options"); 628 return (-ENOTSUP); 629 } 630 } else if (strcmp(fstype, "nfs") == 0) { 631 632 /* 633 * Copy in Linux mount options. Note that for Linux 634 * nfs mounts the mount options pointer (which normally 635 * points to a string) points to a structure. 636 */ 637 if (uucopy((void *)datap, &lx_nmd, sizeof (lx_nmd)) < 0) 638 return (-errno); 639 640 /* 641 * For Solaris nfs mounts, the kernel expects a special 642 * strucutre, but a pointer to this structure is passed 643 * in via an extra parameter (sdataptr below.) 644 */ 645 if ((rv = i_make_nfs_args(&lx_nmd, &nfs_args, 646 &nfs_args_addr, &nfs_args_knconf, &nfs_args_fh, 647 &nfs_args_secdata, fstype, 648 options, sizeof (options))) != 0) 649 return (rv); 650 651 /* 652 * For nfs mounts we need to tell the mount system call 653 * to expect extra parameters. 654 */ 655 sflags |= MS_DATA; 656 sdataptr = (char *)&nfs_args; 657 sdatalen = sizeof (nfs_args); 658 } else { 659 lx_unsupported( 660 "unsupported mount filesystem type: %s", fstype); 661 return (-ENOTSUP); 662 } 663 664 /* Convert some Linux flags to Solaris flags. */ 665 if (flags & LX_MS_RDONLY) 666 sflags |= MS_RDONLY; 667 if (flags & LX_MS_NOSUID) 668 sflags |= MS_NOSUID; 669 if (flags & LX_MS_REMOUNT) 670 sflags |= MS_REMOUNT; 671 672 /* Convert some Linux flags to Solaris option strings. */ 673 if ((flags & LX_MS_NODEV) && 674 ((rv = i_add_option("nodev", options, sizeof (options))) != 0)) 675 return (rv); 676 if ((flags & LX_MS_NOEXEC) && 677 ((rv = i_add_option("noexec", options, sizeof (options))) != 0)) 678 return (rv); 679 if ((flags & LX_MS_NOATIME) && 680 ((rv = i_add_option("noatime", options, sizeof (options))) != 0)) 681 return (rv); 682 683 lx_debug("\tsolaris mount fstype: %s", fstype); 684 lx_debug("\tsolaris mount options: \"%s\"", options); 685 686 return (mount(source, target, sflags, fstype, sdataptr, sdatalen, 687 options, sizeof (options)) ? -errno : 0); 688 } 689 690 /* 691 * umount() is identical, though it is implemented on top of umount2() in 692 * Solaris so it cannot be a pass-thru system call. 693 */ 694 int 695 lx_umount(uintptr_t p1) 696 { 697 return (umount((char *)p1) ? -errno : 0); 698 } 699 700 /* 701 * The Linux umount2() system call is identical but has a different value for 702 * MNT_FORCE (the logical equivalent to MS_FORCE). 703 */ 704 #define LX_MNT_FORCE 0x1 705 706 int 707 lx_umount2(uintptr_t p1, uintptr_t p2) 708 { 709 char *path = (char *)p1; 710 int flags = 0; 711 712 if (p2 & ~LX_MNT_FORCE) 713 return (-EINVAL); 714 715 if (p2 & LX_MNT_FORCE) 716 flags |= MS_FORCE; 717 718 return (umount2(path, flags) ? -errno : 0); 719 }