xref: /titanic_52/usr/src/stand/lib/fs/nfs/nfsops.c (revision 3db86aab554edbb4244c8d1a1c90f152eee768af)
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