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