1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 35*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 36*7c478bd9Sstevel@tonic-gate #include <rpc/types.h> 37*7c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 39*7c478bd9Sstevel@tonic-gate #include <netdb.h> 40*7c478bd9Sstevel@tonic-gate #include "clnt.h" 41*7c478bd9Sstevel@tonic-gate #include <rpc/xdr.h> 42*7c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.h> 43*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 44*7c478bd9Sstevel@tonic-gate #include "brpc.h" 45*7c478bd9Sstevel@tonic-gate #include "auth_inet.h" 46*7c478bd9Sstevel@tonic-gate #include "pmap.h" 47*7c478bd9Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h> 48*7c478bd9Sstevel@tonic-gate #include <rpcsvc/nfs4_prot.h> 49*7c478bd9Sstevel@tonic-gate #include "nfs_inet.h" 50*7c478bd9Sstevel@tonic-gate #include <rpcsvc/bootparam.h> 51*7c478bd9Sstevel@tonic-gate #include <dhcp_impl.h> 52*7c478bd9Sstevel@tonic-gate #include <rpcsvc/mount.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/salib.h> 55*7c478bd9Sstevel@tonic-gate #include "socket_inet.h" 56*7c478bd9Sstevel@tonic-gate #include "ipv4.h" 57*7c478bd9Sstevel@tonic-gate #include "mac.h" 58*7c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h> 59*7c478bd9Sstevel@tonic-gate #include <errno.h> 60*7c478bd9Sstevel@tonic-gate #include "dhcpv4.h" 61*7c478bd9Sstevel@tonic-gate #include <sys/mntent.h> 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate struct nfs_file roothandle; /* root file handle */ 64*7c478bd9Sstevel@tonic-gate static char root_hostname[SYS_NMLN]; /* server hostname */ 65*7c478bd9Sstevel@tonic-gate static char my_hostname[MAXHOSTNAMELEN]; 66*7c478bd9Sstevel@tonic-gate static char root_pathbuf[NFS_MAXPATHLEN]; /* the root's path */ 67*7c478bd9Sstevel@tonic-gate static char root_boot_file[NFS_MAXPATHLEN]; /* optional boot file */ 68*7c478bd9Sstevel@tonic-gate static struct sockaddr_in root_to; /* server sock ip */ 69*7c478bd9Sstevel@tonic-gate /* in network order */ 70*7c478bd9Sstevel@tonic-gate CLIENT *root_CLIENT = NULL; /* CLIENT handle */ 71*7c478bd9Sstevel@tonic-gate int dontroute = FALSE; /* In case rarp/bootparams was selected */ 72*7c478bd9Sstevel@tonic-gate char rootopts[MAX_PATH_LEN]; 73*7c478bd9Sstevel@tonic-gate static gid_t fake_gids = 1; /* fake gids list for auth_unix */ 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate extern void set_default_filename(char *); /* boot.c */ 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate /* 78*7c478bd9Sstevel@tonic-gate * xdr routines used by mount. 79*7c478bd9Sstevel@tonic-gate */ 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate bool_t 82*7c478bd9Sstevel@tonic-gate xdr_fhstatus(XDR *xdrs, struct fhstatus *fhsp) 83*7c478bd9Sstevel@tonic-gate { 84*7c478bd9Sstevel@tonic-gate if (!xdr_int(xdrs, (int *)&fhsp->fhs_status)) 85*7c478bd9Sstevel@tonic-gate return (FALSE); 86*7c478bd9Sstevel@tonic-gate if (fhsp->fhs_status == 0) { 87*7c478bd9Sstevel@tonic-gate return (xdr_fhandle(xdrs, fhsp->fhstatus_u.fhs_fhandle)); 88*7c478bd9Sstevel@tonic-gate } 89*7c478bd9Sstevel@tonic-gate return (TRUE); 90*7c478bd9Sstevel@tonic-gate } 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate bool_t 93*7c478bd9Sstevel@tonic-gate xdr_fhandle(XDR *xdrs, fhandle fhp) 94*7c478bd9Sstevel@tonic-gate { 95*7c478bd9Sstevel@tonic-gate return (xdr_opaque(xdrs, (char *)fhp, NFS_FHSIZE)); 96*7c478bd9Sstevel@tonic-gate } 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate bool_t 99*7c478bd9Sstevel@tonic-gate xdr_path(XDR *xdrs, char **pathp) 100*7c478bd9Sstevel@tonic-gate { 101*7c478bd9Sstevel@tonic-gate return (xdr_string(xdrs, pathp, MNTPATHLEN)); 102*7c478bd9Sstevel@tonic-gate } 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate bool_t 105*7c478bd9Sstevel@tonic-gate xdr_fhandle3(XDR *xdrs, fhandle3 *objp) 106*7c478bd9Sstevel@tonic-gate { 107*7c478bd9Sstevel@tonic-gate return (xdr_bytes(xdrs, (char **)&objp->fhandle3_val, 108*7c478bd9Sstevel@tonic-gate (uint_t *)&objp->fhandle3_len, FHSIZE3)); 109*7c478bd9Sstevel@tonic-gate } 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate bool_t 112*7c478bd9Sstevel@tonic-gate xdr_mountstat3(XDR *xdrs, mountstat3 *objp) 113*7c478bd9Sstevel@tonic-gate { 114*7c478bd9Sstevel@tonic-gate return (xdr_enum(xdrs, (enum_t *)objp)); 115*7c478bd9Sstevel@tonic-gate } 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate bool_t 118*7c478bd9Sstevel@tonic-gate xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp) 119*7c478bd9Sstevel@tonic-gate { 120*7c478bd9Sstevel@tonic-gate if (!xdr_fhandle3(xdrs, &objp->fhandle)) 121*7c478bd9Sstevel@tonic-gate return (FALSE); 122*7c478bd9Sstevel@tonic-gate return (xdr_array(xdrs, (char **)&objp->auth_flavors.auth_flavors_val, 123*7c478bd9Sstevel@tonic-gate (uint_t *)&objp->auth_flavors.auth_flavors_len, ~0, 124*7c478bd9Sstevel@tonic-gate sizeof (int), (xdrproc_t)xdr_int)); 125*7c478bd9Sstevel@tonic-gate } 126*7c478bd9Sstevel@tonic-gate 127*7c478bd9Sstevel@tonic-gate bool_t 128*7c478bd9Sstevel@tonic-gate xdr_mountres3(XDR *xdrs, mountres3 *objp) 129*7c478bd9Sstevel@tonic-gate { 130*7c478bd9Sstevel@tonic-gate if (!xdr_mountstat3(xdrs, &objp->fhs_status)) 131*7c478bd9Sstevel@tonic-gate return (FALSE); 132*7c478bd9Sstevel@tonic-gate if (objp->fhs_status == MNT_OK) 133*7c478bd9Sstevel@tonic-gate return (xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo)); 134*7c478bd9Sstevel@tonic-gate return (TRUE); 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate static int 138*7c478bd9Sstevel@tonic-gate nfsmountroot(char *path, struct nfs_file *filep) 139*7c478bd9Sstevel@tonic-gate { 140*7c478bd9Sstevel@tonic-gate int rexmit; 141*7c478bd9Sstevel@tonic-gate int resp_wait; 142*7c478bd9Sstevel@tonic-gate enum clnt_stat status; 143*7c478bd9Sstevel@tonic-gate struct fhstatus root_tmp; /* to pass to rpc/xdr */ 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate /* 146*7c478bd9Sstevel@tonic-gate * Wait up to 16 secs for first response, retransmitting expon. 147*7c478bd9Sstevel@tonic-gate */ 148*7c478bd9Sstevel@tonic-gate rexmit = 0; /* default retransmission interval */ 149*7c478bd9Sstevel@tonic-gate resp_wait = 16; 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate do { 152*7c478bd9Sstevel@tonic-gate status = brpc_call((rpcprog_t)MOUNTPROG, (rpcvers_t)MOUNTVERS, 153*7c478bd9Sstevel@tonic-gate (rpcproc_t)MOUNTPROC_MNT, xdr_path, (caddr_t)&path, 154*7c478bd9Sstevel@tonic-gate xdr_fhstatus, (caddr_t)&(root_tmp), rexmit, resp_wait, 155*7c478bd9Sstevel@tonic-gate &root_to, NULL, AUTH_UNIX); 156*7c478bd9Sstevel@tonic-gate if (status == RPC_TIMEDOUT) { 157*7c478bd9Sstevel@tonic-gate dprintf("boot: %s:%s mount server not responding.\n", 158*7c478bd9Sstevel@tonic-gate root_hostname, path); 159*7c478bd9Sstevel@tonic-gate } 160*7c478bd9Sstevel@tonic-gate rexmit = resp_wait; 161*7c478bd9Sstevel@tonic-gate resp_wait = 0; /* use default wait time. */ 162*7c478bd9Sstevel@tonic-gate } while (status == RPC_TIMEDOUT); 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate if ((status != RPC_SUCCESS) || (root_tmp.fhs_status != 0)) { 165*7c478bd9Sstevel@tonic-gate nfs_error(root_tmp.fhs_status); 166*7c478bd9Sstevel@tonic-gate root_to.sin_port = 0; 167*7c478bd9Sstevel@tonic-gate return (-1); 168*7c478bd9Sstevel@tonic-gate } 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate /* 171*7c478bd9Sstevel@tonic-gate * Since the mount succeeded, we'll mark the filep's 172*7c478bd9Sstevel@tonic-gate * status as NFS_OK, and its type as NFDIR. If these 173*7c478bd9Sstevel@tonic-gate * points aren't the case, then we wouldn't be here. 174*7c478bd9Sstevel@tonic-gate */ 175*7c478bd9Sstevel@tonic-gate bcopy(&root_tmp.fhstatus_u.fhs_fhandle, &filep->fh.fh2, FHSIZE); 176*7c478bd9Sstevel@tonic-gate filep->ftype.type2 = NFDIR; 177*7c478bd9Sstevel@tonic-gate filep->version = NFS_VERSION; 178*7c478bd9Sstevel@tonic-gate nfs_readsize = nfs_readsize < NFS_MAXDATA ? nfs_readsize : NFS_MAXDATA; 179*7c478bd9Sstevel@tonic-gate /* 180*7c478bd9Sstevel@tonic-gate * Set a reasonable lower limit on readsize 181*7c478bd9Sstevel@tonic-gate */ 182*7c478bd9Sstevel@tonic-gate nfs_readsize = (nfs_readsize != 0 && nfs_readsize < 512) ? 183*7c478bd9Sstevel@tonic-gate 512 : nfs_readsize; 184*7c478bd9Sstevel@tonic-gate return (0); 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate int 188*7c478bd9Sstevel@tonic-gate setup_root_vars(void) 189*7c478bd9Sstevel@tonic-gate { 190*7c478bd9Sstevel@tonic-gate size_t buflen; 191*7c478bd9Sstevel@tonic-gate uint16_t readsize; 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate /* 194*7c478bd9Sstevel@tonic-gate * Root server name. Required. 195*7c478bd9Sstevel@tonic-gate */ 196*7c478bd9Sstevel@tonic-gate buflen = sizeof (root_hostname); 197*7c478bd9Sstevel@tonic-gate if (dhcp_getinfo(DSYM_VENDOR, VS_NFSMNT_ROOTSRVR_NAME, 0, 198*7c478bd9Sstevel@tonic-gate root_hostname, &buflen)) { 199*7c478bd9Sstevel@tonic-gate root_hostname[buflen] = '\0'; 200*7c478bd9Sstevel@tonic-gate } else { 201*7c478bd9Sstevel@tonic-gate dprintf("BOUND: Missing Root Server Name Option\n"); 202*7c478bd9Sstevel@tonic-gate errno = EINVAL; 203*7c478bd9Sstevel@tonic-gate return (-1); 204*7c478bd9Sstevel@tonic-gate } 205*7c478bd9Sstevel@tonic-gate 206*7c478bd9Sstevel@tonic-gate /* 207*7c478bd9Sstevel@tonic-gate * Root server IP. Required. 208*7c478bd9Sstevel@tonic-gate */ 209*7c478bd9Sstevel@tonic-gate buflen = sizeof (root_to.sin_addr); 210*7c478bd9Sstevel@tonic-gate if (!dhcp_getinfo(DSYM_VENDOR, VS_NFSMNT_ROOTSRVR_IP, 0, 211*7c478bd9Sstevel@tonic-gate &root_to.sin_addr, &buflen)) { 212*7c478bd9Sstevel@tonic-gate dprintf("BOUND: Missing Root Server IP Option\n"); 213*7c478bd9Sstevel@tonic-gate errno = EINVAL; 214*7c478bd9Sstevel@tonic-gate return (-1); 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* 218*7c478bd9Sstevel@tonic-gate * Root path Required. 219*7c478bd9Sstevel@tonic-gate */ 220*7c478bd9Sstevel@tonic-gate buflen = sizeof (root_pathbuf); 221*7c478bd9Sstevel@tonic-gate if (dhcp_getinfo(DSYM_VENDOR, VS_NFSMNT_ROOTPATH, 0, 222*7c478bd9Sstevel@tonic-gate root_pathbuf, &buflen)) { 223*7c478bd9Sstevel@tonic-gate root_pathbuf[buflen] = '\0'; 224*7c478bd9Sstevel@tonic-gate } else { 225*7c478bd9Sstevel@tonic-gate dprintf("BOUND: Missing Root Path Option\n"); 226*7c478bd9Sstevel@tonic-gate errno = EINVAL; 227*7c478bd9Sstevel@tonic-gate return (-1); 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate /* 231*7c478bd9Sstevel@tonic-gate * Optional Bootfile path. 232*7c478bd9Sstevel@tonic-gate */ 233*7c478bd9Sstevel@tonic-gate buflen = sizeof (root_boot_file); 234*7c478bd9Sstevel@tonic-gate if (dhcp_getinfo(DSYM_VENDOR, VS_NFSMNT_BOOTFILE, 0, 235*7c478bd9Sstevel@tonic-gate root_boot_file, &buflen)) { 236*7c478bd9Sstevel@tonic-gate root_boot_file[buflen] = '\0'; 237*7c478bd9Sstevel@tonic-gate dprintf("BOUND: Optional Boot File is: %s\n", root_boot_file); 238*7c478bd9Sstevel@tonic-gate } 239*7c478bd9Sstevel@tonic-gate 240*7c478bd9Sstevel@tonic-gate /* if we got a boot file name, use it as the default */ 241*7c478bd9Sstevel@tonic-gate if (root_boot_file[0] != '\0') 242*7c478bd9Sstevel@tonic-gate set_default_filename(root_boot_file); 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate /* 245*7c478bd9Sstevel@tonic-gate * Set the NFS read size. The mount code will adjust it to 246*7c478bd9Sstevel@tonic-gate * the maximum size. 247*7c478bd9Sstevel@tonic-gate */ 248*7c478bd9Sstevel@tonic-gate buflen = sizeof (readsize); 249*7c478bd9Sstevel@tonic-gate if (dhcp_getinfo(DSYM_VENDOR, VS_BOOT_NFS_READSIZE, 0, 250*7c478bd9Sstevel@tonic-gate &readsize, &buflen)) { 251*7c478bd9Sstevel@tonic-gate nfs_readsize = ntohs(readsize); 252*7c478bd9Sstevel@tonic-gate if (boothowto & RB_VERBOSE) { 253*7c478bd9Sstevel@tonic-gate printf("Boot NFS read size: %d\n", nfs_readsize); 254*7c478bd9Sstevel@tonic-gate } 255*7c478bd9Sstevel@tonic-gate } 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate /* 258*7c478bd9Sstevel@tonic-gate * Optional rootopts. 259*7c478bd9Sstevel@tonic-gate */ 260*7c478bd9Sstevel@tonic-gate buflen = sizeof (rootopts); 261*7c478bd9Sstevel@tonic-gate if (dhcp_getinfo(DSYM_VENDOR, VS_NFSMNT_ROOTOPTS, 0, 262*7c478bd9Sstevel@tonic-gate rootopts, &buflen)) { 263*7c478bd9Sstevel@tonic-gate rootopts[buflen] = '\0'; 264*7c478bd9Sstevel@tonic-gate dprintf("BOUND: Optional Rootopts is: %s\n", rootopts); 265*7c478bd9Sstevel@tonic-gate } 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate return (0); 268*7c478bd9Sstevel@tonic-gate } 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate static void 271*7c478bd9Sstevel@tonic-gate mnt3_error(enum mountstat3 status) 272*7c478bd9Sstevel@tonic-gate { 273*7c478bd9Sstevel@tonic-gate if (!(boothowto & RB_DEBUG)) 274*7c478bd9Sstevel@tonic-gate return; 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate switch (status) { 277*7c478bd9Sstevel@tonic-gate case MNT_OK: 278*7c478bd9Sstevel@tonic-gate printf("Mount: No error.\n"); 279*7c478bd9Sstevel@tonic-gate break; 280*7c478bd9Sstevel@tonic-gate case MNT3ERR_PERM: 281*7c478bd9Sstevel@tonic-gate printf("Mount: Not owner.\n"); 282*7c478bd9Sstevel@tonic-gate break; 283*7c478bd9Sstevel@tonic-gate case MNT3ERR_NOENT: 284*7c478bd9Sstevel@tonic-gate printf("Mount: No such file or directory.\n"); 285*7c478bd9Sstevel@tonic-gate break; 286*7c478bd9Sstevel@tonic-gate case MNT3ERR_IO: 287*7c478bd9Sstevel@tonic-gate printf("Mount: I/O error.\n"); 288*7c478bd9Sstevel@tonic-gate break; 289*7c478bd9Sstevel@tonic-gate case MNT3ERR_ACCES: 290*7c478bd9Sstevel@tonic-gate printf("Mount: Permission denied.\n"); 291*7c478bd9Sstevel@tonic-gate break; 292*7c478bd9Sstevel@tonic-gate case MNT3ERR_NOTDIR: 293*7c478bd9Sstevel@tonic-gate printf("Mount: Not a directory.\n"); 294*7c478bd9Sstevel@tonic-gate break; 295*7c478bd9Sstevel@tonic-gate case MNT3ERR_INVAL: 296*7c478bd9Sstevel@tonic-gate printf("Mount: Invalid argument.\n"); 297*7c478bd9Sstevel@tonic-gate break; 298*7c478bd9Sstevel@tonic-gate case MNT3ERR_NAMETOOLONG: 299*7c478bd9Sstevel@tonic-gate printf("Mount: File name too long.\n"); 300*7c478bd9Sstevel@tonic-gate break; 301*7c478bd9Sstevel@tonic-gate case MNT3ERR_NOTSUPP: 302*7c478bd9Sstevel@tonic-gate printf("Mount: Operation not supported.\n"); 303*7c478bd9Sstevel@tonic-gate break; 304*7c478bd9Sstevel@tonic-gate case MNT3ERR_SERVERFAULT: 305*7c478bd9Sstevel@tonic-gate printf("Mount: Server fault.\n"); 306*7c478bd9Sstevel@tonic-gate break; 307*7c478bd9Sstevel@tonic-gate default: 308*7c478bd9Sstevel@tonic-gate printf("Mount: unknown error.\n"); 309*7c478bd9Sstevel@tonic-gate break; 310*7c478bd9Sstevel@tonic-gate } 311*7c478bd9Sstevel@tonic-gate } 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate static int 314*7c478bd9Sstevel@tonic-gate nfs3mountroot(char *path, struct nfs_file *filep) 315*7c478bd9Sstevel@tonic-gate { 316*7c478bd9Sstevel@tonic-gate int rexmit; 317*7c478bd9Sstevel@tonic-gate int resp_wait; 318*7c478bd9Sstevel@tonic-gate struct mountres3 res3; 319*7c478bd9Sstevel@tonic-gate enum clnt_stat status; 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate /* 322*7c478bd9Sstevel@tonic-gate * Wait up to 16 secs for first response, retransmitting expon. 323*7c478bd9Sstevel@tonic-gate */ 324*7c478bd9Sstevel@tonic-gate rexmit = 0; /* default retransmission interval */ 325*7c478bd9Sstevel@tonic-gate resp_wait = 16; 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate /* 328*7c478bd9Sstevel@tonic-gate * Try to mount using V3 329*7c478bd9Sstevel@tonic-gate */ 330*7c478bd9Sstevel@tonic-gate do { 331*7c478bd9Sstevel@tonic-gate bzero(&res3, sizeof (struct mountres3)); 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate status = brpc_call((rpcprog_t)MOUNTPROG, (rpcvers_t)MOUNTVERS3, 334*7c478bd9Sstevel@tonic-gate (rpcproc_t)MOUNTPROC_MNT, xdr_path, (caddr_t)&path, 335*7c478bd9Sstevel@tonic-gate xdr_mountres3, (caddr_t)&res3, rexmit, resp_wait, 336*7c478bd9Sstevel@tonic-gate &root_to, NULL, AUTH_UNIX); 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate if (status != RPC_TIMEDOUT) 339*7c478bd9Sstevel@tonic-gate break; 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate dprintf("boot: %s:%s mount server not responding.\n", 342*7c478bd9Sstevel@tonic-gate root_hostname, path); 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate rexmit = resp_wait; 345*7c478bd9Sstevel@tonic-gate resp_wait = 0; /* use default wait time. */ 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate xdr_free(xdr_mountres3, (caddr_t)&res3); 348*7c478bd9Sstevel@tonic-gate } while (status == RPC_TIMEDOUT); 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate if ((status != RPC_SUCCESS) || (res3.fhs_status != MNT_OK)) { 351*7c478bd9Sstevel@tonic-gate mnt3_error(res3.fhs_status); 352*7c478bd9Sstevel@tonic-gate root_to.sin_port = 0; 353*7c478bd9Sstevel@tonic-gate return (-1); 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate /* 357*7c478bd9Sstevel@tonic-gate * Since the mount succeeded, we'll mark the filep's 358*7c478bd9Sstevel@tonic-gate * status as NFS_OK, and its type as NF3DIR. If these 359*7c478bd9Sstevel@tonic-gate * points aren't the case, then we wouldn't be here. 360*7c478bd9Sstevel@tonic-gate */ 361*7c478bd9Sstevel@tonic-gate filep->fh.fh3.len = res3.mountres3_u.mountinfo.fhandle.fhandle3_len; 362*7c478bd9Sstevel@tonic-gate bcopy(res3.mountres3_u.mountinfo.fhandle.fhandle3_val, 363*7c478bd9Sstevel@tonic-gate filep->fh.fh3.data, 364*7c478bd9Sstevel@tonic-gate filep->fh.fh3.len); 365*7c478bd9Sstevel@tonic-gate filep->ftype.type3 = NF3DIR; 366*7c478bd9Sstevel@tonic-gate filep->version = NFS_V3; 367*7c478bd9Sstevel@tonic-gate /* 368*7c478bd9Sstevel@tonic-gate * Hardwire in a known reasonable upper limit of 32K 369*7c478bd9Sstevel@tonic-gate */ 370*7c478bd9Sstevel@tonic-gate nfs_readsize = nfs_readsize < 32 * 1024 ? nfs_readsize : 32 * 1024; 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * Set a reasonable lower limit on readsize 373*7c478bd9Sstevel@tonic-gate */ 374*7c478bd9Sstevel@tonic-gate nfs_readsize = (nfs_readsize != 0 && nfs_readsize < 512) ? 375*7c478bd9Sstevel@tonic-gate 512 : nfs_readsize; 376*7c478bd9Sstevel@tonic-gate xdr_free(xdr_mountres3, (caddr_t)&res3); 377*7c478bd9Sstevel@tonic-gate return (0); 378*7c478bd9Sstevel@tonic-gate } 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate /* 381*7c478bd9Sstevel@tonic-gate * Setup v4 client for inetboot 382*7c478bd9Sstevel@tonic-gate */ 383*7c478bd9Sstevel@tonic-gate static int 384*7c478bd9Sstevel@tonic-gate nfs4init(char *path, uint16_t nfs_port) 385*7c478bd9Sstevel@tonic-gate { 386*7c478bd9Sstevel@tonic-gate struct timeval wait; 387*7c478bd9Sstevel@tonic-gate int fd = -1; 388*7c478bd9Sstevel@tonic-gate int error = 0; 389*7c478bd9Sstevel@tonic-gate enum clnt_stat rpc_stat; 390*7c478bd9Sstevel@tonic-gate struct nfs_file rootpath; 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate wait.tv_sec = RPC_RCVWAIT_MSEC / 1000; 393*7c478bd9Sstevel@tonic-gate wait.tv_usec = 0; 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate /* 396*7c478bd9Sstevel@tonic-gate * If we haven't explicitly set the port number, set to the standard 397*7c478bd9Sstevel@tonic-gate * 2049 and don't cause a rpcbind request. 398*7c478bd9Sstevel@tonic-gate */ 399*7c478bd9Sstevel@tonic-gate if (nfs_port == 0) 400*7c478bd9Sstevel@tonic-gate nfs_port = 2049; 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate root_to.sin_port = htons(nfs_port); 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate /* 405*7c478bd9Sstevel@tonic-gate * Support TCP only 406*7c478bd9Sstevel@tonic-gate */ 407*7c478bd9Sstevel@tonic-gate root_CLIENT = clntbtcp_create(&root_to, NFS_PROGRAM, 408*7c478bd9Sstevel@tonic-gate NFS_V4, wait, &fd, 409*7c478bd9Sstevel@tonic-gate NFS4BUF_SIZE, NFS4BUF_SIZE); 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate if (root_CLIENT == NULL) { 412*7c478bd9Sstevel@tonic-gate root_to.sin_port = 0; 413*7c478bd9Sstevel@tonic-gate return (-1); 414*7c478bd9Sstevel@tonic-gate } 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate root_CLIENT->cl_auth = 417*7c478bd9Sstevel@tonic-gate authunix_create(my_hostname, 0, 1, 1, &fake_gids); 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate /* 420*7c478bd9Sstevel@tonic-gate * Send NULL proc the server first to see if V4 exists 421*7c478bd9Sstevel@tonic-gate */ 422*7c478bd9Sstevel@tonic-gate rpc_stat = CLNT_CALL(root_CLIENT, NFSPROC4_NULL, xdr_void, NULL, 423*7c478bd9Sstevel@tonic-gate xdr_void, NULL, wait); 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate if (rpc_stat != RPC_SUCCESS) { 426*7c478bd9Sstevel@tonic-gate dprintf("boot: NULL proc failed NFSv4 service not available\n"); 427*7c478bd9Sstevel@tonic-gate AUTH_DESTROY(root_CLIENT->cl_auth); 428*7c478bd9Sstevel@tonic-gate CLNT_DESTROY(root_CLIENT); 429*7c478bd9Sstevel@tonic-gate root_to.sin_port = 0; 430*7c478bd9Sstevel@tonic-gate return (-1); 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate /* 434*7c478bd9Sstevel@tonic-gate * Do a lookup to get to the root_path. This is nice since it can 435*7c478bd9Sstevel@tonic-gate * handle multicomponent lookups. 436*7c478bd9Sstevel@tonic-gate */ 437*7c478bd9Sstevel@tonic-gate roothandle.version = NFS_V4; 438*7c478bd9Sstevel@tonic-gate roothandle.ftype.type4 = NF4DIR; 439*7c478bd9Sstevel@tonic-gate roothandle.fh.fh4.len = 0; /* Force a PUTROOTFH */ 440*7c478bd9Sstevel@tonic-gate roothandle.offset = (uint_t)0; /* it's a directory! */ 441*7c478bd9Sstevel@tonic-gate error = lookup(path, &rootpath, TRUE); 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate if (error) { 444*7c478bd9Sstevel@tonic-gate printf("boot: lookup %s failed\n", path); 445*7c478bd9Sstevel@tonic-gate return (-1); 446*7c478bd9Sstevel@tonic-gate } 447*7c478bd9Sstevel@tonic-gate roothandle = rootpath; /* structure copy */ 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate /* 450*7c478bd9Sstevel@tonic-gate * Hardwire in a known reasonable upper limit of 32K 451*7c478bd9Sstevel@tonic-gate */ 452*7c478bd9Sstevel@tonic-gate nfs_readsize = nfs_readsize < 32 * 1024 ? nfs_readsize : 32 * 1024; 453*7c478bd9Sstevel@tonic-gate /* 454*7c478bd9Sstevel@tonic-gate * Set a reasonable lower limit on readsize 455*7c478bd9Sstevel@tonic-gate */ 456*7c478bd9Sstevel@tonic-gate nfs_readsize = (nfs_readsize != 0 && nfs_readsize < 512) ? 457*7c478bd9Sstevel@tonic-gate 512 : nfs_readsize; 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate return (0); 460*7c478bd9Sstevel@tonic-gate } 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate static int 463*7c478bd9Sstevel@tonic-gate atoi(const char *p) 464*7c478bd9Sstevel@tonic-gate { 465*7c478bd9Sstevel@tonic-gate int n; 466*7c478bd9Sstevel@tonic-gate int c, neg = 0; 467*7c478bd9Sstevel@tonic-gate 468*7c478bd9Sstevel@tonic-gate if (!isdigit(c = *p)) { 469*7c478bd9Sstevel@tonic-gate while (c == ' ' || c == '\t' || c == '\n') 470*7c478bd9Sstevel@tonic-gate c = *++p; 471*7c478bd9Sstevel@tonic-gate switch (c) { 472*7c478bd9Sstevel@tonic-gate case '-': 473*7c478bd9Sstevel@tonic-gate neg++; 474*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 475*7c478bd9Sstevel@tonic-gate case '+': 476*7c478bd9Sstevel@tonic-gate c = *++p; 477*7c478bd9Sstevel@tonic-gate } 478*7c478bd9Sstevel@tonic-gate if (!isdigit(c)) 479*7c478bd9Sstevel@tonic-gate return (0); 480*7c478bd9Sstevel@tonic-gate } 481*7c478bd9Sstevel@tonic-gate for (n = '0' - c; isdigit(c = *++p); ) { 482*7c478bd9Sstevel@tonic-gate n *= 10; /* two steps to avoid unnecessary overflow */ 483*7c478bd9Sstevel@tonic-gate n += '0' - c; /* accum neg to avoid surprises at MAX */ 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate return (neg ? n : -n); 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate /* 489*7c478bd9Sstevel@tonic-gate * Parse suboptions from a string. 490*7c478bd9Sstevel@tonic-gate * Same as getsubopt(3C). 491*7c478bd9Sstevel@tonic-gate */ 492*7c478bd9Sstevel@tonic-gate static int 493*7c478bd9Sstevel@tonic-gate getsubopt(char **optionsp, char * const *tokens, char **valuep) 494*7c478bd9Sstevel@tonic-gate { 495*7c478bd9Sstevel@tonic-gate char *s = *optionsp, *p; 496*7c478bd9Sstevel@tonic-gate int i; 497*7c478bd9Sstevel@tonic-gate size_t optlen; 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate *valuep = NULL; 500*7c478bd9Sstevel@tonic-gate if (*s == '\0') 501*7c478bd9Sstevel@tonic-gate return (-1); 502*7c478bd9Sstevel@tonic-gate p = strchr(s, ','); /* find next option */ 503*7c478bd9Sstevel@tonic-gate if (p == NULL) { 504*7c478bd9Sstevel@tonic-gate p = s + strlen(s); 505*7c478bd9Sstevel@tonic-gate } else { 506*7c478bd9Sstevel@tonic-gate *p++ = '\0'; /* mark end and point to next */ 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate *optionsp = p; /* point to next option */ 509*7c478bd9Sstevel@tonic-gate p = strchr(s, '='); /* find value */ 510*7c478bd9Sstevel@tonic-gate if (p == NULL) { 511*7c478bd9Sstevel@tonic-gate optlen = strlen(s); 512*7c478bd9Sstevel@tonic-gate *valuep = NULL; 513*7c478bd9Sstevel@tonic-gate } else { 514*7c478bd9Sstevel@tonic-gate optlen = p - s; 515*7c478bd9Sstevel@tonic-gate *valuep = ++p; 516*7c478bd9Sstevel@tonic-gate } 517*7c478bd9Sstevel@tonic-gate for (i = 0; tokens[i] != NULL; i++) { 518*7c478bd9Sstevel@tonic-gate if ((optlen == strlen(tokens[i])) && 519*7c478bd9Sstevel@tonic-gate (strncmp(s, tokens[i], optlen) == 0)) 520*7c478bd9Sstevel@tonic-gate return (i); 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate /* no match, point value at option and return error */ 523*7c478bd9Sstevel@tonic-gate *valuep = s; 524*7c478bd9Sstevel@tonic-gate return (-1); 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate /* 528*7c478bd9Sstevel@tonic-gate * The only interesting NFS mount options for initiating the kernel 529*7c478bd9Sstevel@tonic-gate * all others are ignored. 530*7c478bd9Sstevel@tonic-gate */ 531*7c478bd9Sstevel@tonic-gate static char *optlist[] = { 532*7c478bd9Sstevel@tonic-gate #define OPT_RSIZE 0 533*7c478bd9Sstevel@tonic-gate MNTOPT_RSIZE, 534*7c478bd9Sstevel@tonic-gate #define OPT_TIMEO 1 535*7c478bd9Sstevel@tonic-gate MNTOPT_TIMEO, 536*7c478bd9Sstevel@tonic-gate #define OPT_VERS 2 537*7c478bd9Sstevel@tonic-gate MNTOPT_VERS, 538*7c478bd9Sstevel@tonic-gate #define OPT_PROTO 3 539*7c478bd9Sstevel@tonic-gate MNTOPT_PROTO, 540*7c478bd9Sstevel@tonic-gate #define OPT_PORT 4 541*7c478bd9Sstevel@tonic-gate MNTOPT_PORT, 542*7c478bd9Sstevel@tonic-gate NULL 543*7c478bd9Sstevel@tonic-gate }; 544*7c478bd9Sstevel@tonic-gate 545*7c478bd9Sstevel@tonic-gate /* 546*7c478bd9Sstevel@tonic-gate * This routine will open a device as it is known by the V2 OBP. It 547*7c478bd9Sstevel@tonic-gate * then goes thru the stuff necessary to initialize the network device, 548*7c478bd9Sstevel@tonic-gate * get our network parameters, (using DHCP or rarp/bootparams), and 549*7c478bd9Sstevel@tonic-gate * finally actually go and get the root filehandle. Sound like fun? 550*7c478bd9Sstevel@tonic-gate * Suuurrrree. Take a look. 551*7c478bd9Sstevel@tonic-gate * 552*7c478bd9Sstevel@tonic-gate * Returns 0 if things worked. -1 if we crashed and burned. 553*7c478bd9Sstevel@tonic-gate */ 554*7c478bd9Sstevel@tonic-gate int 555*7c478bd9Sstevel@tonic-gate boot_nfs_mountroot(char *str) 556*7c478bd9Sstevel@tonic-gate { 557*7c478bd9Sstevel@tonic-gate int status; 558*7c478bd9Sstevel@tonic-gate enum clnt_stat rpc_stat; 559*7c478bd9Sstevel@tonic-gate char *root_path = &root_pathbuf[0]; /* to make XDR happy */ 560*7c478bd9Sstevel@tonic-gate struct timeval wait; 561*7c478bd9Sstevel@tonic-gate int fd; 562*7c478bd9Sstevel@tonic-gate int bufsize; 563*7c478bd9Sstevel@tonic-gate char *opts, *val; 564*7c478bd9Sstevel@tonic-gate int nfs_version = 0; 565*7c478bd9Sstevel@tonic-gate int istcp = 1; 566*7c478bd9Sstevel@tonic-gate int nfs_port = 0; /* Cause pmap to get port */ 567*7c478bd9Sstevel@tonic-gate struct sockaddr_in tmp_addr; /* throw away */ 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate if (root_CLIENT != NULL) { 570*7c478bd9Sstevel@tonic-gate AUTH_DESTROY(root_CLIENT->cl_auth); 571*7c478bd9Sstevel@tonic-gate CLNT_DESTROY(root_CLIENT); 572*7c478bd9Sstevel@tonic-gate root_CLIENT = NULL; 573*7c478bd9Sstevel@tonic-gate } 574*7c478bd9Sstevel@tonic-gate 575*7c478bd9Sstevel@tonic-gate root_to.sin_family = AF_INET; 576*7c478bd9Sstevel@tonic-gate root_to.sin_addr.s_addr = htonl(INADDR_ANY); 577*7c478bd9Sstevel@tonic-gate root_to.sin_port = htons(0); 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate mac_init(str); 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate (void) ipv4_setpromiscuous(TRUE); 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate if (get_netconfig_strategy() == NCT_BOOTP_DHCP) { 584*7c478bd9Sstevel@tonic-gate if (boothowto & RB_VERBOSE) 585*7c478bd9Sstevel@tonic-gate printf("Using BOOTP/DHCP...\n"); 586*7c478bd9Sstevel@tonic-gate if (dhcp() != 0 || setup_root_vars() != 0) { 587*7c478bd9Sstevel@tonic-gate (void) ipv4_setpromiscuous(FALSE); 588*7c478bd9Sstevel@tonic-gate if (boothowto & RB_VERBOSE) 589*7c478bd9Sstevel@tonic-gate printf("BOOTP/DHCP configuration failed!\n"); 590*7c478bd9Sstevel@tonic-gate return (-1); 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate /* now that we have an IP address, turn off promiscuous mode */ 594*7c478bd9Sstevel@tonic-gate (void) ipv4_setpromiscuous(FALSE); 595*7c478bd9Sstevel@tonic-gate } else { 596*7c478bd9Sstevel@tonic-gate /* Use RARP/BOOTPARAMS. RARP will try forever... */ 597*7c478bd9Sstevel@tonic-gate if (boothowto & RB_VERBOSE) 598*7c478bd9Sstevel@tonic-gate printf("Using RARP/BOOTPARAMS...\n"); 599*7c478bd9Sstevel@tonic-gate mac_call_rarp(); 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate /* 602*7c478bd9Sstevel@tonic-gate * Since there is no way to determine our netmask, and therefore 603*7c478bd9Sstevel@tonic-gate * figure out if the router we got is useful, we assume all 604*7c478bd9Sstevel@tonic-gate * services are local. Use DHCP if this bothers you. 605*7c478bd9Sstevel@tonic-gate */ 606*7c478bd9Sstevel@tonic-gate dontroute = TRUE; 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate /* now that we have an IP address, turn off promiscuous mode */ 609*7c478bd9Sstevel@tonic-gate (void) ipv4_setpromiscuous(FALSE); 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate /* get our hostname */ 612*7c478bd9Sstevel@tonic-gate if (whoami() == FALSE) 613*7c478bd9Sstevel@tonic-gate return (-1); 614*7c478bd9Sstevel@tonic-gate 615*7c478bd9Sstevel@tonic-gate /* get our bootparams. */ 616*7c478bd9Sstevel@tonic-gate if (getfile("root", root_hostname, &root_to.sin_addr, 617*7c478bd9Sstevel@tonic-gate root_pathbuf) == FALSE) 618*7c478bd9Sstevel@tonic-gate return (-1); 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate /* get our rootopts. */ 621*7c478bd9Sstevel@tonic-gate (void) getfile("rootopts", root_hostname, &tmp_addr.sin_addr, 622*7c478bd9Sstevel@tonic-gate rootopts); 623*7c478bd9Sstevel@tonic-gate } 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate /* mount root */ 626*7c478bd9Sstevel@tonic-gate if (boothowto & RB_VERBOSE) { 627*7c478bd9Sstevel@tonic-gate printf("root server: %s (%s)\n", root_hostname, 628*7c478bd9Sstevel@tonic-gate inet_ntoa(root_to.sin_addr)); 629*7c478bd9Sstevel@tonic-gate printf("root directory: %s\n", root_pathbuf); 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate /* 633*7c478bd9Sstevel@tonic-gate * Assumes we've configured the stack and thus know our 634*7c478bd9Sstevel@tonic-gate * IP address/hostname, either by using DHCP or rarp/bootparams. 635*7c478bd9Sstevel@tonic-gate */ 636*7c478bd9Sstevel@tonic-gate gethostname(my_hostname, sizeof (my_hostname)); 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate wait.tv_sec = RPC_RCVWAIT_MSEC / 1000; 639*7c478bd9Sstevel@tonic-gate wait.tv_usec = 0; 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate /* 642*7c478bd9Sstevel@tonic-gate * Parse out the interesting root options, if an invalid 643*7c478bd9Sstevel@tonic-gate * or unknown option is provided, silently ignore it and 644*7c478bd9Sstevel@tonic-gate * use the defaults. 645*7c478bd9Sstevel@tonic-gate */ 646*7c478bd9Sstevel@tonic-gate opts = rootopts; 647*7c478bd9Sstevel@tonic-gate while (*opts) { 648*7c478bd9Sstevel@tonic-gate int ival; 649*7c478bd9Sstevel@tonic-gate switch (getsubopt(&opts, optlist, &val)) { 650*7c478bd9Sstevel@tonic-gate case OPT_RSIZE: 651*7c478bd9Sstevel@tonic-gate if (val == NULL || !isdigit(*val)) 652*7c478bd9Sstevel@tonic-gate break; 653*7c478bd9Sstevel@tonic-gate nfs_readsize = atoi(val); 654*7c478bd9Sstevel@tonic-gate break; 655*7c478bd9Sstevel@tonic-gate case OPT_TIMEO: 656*7c478bd9Sstevel@tonic-gate if (val == NULL || !isdigit(*val)) 657*7c478bd9Sstevel@tonic-gate break; 658*7c478bd9Sstevel@tonic-gate ival = atoi(val); 659*7c478bd9Sstevel@tonic-gate wait.tv_sec = ival / 10; 660*7c478bd9Sstevel@tonic-gate wait.tv_usec = (ival % 10) * 100000; 661*7c478bd9Sstevel@tonic-gate break; 662*7c478bd9Sstevel@tonic-gate case OPT_VERS: 663*7c478bd9Sstevel@tonic-gate if (val == NULL || !isdigit(*val)) 664*7c478bd9Sstevel@tonic-gate break; 665*7c478bd9Sstevel@tonic-gate nfs_version = atoi(val); 666*7c478bd9Sstevel@tonic-gate break; 667*7c478bd9Sstevel@tonic-gate case OPT_PROTO: 668*7c478bd9Sstevel@tonic-gate if (val == NULL || isdigit(*val)) 669*7c478bd9Sstevel@tonic-gate break; 670*7c478bd9Sstevel@tonic-gate if ((strncmp(val, "udp", 3) == 0)) 671*7c478bd9Sstevel@tonic-gate istcp = 0; 672*7c478bd9Sstevel@tonic-gate else 673*7c478bd9Sstevel@tonic-gate istcp = 1; /* must be tcp */ 674*7c478bd9Sstevel@tonic-gate break; 675*7c478bd9Sstevel@tonic-gate case OPT_PORT: 676*7c478bd9Sstevel@tonic-gate if (val == NULL || !isdigit(*val)) 677*7c478bd9Sstevel@tonic-gate break; 678*7c478bd9Sstevel@tonic-gate nfs_port = atoi(val); 679*7c478bd9Sstevel@tonic-gate 680*7c478bd9Sstevel@tonic-gate /* 681*7c478bd9Sstevel@tonic-gate * Currently nfs_dlinet.c doesn't support setting 682*7c478bd9Sstevel@tonic-gate * the root NFS port. Delete this when it does. 683*7c478bd9Sstevel@tonic-gate */ 684*7c478bd9Sstevel@tonic-gate nfs_port = 0; 685*7c478bd9Sstevel@tonic-gate break; 686*7c478bd9Sstevel@tonic-gate default: 687*7c478bd9Sstevel@tonic-gate /* 688*7c478bd9Sstevel@tonic-gate * Unknown options are silently ignored 689*7c478bd9Sstevel@tonic-gate */ 690*7c478bd9Sstevel@tonic-gate break; 691*7c478bd9Sstevel@tonic-gate } 692*7c478bd9Sstevel@tonic-gate } 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate /* 695*7c478bd9Sstevel@tonic-gate * If version is set, then try that version first. 696*7c478bd9Sstevel@tonic-gate */ 697*7c478bd9Sstevel@tonic-gate switch (nfs_version) { 698*7c478bd9Sstevel@tonic-gate case NFS_VERSION: 699*7c478bd9Sstevel@tonic-gate if (nfsmountroot(root_path, &roothandle) == 0) 700*7c478bd9Sstevel@tonic-gate goto domount; 701*7c478bd9Sstevel@tonic-gate break; 702*7c478bd9Sstevel@tonic-gate case NFS_V3: 703*7c478bd9Sstevel@tonic-gate if (nfs3mountroot(root_path, &roothandle) == 0) 704*7c478bd9Sstevel@tonic-gate goto domount; 705*7c478bd9Sstevel@tonic-gate break; 706*7c478bd9Sstevel@tonic-gate case NFS_V4: 707*7c478bd9Sstevel@tonic-gate /* 708*7c478bd9Sstevel@tonic-gate * With v4 we skip the mount and go straight to 709*7c478bd9Sstevel@tonic-gate * setting the root filehandle. Because of this we 710*7c478bd9Sstevel@tonic-gate * do things slightly differently and obtain our 711*7c478bd9Sstevel@tonic-gate * client handle first. 712*7c478bd9Sstevel@tonic-gate */ 713*7c478bd9Sstevel@tonic-gate if (istcp && nfs4init(root_path, nfs_port) == 0) { 714*7c478bd9Sstevel@tonic-gate /* 715*7c478bd9Sstevel@tonic-gate * If v4 init succeeded then we are done. Just return. 716*7c478bd9Sstevel@tonic-gate */ 717*7c478bd9Sstevel@tonic-gate return (0); 718*7c478bd9Sstevel@tonic-gate } 719*7c478bd9Sstevel@tonic-gate } 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate /* 722*7c478bd9Sstevel@tonic-gate * If there was no chosen version or the chosen version failed 723*7c478bd9Sstevel@tonic-gate * try all versions in order, this may still fail to boot 724*7c478bd9Sstevel@tonic-gate * at the kernel level if the options are not right, but be 725*7c478bd9Sstevel@tonic-gate * generous at this early stage. 726*7c478bd9Sstevel@tonic-gate */ 727*7c478bd9Sstevel@tonic-gate if (istcp && nfs4init(root_path, nfs_port) == 0) { 728*7c478bd9Sstevel@tonic-gate /* 729*7c478bd9Sstevel@tonic-gate * If v4 init succeeded then we are done. Just return. 730*7c478bd9Sstevel@tonic-gate */ 731*7c478bd9Sstevel@tonic-gate return (0); 732*7c478bd9Sstevel@tonic-gate } 733*7c478bd9Sstevel@tonic-gate 734*7c478bd9Sstevel@tonic-gate if (nfs3mountroot(root_path, &roothandle) == 0) 735*7c478bd9Sstevel@tonic-gate goto domount; 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate if ((status = nfsmountroot(root_path, &roothandle)) != 0) 738*7c478bd9Sstevel@tonic-gate return (status); 739*7c478bd9Sstevel@tonic-gate 740*7c478bd9Sstevel@tonic-gate domount: 741*7c478bd9Sstevel@tonic-gate /* 742*7c478bd9Sstevel@tonic-gate * Only v2 and v3 go on from here. 743*7c478bd9Sstevel@tonic-gate */ 744*7c478bd9Sstevel@tonic-gate roothandle.offset = (uint_t)0; /* it's a directory! */ 745*7c478bd9Sstevel@tonic-gate root_to.sin_port = htons(nfs_port); /* NFS is next after mount */ 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate /* 748*7c478bd9Sstevel@tonic-gate * Create the CLIENT handle for NFS operations 749*7c478bd9Sstevel@tonic-gate */ 750*7c478bd9Sstevel@tonic-gate if (roothandle.version == NFS_VERSION) 751*7c478bd9Sstevel@tonic-gate bufsize = NFSBUF_SIZE; 752*7c478bd9Sstevel@tonic-gate else 753*7c478bd9Sstevel@tonic-gate bufsize = NFS3BUF_SIZE; 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate /* 756*7c478bd9Sstevel@tonic-gate * First try TCP then UDP (unless UDP asked for explicitly), if mountd 757*7c478bd9Sstevel@tonic-gate * alows this version but neither transport is available we are stuck. 758*7c478bd9Sstevel@tonic-gate */ 759*7c478bd9Sstevel@tonic-gate if (istcp) { 760*7c478bd9Sstevel@tonic-gate fd = -1; 761*7c478bd9Sstevel@tonic-gate root_CLIENT = clntbtcp_create(&root_to, NFS_PROGRAM, 762*7c478bd9Sstevel@tonic-gate roothandle.version, wait, &fd, bufsize, bufsize); 763*7c478bd9Sstevel@tonic-gate if (root_CLIENT != NULL) { 764*7c478bd9Sstevel@tonic-gate root_CLIENT->cl_auth = 765*7c478bd9Sstevel@tonic-gate authunix_create(my_hostname, 0, 1, 1, &fake_gids); 766*7c478bd9Sstevel@tonic-gate /* 767*7c478bd9Sstevel@tonic-gate * Send NULL proc, check if the server really exists 768*7c478bd9Sstevel@tonic-gate */ 769*7c478bd9Sstevel@tonic-gate rpc_stat = CLNT_CALL(root_CLIENT, 0, 770*7c478bd9Sstevel@tonic-gate xdr_void, NULL, xdr_void, NULL, wait); 771*7c478bd9Sstevel@tonic-gate 772*7c478bd9Sstevel@tonic-gate if (rpc_stat == RPC_SUCCESS) 773*7c478bd9Sstevel@tonic-gate return (0); 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate AUTH_DESTROY(root_CLIENT->cl_auth); 776*7c478bd9Sstevel@tonic-gate CLNT_DESTROY(root_CLIENT); 777*7c478bd9Sstevel@tonic-gate root_CLIENT = NULL; 778*7c478bd9Sstevel@tonic-gate } 779*7c478bd9Sstevel@tonic-gate /* Fall through to UDP case */ 780*7c478bd9Sstevel@tonic-gate } 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate fd = -1; 783*7c478bd9Sstevel@tonic-gate root_CLIENT = clntbudp_bufcreate(&root_to, NFS_PROGRAM, 784*7c478bd9Sstevel@tonic-gate roothandle.version, wait, &fd, bufsize, bufsize); 785*7c478bd9Sstevel@tonic-gate if (root_CLIENT == NULL) 786*7c478bd9Sstevel@tonic-gate return (-1); 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate root_CLIENT->cl_auth = 789*7c478bd9Sstevel@tonic-gate authunix_create(my_hostname, 0, 1, 1, &fake_gids); 790*7c478bd9Sstevel@tonic-gate /* 791*7c478bd9Sstevel@tonic-gate * Send NULL proc, check if the server really exists 792*7c478bd9Sstevel@tonic-gate */ 793*7c478bd9Sstevel@tonic-gate rpc_stat = CLNT_CALL(root_CLIENT, 0, 794*7c478bd9Sstevel@tonic-gate xdr_void, NULL, xdr_void, NULL, wait); 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate if (rpc_stat == RPC_SUCCESS) 797*7c478bd9Sstevel@tonic-gate return (0); 798*7c478bd9Sstevel@tonic-gate 799*7c478bd9Sstevel@tonic-gate AUTH_DESTROY(root_CLIENT->cl_auth); 800*7c478bd9Sstevel@tonic-gate CLNT_DESTROY(root_CLIENT); 801*7c478bd9Sstevel@tonic-gate root_CLIENT = NULL; 802*7c478bd9Sstevel@tonic-gate return (-1); 803*7c478bd9Sstevel@tonic-gate } 804