xref: /original-bsd/usr.sbin/amd/amd/nfs_subr.c (revision 9bffe400)
1 /*
2  * $Id: nfs_subr.c,v 5.2 90/06/23 22:19:50 jsp Rel $
3  *
4  * Copyright (c) 1990 Jan-Simon Pendry
5  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
6  * Copyright (c) 1990 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Jan-Simon Pendry at Imperial College, London.
11  *
12  * %sccs.include.redist.c%
13  *
14  *	@(#)nfs_subr.c	5.1 (Berkeley) 06/29/90
15  */
16 
17 #include "am.h"
18 
19 /*
20  * Convert from UN*X to NFS error code
21  */
22 #ifdef NFS_ERROR_MAPPING
23 NFS_ERROR_MAPPING
24 #define nfs_error(e) \
25         ((nfsstat)((e) > NFS_LOMAP && (e) < NFS_HIMAP ? \
26         nfs_errormap[(e) - NFS_LOMAP] : (e)))
27 #else
28 #define nfs_error(e) ((nfsstat)(e))
29 #endif /* NFS_ERROR_MAPPING */
30 
31 static char *do_readlink(mp, error_return, attrpp)
32 am_node *mp;
33 int *error_return;
34 struct attrstat **attrpp;
35 {
36 	char *ln;
37 
38 	/*
39 	 * If there is a readlink method, then use
40 	 * that, otherwise if a link exists use
41 	 * that, otherwise use the mount point.
42 	 */
43 	if (mp->am_mnt->mf_ops->readlink) {
44 		int retry = 0;
45 		mp = (*mp->am_mnt->mf_ops->readlink)(mp, &retry);
46 		if (mp == 0) {
47 			*error_return = retry;
48 			return 0;
49 		}
50 		/*reschedule_timeout_mp();*/
51 	}
52 	if (mp->am_link) {
53 		ln = mp->am_link;
54 	} else {
55 		ln = mp->am_mnt->mf_mount;
56 	}
57 	if (attrpp)
58 		*attrpp = &mp->am_mnt->mf_attr;
59 	return ln;
60 }
61 
62 /*ARGSUSED*/
63 voidp
64 nfsproc_null_2(argp, rqstp)
65 voidp argp;
66 struct svc_req *rqstp;
67 {
68 	static char res;
69 
70 	return (voidp) &res;
71 }
72 
73 
74 /*ARGSUSED*/
75 struct attrstat *
76 nfsproc_getattr_2(argp, rqstp)
77 struct nfs_fh *argp;
78 struct svc_req *rqstp;
79 {
80 	static struct attrstat res;
81 	am_node *mp;
82 	int retry;
83 
84 #ifdef DEBUG
85 	Debug(D_TRACE)
86 		plog(XLOG_DEBUG, "gettattr:");
87 #endif /* DEBUG */
88 
89 	mp = fh_to_mp2(argp, &retry);
90 	if (mp == 0) {
91 #ifdef PRECISE_SYMLINKS
92 getattr_retry:
93 #endif /* PRECISE_SYMLINKS */
94 
95 		if (retry < 0)
96 			return 0;
97 		res.status = nfs_error(retry);
98 	} else {
99 		struct attrstat *attrp = &mp->am_mnt->mf_attr;
100 #ifdef PRECISE_SYMLINKS
101 		if (mp->am_mnt->mf_fattr.type == NFLNK) {
102 			/*
103 			 * Make sure we can read the link,
104 			 * and then determine the length.
105 			 */
106 			char *ln = do_readlink(mp, &retry, &attrp);
107 			if (ln == 0)
108 				goto getattr_retry;
109 		}
110 #endif /* PRECISE_SYMLINKS */
111 #ifdef DEBUG
112 		Debug(D_TRACE)
113 			plog(XLOG_DEBUG, "\tstat(%s), size = %d", mp->am_path, attrp->attrstat_u.attributes.size);
114 #endif /* DEBUG */
115 		mp->am_stats.s_getattr++;
116 		return attrp;
117 	}
118 
119 	return &res;
120 }
121 
122 
123 /*ARGSUSED*/
124 struct attrstat *
125 nfsproc_setattr_2(argp, rqstp)
126 struct sattrargs *argp;
127 struct svc_req *rqstp;
128 {
129 	static struct attrstat res;
130 
131 	if (!fh_to_mp(&argp->file))
132 		res.status = nfs_error(ESTALE);
133 	else
134 		res.status = nfs_error(EROFS);
135 
136 	return &res;
137 }
138 
139 
140 /*ARGSUSED*/
141 voidp
142 nfsproc_root_2(argp, rqstp)
143 voidp argp;
144 struct svc_req *rqstp;
145 {
146 	static char res;
147 
148 	return (voidp)&res;
149 }
150 
151 
152 /*ARGSUSED*/
153 struct diropres *
154 nfsproc_lookup_2(argp, rqstp)
155 struct diropargs *argp;
156 struct svc_req *rqstp;
157 {
158 	static struct diropres res;
159 	am_node *mp;
160 	int retry;
161 
162 #ifdef DEBUG
163 	Debug(D_TRACE)
164 		plog(XLOG_DEBUG, "lookup:");
165 #endif /* DEBUG */
166 
167 	mp = fh_to_mp2(&argp->dir, &retry);
168 	if (mp == 0) {
169 		if (retry < 0)
170 			return 0;
171 		res.status = nfs_error(retry);
172 	} else {
173 		int error;
174 		am_node *ap;
175 #ifdef DEBUG
176 		Debug(D_TRACE)
177 			plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->name);
178 #endif /* DEBUG */
179 		ap = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &error, VLOOK_CREATE);
180 		if (ap == 0) {
181 			if (error < 0) {
182 #ifdef DEBUG
183 				dlog("Not sending RPC reply");
184 #endif /* DEBUG */
185 				amd_stats.d_drops++;
186 				return 0;
187 			}
188 			res.status = nfs_error(error);
189 		} else {
190 #ifdef DEBUG
191 			if (ap->am_mnt->mf_fattr.size < 0)
192 				dlog("\tERROR: size = %d!", ap->am_mnt->mf_fattr.size);
193 #endif /* DEBUG */
194 			mp_to_fh(ap, &res.diropres_u.diropres.file);
195 			res.diropres_u.diropres.attributes = ap->am_mnt->mf_fattr;
196 			res.status = NFS_OK;
197 		}
198 		mp->am_stats.s_lookup++;
199 		/*reschedule_timeout_mp();*/
200 	}
201 
202 	return &res;
203 }
204 
205 
206 /*ARGSUSED*/
207 struct readlinkres *
208 nfsproc_readlink_2(argp, rqstp)
209 struct nfs_fh *argp;
210 struct svc_req *rqstp;
211 {
212 	static struct readlinkres res;
213 	am_node *mp;
214 	int retry;
215 
216 #ifdef DEBUG
217 	Debug(D_TRACE)
218 		plog(XLOG_DEBUG, "readlink:");
219 #endif /* DEBUG */
220 
221 	mp = fh_to_mp2(argp, &retry);
222 	if (mp == 0) {
223 readlink_retry:
224 		if (retry < 0)
225 			return 0;
226 		res.status = nfs_error(retry);
227 	} else {
228 		char *ln = do_readlink(mp, &retry, (struct attrstat *) 0);
229 		if (ln == 0)
230 			goto readlink_retry;
231 		res.status = NFS_OK;
232 #ifdef DEBUG
233 		Debug(D_TRACE)
234 			if (ln)
235 				plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
236 #endif /* DEBUG */
237 		res.readlinkres_u.data = ln;
238 		mp->am_stats.s_readlink++;
239 	}
240 
241 	return &res;
242 }
243 
244 
245 /*ARGSUSED*/
246 struct readres *
247 nfsproc_read_2(argp, rqstp)
248 struct readargs *argp;
249 struct svc_req *rqstp;
250 {
251 	static struct readres res;
252 
253 	bzero((char *)&res, sizeof(res));
254 
255 	res.status = nfs_error(EACCES);
256 
257 	return &res;
258 }
259 
260 
261 /*ARGSUSED*/
262 voidp
263 nfsproc_writecache_2(argp, rqstp)
264 voidp argp;
265 struct svc_req *rqstp;
266 {
267 	static char res;
268 
269 	return (voidp) &res;
270 }
271 
272 
273 /*ARGSUSED*/
274 struct attrstat *
275 nfsproc_write_2(argp, rqstp)
276 writeargs *argp;
277 struct svc_req *rqstp;
278 {
279 	static struct attrstat res;
280 
281 	if (!fh_to_mp(&argp->file))
282 		res.status = nfs_error(ESTALE);
283 	else
284 		res.status = nfs_error(EROFS);
285 
286 	return &res;
287 }
288 
289 
290 /*ARGSUSED*/
291 struct diropres *
292 nfsproc_create_2(argp, rqstp)
293 createargs *argp;
294 struct svc_req *rqstp;
295 {
296 	static struct diropres res;
297 
298 	if (!fh_to_mp(&argp->where.dir))
299 		res.status = nfs_error(ESTALE);
300 	else
301 		res.status = nfs_error(EROFS);
302 
303 	return &res;
304 }
305 
306 
307 /*ARGSUSED*/
308 static nfsstat *
309 unlink_or_rmdir(argp, rqstp, unlinkp)
310 struct diropargs *argp;
311 struct svc_req *rqstp;
312 {
313 	static nfsstat res;
314 	int retry;
315 	mntfs *mf;
316 	am_node *mp = fh_to_mp3(&argp->dir, &retry, VLOOK_DELETE);
317 	if (mp == 0) {
318 		if (retry < 0)
319 			return 0;
320 		res = nfs_error(retry);
321 		goto out;
322 	}
323 	mf = mp->am_mnt;
324 	if (mf->mf_fattr.type != NFDIR) {
325 		res = nfs_error(ENOTDIR);
326 		goto out;
327 	}
328 #ifdef DEBUG
329 	Debug(D_TRACE)
330 		plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->name);
331 #endif /* DEBUG */
332 	mp = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &retry, VLOOK_DELETE);
333 	if (mp == 0) {
334 		/*
335 		 * Ignore retries...
336 		 */
337 		if (retry < 0)
338 			retry = 0;
339 		/*
340 		 * Usual NFS workaround...
341 		 */
342 		else if (retry == ENOENT)
343 			retry = 0;
344 		res = nfs_error(retry);
345 	} else {
346 		forcibly_timeout_mp(mp);
347 		res = NFS_OK;
348 	}
349 
350 out:
351 	return &res;
352 }
353 
354 
355 /*ARGSUSED*/
356 nfsstat *
357 nfsproc_remove_2(argp, rqstp)
358 struct diropargs *argp;
359 struct svc_req *rqstp;
360 {
361 	return unlink_or_rmdir(argp, rqstp, 1);
362 }
363 
364 /*ARGSUSED*/
365 nfsstat *
366 nfsproc_rename_2(argp, rqstp)
367 renameargs *argp;
368 struct svc_req *rqstp;
369 {
370 	static nfsstat res;
371 	if (!fh_to_mp(&argp->from.dir) || !fh_to_mp(&argp->to.dir))
372 		res = nfs_error(ESTALE);
373 	/*
374 	 * If the kernel is doing clever things with referenced files
375 	 * then let it pretend...
376 	 */
377 	else if (strncmp(argp->to.name, ".nfs", 4) == 0)
378 		res = NFS_OK;
379 	/*
380 	 * otherwise a failure
381 	 */
382 	else
383 		res = nfs_error(EROFS);
384 	return &res;
385 }
386 
387 
388 /*ARGSUSED*/
389 nfsstat *
390 nfsproc_link_2(argp, rqstp)
391 linkargs *argp;
392 struct svc_req *rqstp;
393 {
394 	static nfsstat res;
395 	if (!fh_to_mp(&argp->from) || !fh_to_mp(&argp->to.dir))
396 		res = nfs_error(ESTALE);
397 	else
398 		res = nfs_error(EROFS);
399 
400 	return &res;
401 }
402 
403 
404 /*ARGSUSED*/
405 nfsstat *
406 nfsproc_symlink_2(argp, rqstp)
407 symlinkargs *argp;
408 struct svc_req *rqstp;
409 {
410 	static nfsstat res;
411 	if (!fh_to_mp(&argp->from.dir))
412 		res = nfs_error(ESTALE);
413 	else
414 		res = nfs_error(EROFS);
415 
416 	return &res;
417 }
418 
419 
420 /*ARGSUSED*/
421 struct diropres *
422 nfsproc_mkdir_2(argp, rqstp)
423 createargs *argp;
424 struct svc_req *rqstp;
425 {
426 	static struct diropres res;
427 	if (!fh_to_mp(&argp->where.dir))
428 		res.status = nfs_error(ESTALE);
429 	else
430 		res.status = nfs_error(EROFS);
431 
432 	return &res;
433 }
434 
435 
436 /*ARGSUSED*/
437 nfsstat *
438 nfsproc_rmdir_2(argp, rqstp)
439 struct diropargs *argp;
440 struct svc_req *rqstp;
441 {
442 	return unlink_or_rmdir(argp, rqstp, 0);
443 }
444 
445 
446 /*ARGSUSED*/
447 struct readdirres *
448 nfsproc_readdir_2(argp, rqstp)
449 readdirargs *argp;
450 struct svc_req *rqstp;
451 {
452 	static readdirres res;
453 	static entry e_res[2];
454 	am_node *mp;
455 	int retry;
456 
457 #ifdef DEBUG
458 	Debug(D_TRACE)
459 		plog(XLOG_DEBUG, "readdir:");
460 #endif /* DEBUG */
461 
462 	mp = fh_to_mp2(&argp->dir, &retry);
463 	if (mp == 0) {
464 		if (retry < 0)
465 			return 0;
466 		res.status = nfs_error(retry);
467 	} else {
468 #ifdef DEBUG
469 		Debug(D_TRACE)
470 			plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path);
471 #endif /* DEBUG */
472 		res.status = nfs_error((*mp->am_mnt->mf_ops->readdir)(mp, argp->cookie,
473 					&res.readdirres_u.reply, e_res));
474 		mp->am_stats.s_readdir++;
475 	}
476 
477 	/* XXX - need to take argp->count into account */
478 
479 	return &res;
480 }
481 
482 /*ARGSUSED*/
483 struct statfsres *
484 nfsproc_statfs_2(argp, rqstp)
485 struct nfs_fh *argp;
486 struct svc_req *rqstp;
487 {
488 	static statfsres res;
489 	am_node *mp;
490 	int retry;
491 
492 #ifdef DEBUG
493 	Debug(D_TRACE)
494 		plog(XLOG_DEBUG, "statfs:");
495 #endif /* DEBUG */
496 
497 	mp = fh_to_mp2(argp, &retry);
498 	if (mp == 0) {
499 		if (retry < 0)
500 			return 0;
501 		res.status = nfs_error(retry);
502 	} else {
503 		statfsokres *fp;
504 #ifdef DEBUG
505 		Debug(D_TRACE)
506 			plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path);
507 #endif /* DEBUG */
508 		/*
509 		 * just return faked up file system information
510 		 */
511 
512 		fp = &res.statfsres_u.reply;
513 
514 		fp->tsize = 1024;
515 		fp->bsize = 4192;
516 		fp->blocks = 1;
517 		fp->bfree = 0;
518 		fp->bavail = 0;
519 
520 		res.status = NFS_OK;
521 		mp->am_stats.s_statfs++;
522 	}
523 
524 	return &res;
525 }
526