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 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * Simple nfs ops - open, close, read, and lseek. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <rpc/types.h> 31 #include <rpc/auth.h> 32 #include <sys/t_lock.h> 33 #include "clnt.h" 34 #include <sys/fcntl.h> 35 #include <sys/vfs.h> 36 #include <errno.h> 37 #include <sys/promif.h> 38 #include <rpc/xdr.h> 39 #include "nfs_inet.h" 40 #include <sys/stat.h> 41 #include <sys/bootvfs.h> 42 #include <sys/bootdebug.h> 43 #include <sys/salib.h> 44 #include <sys/sacache.h> 45 #include <rpc/rpc.h> 46 #include "brpc.h" 47 #include <rpcsvc/nfs_prot.h> 48 #include "socket_inet.h" 49 #include "mac.h" 50 #include <sys/mode.h> 51 52 ushort_t vttoif_tab[] = { 53 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, 54 S_IFDOOR, 0, S_IFSOCK, 0 55 }; 56 57 static int file_desc = 1; 58 static struct nfs_files { 59 struct nfs_file file; 60 int desc; 61 struct nfs_files *next; 62 } nfs_files[1] = { 63 {0, 0, 0}, 64 }; 65 66 #define dprintf if (boothowto & RB_DEBUG) printf 67 68 static int boot_nfs_open(char *filename, int flags); 69 static int boot_nfs_close(int fd); 70 static ssize_t boot_nfs_read(int fd, caddr_t buf, size_t size); 71 static off_t boot_nfs_lseek(int, off_t, int); 72 static int boot_nfs_fstat(int fd, struct bootstat *stp); 73 static void boot_nfs_closeall(int flag); 74 static int boot_nfs_getdents(int fd, struct dirent *dep, unsigned size); 75 76 struct boot_fs_ops boot_nfs_ops = { 77 "nfs", 78 boot_nfs_mountroot, 79 boot_nfs_unmountroot, 80 boot_nfs_open, 81 boot_nfs_close, 82 boot_nfs_read, 83 boot_nfs_lseek, 84 boot_nfs_fstat, 85 boot_nfs_closeall, 86 boot_nfs_getdents 87 }; 88 89 /* 90 * bootops.c calls a closeall() function to close all open files. Since 91 * we only permit one open file at a time (not counting the device), this 92 * is simple to implement. 93 */ 94 95 /*ARGSUSED*/ 96 static void 97 boot_nfs_closeall(int flag) 98 { 99 struct nfs_files *filep; 100 101 #ifdef NFS_OPS_DEBUG 102 if ((boothowto & DBFLAGS) == DBFLAGS) 103 printf("boot_nfs_closeall(%x)\n", flag); 104 #endif 105 106 if (nfs_files->file.version == 0 && 107 nfs_files->desc == 0 && 108 nfs_files->next == NULL) 109 return; 110 111 /* delete any dynamically allocated entries */ 112 while ((filep = nfs_files->next) != NULL) { 113 nfs_files->next = filep->next; 114 bkmem_free((caddr_t)filep, sizeof (struct nfs_files)); 115 } 116 117 /* clear the first, static file */ 118 bzero((caddr_t)nfs_files, sizeof (struct nfs_files)); 119 120 /* Close device */ 121 release_cache(mac_get_dev()); 122 123 mac_fini(); 124 } 125 126 /* 127 * Get a file pointer given a file descriptor. Return 0 on error 128 */ 129 static struct nfs_files * 130 get_filep(int fd) 131 { 132 struct nfs_files *filep; 133 134 for (filep = nfs_files; filep; filep = filep->next) { 135 if (fd == filep->desc) 136 return (filep); 137 } 138 return (NULL); 139 } 140 141 /* 142 * Unmount the root fs -- not supported for this fstype. 143 */ 144 145 int 146 boot_nfs_unmountroot(void) 147 { 148 return (-1); 149 } 150 151 /* 152 * open a file for reading. Note: writing is NOT supported. 153 */ 154 155 static int 156 boot_nfs_open(char *path, int flags) 157 { 158 struct nfs_files *filep, *newfilep; 159 int got_filep; 160 161 #ifdef NFS_OPS_DEBUG 162 if ((boothowto & DBFLAGS) == DBFLAGS) 163 printf("boot_nfs_open(%s, %x)\n", path, flags); 164 #endif 165 166 /* file can only be opened readonly. */ 167 if (flags & ~O_RDONLY) { 168 dprintf("boot_nfs_open: files can only be opened O_RDONLY.\n"); 169 return (-1); 170 } 171 172 if (path == NULL || *path == '\0') { 173 dprintf("boot_nfs_open: NULL or EMPTY pathname argument.\n"); 174 return (-1); 175 } 176 177 /* Try and find a vacant file pointer */ 178 filep = nfs_files; 179 got_filep = FALSE; 180 do { 181 if (filep->desc == 0) { 182 filep->desc = file_desc++; 183 got_filep = TRUE; 184 break; /* We've got a file pointer */ 185 } 186 /* Get next entry if not at end of list */ 187 if (filep->next) 188 filep = filep->next; 189 } while (filep->next); 190 191 /* If a a vacant file pointer cannot be found, make one */ 192 if (!got_filep) { 193 if ((newfilep = (struct nfs_files *) 194 bkmem_zalloc(sizeof (struct nfs_files))) == 0) { 195 dprintf("open: Cannot allocate file pointer\n"); 196 return (-1); 197 } 198 filep->next = newfilep; 199 filep = newfilep; 200 filep->desc = file_desc++; 201 } 202 203 if (lookup(path, &filep->file, FALSE) != 0) { 204 #ifdef NFS_OPS_DEBUG 205 if ((boothowto & DBFLAGS) == DBFLAGS) 206 printf("boot_nfs_open(): Cannot open '%s'.\n", path); 207 #endif 208 /* zero file pointer */ 209 bzero((caddr_t)filep, sizeof (struct nfs_file)); 210 filep->desc = 0; 211 return (-1); 212 } 213 bzero(&filep->file.cookie, sizeof (filep->file.cookie)); 214 215 #ifdef NFS_OPS_DEBUG 216 if ((boothowto & DBFLAGS) == DBFLAGS) 217 printf("boot_nfs_open(): '%s' successful, fd = 0x%x\n", 218 path, filep->desc); 219 #endif 220 return (filep->desc); 221 } 222 223 /* 224 * close a previously opened file. 225 */ 226 static int 227 boot_nfs_close(int fd) 228 { 229 struct nfs_files *filep; 230 231 #ifdef NFS_OPS_DEBUG 232 if ((boothowto & DBFLAGS) == DBFLAGS) 233 printf("boot_nfs_close(%d)\n", fd); 234 #endif 235 if ((filep = get_filep(fd)) == 0) 236 return (0); 237 238 /* 239 * zero file pointer 240 */ 241 bzero((caddr_t)&filep->file, sizeof (struct nfs_file)); 242 243 /* 244 * "close" the fd. 245 */ 246 filep->desc = 0; 247 248 return (0); 249 } 250 251 /* 252 * read from a file. 253 */ 254 static ssize_t 255 boot_nfs_read(int fd, char *buf, size_t size) 256 { 257 struct nfs_files *filep; 258 int count = 0; 259 260 if (fd == 0) { 261 dprintf("boot_nfs_read: Bad file number.\n"); 262 return (-1); 263 } 264 if (buf == NULL) { 265 dprintf("boot_nfs_read: Bad address.\n"); 266 return (-1); 267 } 268 269 #ifdef NFS_OPS_DEBUG 270 if ((boothowto & DBFLAGS) == DBFLAGS) 271 printf("boot_nfs_read(%d, %x, 0x%x)\n", fd, buf, size); 272 #endif 273 274 /* initialize for read */ 275 if ((filep = get_filep(fd)) == 0) 276 return (-1); 277 278 switch (filep->file.version) { 279 case NFS_VERSION: 280 count = nfsread(&filep->file, buf, size); 281 break; 282 case NFS_V3: 283 count = nfs3read(&filep->file, buf, size); 284 break; 285 case NFS_V4: 286 count = nfs4read(&filep->file, buf, size); 287 break; 288 default: 289 printf("boot_nfs_read: NFS Version %d not supported\n", 290 filep->file.version); 291 count = -1; 292 break; 293 } 294 295 #ifdef NFS_OPS_DEBUG 296 if ((boothowto & DBFLAGS) == DBFLAGS) 297 printf("boot_nfs_read(): 0x%x bytes.\n", count); 298 #endif 299 return (count); 300 } 301 302 /* 303 * lseek - move read file pointer. 304 */ 305 306 static off_t 307 boot_nfs_lseek(int fd, off_t offset, int whence) 308 { 309 struct nfs_files *filep; 310 311 #ifdef NFS_OPS_DEBUG 312 if ((boothowto & DBFLAGS) == DBFLAGS) 313 printf("boot_nfs_lseek(%d, 0x%x, %d)\n", fd, offset, whence); 314 #endif 315 316 if (fd == 0) { 317 dprintf("boot_nfs_lseek: Bad file number.\n"); 318 return (-1); 319 } 320 321 if ((filep = get_filep(fd)) == 0) 322 return (-1); 323 324 switch (whence) { 325 326 case SEEK_SET: 327 /* 328 * file ptr is set to offset from beginning of file 329 */ 330 filep->file.offset = offset; 331 break; 332 case SEEK_CUR: 333 /* 334 * file ptr is set to offset from current position 335 */ 336 filep->file.offset += offset; 337 break; 338 case SEEK_END: 339 /* 340 * file ptr is set to current size of file plus offset. 341 * But since we only support reading, this is illegal. 342 */ 343 default: 344 /* 345 * invalid offset origin 346 */ 347 dprintf("boot_nfs_lseek: invalid whence value.\n"); 348 return (-1); 349 } 350 351 #ifdef notyet 352 return (filep->file.offset); 353 #else 354 /* 355 * BROKE - lseek should return the offset seeked to on a 356 * successful seek, not zero - This must be fixed in the 357 * kernel before It can be fixed here. 358 */ 359 return (0); 360 #endif /* notyet */ 361 } 362 363 /* 364 * This version of fstat supports mode, size, inode #, and times only. 365 * It can be enhanced if more is required, 366 */ 367 368 static int 369 boot_nfs_fstat(int fd, struct bootstat *stp) 370 { 371 struct vattr va; 372 struct nfs_files *filep; 373 int status; 374 375 #ifdef NFS_OPS_DEBUG 376 if ((boothowto & DBFLAGS) == DBFLAGS) { 377 printf("boot_nfs_fstat(%d, 0x%x)\n", fd, stp); 378 } 379 #endif 380 if (fd == 0) { 381 dprintf("boot_nfs_fstat(): Bad file number 0.\n"); 382 return (-1); 383 } 384 385 if ((filep = get_filep(fd)) == 0) 386 return (-1); 387 388 bzero((char *)&va, sizeof (va)); 389 va.va_mask = AT_TYPE | AT_SIZE | AT_MODE | AT_NODEID | 390 AT_ATIME | AT_CTIME | AT_MTIME; 391 392 switch (filep->file.version) { 393 case NFS_VERSION: 394 status = nfsgetattr(&filep->file, &va); 395 break; 396 case NFS_V3: 397 status = nfs3getattr(&filep->file, &va); 398 break; 399 case NFS_V4: 400 status = nfs4getattr(&filep->file, &va); 401 break; 402 default: 403 printf("boot_nfs_fstat: NFS Version %d not supported\n", 404 filep->file.version); 405 status = -1; 406 break; 407 } 408 409 if (status != 0) 410 return (-1); 411 412 if (va.va_size > (u_offset_t)MAXOFF_T) { 413 dprintf("boot_nfs_fstat(): File too large.\n"); 414 return (-1); 415 } 416 stp->st_size = (off_t)va.va_size; 417 stp->st_mode = VTTOIF(va.va_type) | va.va_mode; 418 stp->st_atim.tv_sec = va.va_atime.tv_sec; 419 stp->st_atim.tv_nsec = va.va_atime.tv_nsec; 420 stp->st_ctim.tv_sec = va.va_ctime.tv_sec; 421 stp->st_ctim.tv_nsec = va.va_ctime.tv_nsec; 422 stp->st_mtim.tv_sec = va.va_mtime.tv_sec; 423 stp->st_mtim.tv_nsec = va.va_mtime.tv_nsec; 424 stp->st_ino = (ino_t)va.va_nodeid; 425 426 #ifdef NFS_OPS_DEBUG 427 if ((boothowto & DBFLAGS) == DBFLAGS) 428 printf("boot_nfs_fstat(): done.\n"); 429 #endif 430 return (0); 431 } 432 433 static int 434 boot_nfs_getdents(int fd, struct dirent *dep, unsigned size) 435 { 436 struct nfs_files *filep; 437 int status; 438 439 #ifdef NFS_OPS_DEBUG 440 if ((boothowto & DBFLAGS) == DBFLAGS) { 441 printf("boot_nfs_getdents(%d, 0x%x, 0x%x)\n", fd, dep, size); 442 } 443 #endif 444 445 if (fd == 0) { 446 dprintf("boot_nfs_getdents(): Bad file number 0.\n"); 447 return (-1); 448 } 449 450 if ((filep = get_filep(fd)) == 0) 451 return (-1); 452 453 switch (filep->file.version) { 454 case NFS_VERSION: 455 status = nfsgetdents(&filep->file, dep, size); 456 break; 457 case NFS_V3: 458 status = nfs3getdents(&filep->file, dep, size); 459 break; 460 default: 461 printf("boot_nfs_getdents: NFS Version %d not supported\n", 462 filep->file.version); 463 status = -1; 464 } 465 466 #ifdef NFS_OPS_DEBUG 467 if ((boothowto & DBFLAGS) == DBFLAGS) 468 printf("boot_nfs_getdents(): done.\n"); 469 #endif 470 return (status); 471 } 472