1 /*
2  * Copyright (c) 1990-1998 by Leendert van Doorn <leendert@paramecium.org>
3  * Copyright (c) 2013 by Michael Brown, Net Direct <michael@netdirect.ca>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in the
12  *       documentation and/or other materials provided with the distribution.
13  *     * Neither the name of Vrije Universiteit, Net Direct nor the
14  *       names of its contributors may be used to endorse or promote products
15  *       derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL LEENDERT VAN DOORN, VRIJE UNIVERSITEIT
21  * (AMSTERDAM), MICHAEL BROWN, OR NET DIRECT (CANADA) BE LIABLE FOR ANY DIRECT,
22  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * Tested on the following systems:
32  *	System V release 4 (386)
33  *	SunOS 4.[123] (SPARC/SUN3)
34  *	DEC Ultrix 4.[23] (DEC Station 5100)
35  *	AIX 4.1
36  *	Linux 2.0.33
37  *	Linux Redhat 5
38  */
39 
40 /*
41  * nfs - A shell that provides access to NFS file systems
42  *
43  * Contributions:
44  *	- Source routing inspired by Casper Dik's code.
45  *	- Linux modifications (and other cleanup) inspired by Marc Heuse
46  *	- Porting to NFSv3 done by Michael Brown
47  */
48 #include <assert.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <ctype.h>
52 #include <signal.h>
53 #include <setjmp.h>
54 #include <netdb.h>
55 #include <errno.h>
56 #ifdef AIX
57 #define	blkcnt_t long		/* hack alert */
58 #endif
59 #include <unistd.h>
60 #include <stdlib.h>
61 #include <time.h>
62 #include <rpc/rpc.h>
63 #include <rpc/key_prot.h>
64 #include <rpc/pmap_clnt.h>
65 #ifdef SYSV
66 #include <rpc/clnt_soc.h>
67 #endif
68 #include <sys/ioctl.h>
69 #include <sys/socket.h>
70 #include <netinet/in.h>
71 #include <arpa/inet.h>
72 #include <sys/time.h>
73 #include <sys/param.h>
74 #include "mount.h"
75 #include "nfs_prot.h"
76 #include <netinet/in_systm.h>
77 #include <netinet/ip.h>
78 
79 #ifdef READLINE
80 #include <readline/readline.h>
81 #include <readline/history.h>
82 #endif
83 
84 /*
85  * Missing from clnt.h on Linux
86  */
87 #ifndef CLSET_FD_CLOSE
88 #define CLSET_FD_CLOSE	8	/* close fd while clnt_destroy */
89 #endif
90 
91 /*
92  * Fundamental constants
93  */
94 #define	NARGVEC		100	/* maximum number of arguments */
95 
96 /*
97  * File modes
98  */
99 #ifndef IFCHR
100 #define	IFCHR		0020000		/* character special */
101 #define	IFBLK		0060000		/* block special */
102 #define	IFSOCK		0140000		/* socket */
103 #endif /* IFCHR */
104 
105 /*
106  * NFS mount options
107  */
108 #define	NFS_OVER_UDP	01		/* use NFS over UDP/IP */
109 #define	NFS_OVER_TCP	02		/* use NFS over TCP/IP */
110 #define	TRANSPORT_MASK	03		/* mask out transport */
111 #define	THRU_PORTMAP	010		/* use portmapper proxy call */
112 #define	MOUNT_UMOUNT	020		/* mount followed by umount */
113 
114 /*
115  * List of command identifiers
116  */
117 #define	CMD_UNKNOWN	0	/* unknown command */
118 #define	CMD_HOST	1	/* host <host> */
119 #define	CMD_UID		2	/* uid [<uid> [<secret-key>]] */
120 #define	CMD_GID		3	/* gid [<gid>] */
121 #define	CMD_CD		4	/* cd [<path>] */
122 #define	CMD_LCD		5	/* lcd [<path>] */
123 #define	CMD_CAT		6	/* cat <filespec> */
124 #define	CMD_LS		7	/* ls [-l] <filespec> */
125 #define	CMD_GET		8	/* get <filespec> */
126 #define	CMD_DF		9	/* df */
127 #define	CMD_MOUNT	10	/* mount [-upTU] <path> */
128 #define	CMD_UMOUNT	11	/* umount */
129 #define	CMD_UMOUNTALL	12	/* umountall */
130 #define	CMD_EXPORT	13	/* export */
131 #define	CMD_DUMP	14	/* dump */
132 #define	CMD_STATUS	15	/* status */
133 #define	CMD_HELP	16	/* help */
134 #define	CMD_QUIT	17	/* quit */
135 #define	CMD_RM		18	/* rm <file> */
136 #define	CMD_LN		19	/* ln <file1> <file2> */
137 #define	CMD_MV		20	/* mv <file1> <file2> */
138 #define	CMD_MKDIR	21	/* mkdir <dir> */
139 #define	CMD_RMDIR	22	/* rmdir <dir> */
140 #define	CMD_CHMOD	23	/* chmod <mode> <file> */
141 #define	CMD_CHOWN	24	/* chown <uid>[.<gid>] <file> */
142 #define	CMD_PUT		25	/* put <local-file> [<remote-file>] */
143 #define CMD_HANDLE	26	/* handle [<file-handle>] */
144 #define	CMD_MKNOD	27	/* mknod <name> [b/c major minor] [p] */
145 
146 /*
147  * Key word table
148  */
149 struct keyword {
150     char *kw_command;
151     int kw_value;
152     char *kw_help;
153 } keyword[] = {
154     { "host",	  CMD_HOST,	"<host> - set remote host name" },
155     { "uid",	  CMD_UID,	"[<uid> [<secret-key>]] - set remote user id" },
156     { "gid",	  CMD_GID,	"[<gid>] - set remote group id" },
157     { "cd",	  CMD_CD,	"[<path>] - change remote working directory" },
158     { "lcd",	  CMD_LCD,	"[<path>] - change local working directory" },
159     { "cat",	  CMD_CAT,	"<filespec> - display remote file" },
160     { "ls",	  CMD_LS,	"[-l] <filespec> - list remote directory" },
161     { "get",	  CMD_GET,	"<filespec> - get remote files" },
162     { "df",	  CMD_DF,	"- file system information" },
163     { "rm",	  CMD_RM,	"<file> - delete remote file" },
164     { "ln",	  CMD_LN,	"<file1> <file2> - link file" },
165     { "mv",	  CMD_MV,	"<file1> <file2> - move file" },
166     { "mkdir",	  CMD_MKDIR,	"<dir> - make remote directory" },
167     { "rmdir",	  CMD_RMDIR,	"<dir> - remove remote directory" },
168     { "chmod",	  CMD_CHMOD,	"<mode> <file> - change mode" },
169     { "chown",	  CMD_CHOWN,	"<uid>[.<gid>] <file> -  change owner" },
170     { "put",	  CMD_PUT,	"<local-file> [<remote-file>] - put file" },
171     { "mount",	  CMD_MOUNT,	"[-upTU] [-P port] <path> - mount file system" },
172     { "umount",	  CMD_UMOUNT,	"- umount remote file system" },
173     { "umountall",CMD_UMOUNTALL,"- umount all remote file systems" },
174     { "export",	  CMD_EXPORT,	"- show all exported file systems" },
175     { "dump",	  CMD_DUMP,	"- show all remote mounted file systems" },
176     { "status",	  CMD_STATUS,	"- general status report" },
177     { "help",	  CMD_HELP,	"- this help message" },
178     { "quit",	  CMD_QUIT,	"- its all in the name" },
179     { "bye",	  CMD_QUIT,	"- good bye" },
180     { "handle",	  CMD_HANDLE,	"[<handle>] - get/set directory file handle" },
181     { "mknod",	  CMD_MKNOD,	"<name> [b/c major minor] [p] - make device" }
182 };
183 
184 /* run-time settable flags */
185 int verbose = 1;		/* verbosity flag */
186 int interact = 1;		/* interactive mode */
187 
188 /* user provided credentials */
189 int authtype = AUTH_UNIX;	/* type of authentication */
190 int uid = -2;			/* remote user id (initialy nobody) */
191 int gid = -2;			/* remote group id (initialy nobody) */
192 keybuf secretkey;		/* remote user's secret key */
193 
194 /* server information (also used as state information) */
195 char *mountpath = NULL;		/* remote mount path */
196 char *remotehost = NULL;	/* remote host name */
197 struct sockaddr_in server_addr;	/* remote server address information */
198 struct sockaddr_in mntserver_addr; /* remote mount server address */
199 struct sockaddr_in nfsserver_addr; /* remote nfs server address */
200 CLIENT *mntclient = NULL;	/* mount RPC client */
201 CLIENT *nfsclient = NULL;	/* nfs RPC client */
202 mountres3 *mountpoint = NULL;	/* remote mount point */
203 nfs_fh3 directory_handle;	/* current directory handle */
204 struct timeval timeout = { 60, 0 }; /* default time out */
205 int transfersize;		/* NFS default transfer size */
206 
207 /* interrupt environments */
208 jmp_buf intenv;			/* where to go in interrupts */
209 
210 void interrupt(int);
211 int command(char *);
212 int ngetline(char *, int, int *, char **, int);
213 void do_host(int, char **);
214 void do_setuid(int, char **);
215 void do_setgid(int, char **);
216 void do_cd(int, char **);
217 void do_lcd(int, char **);
218 void do_cat(int, char **);
219 void do_ls(int, char **);
220 void do_get(int, char **);
221 void do_df(int, char **);
222 void do_rm(int, char **);
223 void do_ln(int, char **);
224 void do_mv(int, char **);
225 void do_mkdir(int, char **);
226 void do_rmdir(int, char **);
227 void do_chmod(int, char **);
228 void do_mknod(int, char **);
229 void do_chown(int, char **);
230 void do_put(int, char **);
231 void do_handle(int, char **);
232 void do_mount(int, char **);
233 void do_umount(int, char **);
234 void do_umountall(int, char **);
235 void do_export(int, char **);
236 void do_dump(int, char **);
237 void do_status(int, char **);
238 void do_help(int, char **);
239 
240 AUTH *create_authenticator(void);
241 char *mount_error(enum mountstat3);
242 char *nfs_error(enum nfsstat3);
243 int open_mount(char *);
244 void close_mount(void);
245 int sourceroute(char *, struct sockaddr_in *, int, int);
246 int open_nfs(char *, int, int);
247 mountres3 *pmap_mnt(dirpath *, struct sockaddr_in *);
248 int determine_transfersize(void);
249 int setup(int , struct sockaddr_in *, int, int);
250 int privileged(int, struct sockaddr_in *);
251 void close_nfs(void);
252 
253 int getdirentries(nfs_fh3 *, char ***, char ***, int);
254 void printfilestatus(char *file);
255 int writefiledate(time_t);
256 int match(char *, int, char **);
257 int matchpattern(char *, char *);
258 int amatchpattern(char *, char *);
259 int umatchpattern(char *, char *);
260 
261 
262 void*
263 memcpy(void *dest, const void *src, size_t n);
264 
265 void*
fhandle3copy(fhandle3 * dest,const fhandle3 * src)266 fhandle3copy(fhandle3 *dest, const fhandle3 *src)
267 {
268     dest->fhandle3_len = src->fhandle3_len;
269     return memcpy(dest->fhandle3_val, src->fhandle3_val, FHSIZE3);
270 }
271 
272 void*
fhandle3_to_nfs_fh3(nfs_fh3 * dest,const fhandle3 * src)273 fhandle3_to_nfs_fh3(nfs_fh3 *dest, const fhandle3 *src)
274 {
275     dest->data.data_len = src->fhandle3_len;
276     return memcpy(dest->data.data_val, src->fhandle3_val, MIN(NFS3_FHSIZE,FHSIZE3));
277 }
278 
279 void*
nfs_fh3copy(nfs_fh3 * dest,const nfs_fh3 * src)280 nfs_fh3copy(nfs_fh3 *dest, const nfs_fh3 *src)
281 {
282     dest->data.data_len = src->data.data_len;
283     return memcpy(dest->data.data_val, src->data.data_val, NFS3_FHSIZE);
284 }
285 
286 int
main(int argc,char ** argv)287 main(int argc, char **argv)
288 {
289     int opt, cmd, argcount;
290     char *argvec[NARGVEC];
291     char buffer[BUFSIZ];
292 
293     /* command line option processing */
294     while ((opt = getopt(argc, argv, "vi")) != EOF) {
295 	switch (opt) {
296 	case 'v':
297 	    verbose = 0;
298 	    break;
299 	case 'i':
300 	    interact = 0;
301 	    break;
302 	default:
303 	    fprintf(stderr, "Usage: %s [-vi]\n"
304 			    "\t-v\tverbose off\n"
305 			    "\t-i\tinteractive mode off\n", argv[0]);
306 	    exit(1);
307 	}
308     }
309 
310     signal(SIGINT, interrupt);
311 
312     /* interpreter's main command loop */
313     if (setjmp(intenv)) putchar('\n');
314     while (ngetline(buffer, BUFSIZ, &argcount, argvec, NARGVEC)) {
315 	if (argcount == 0) continue;
316 	if ((cmd = command(argvec[0])) == CMD_QUIT)
317 	    break;
318 	else switch (cmd) {
319 	case CMD_HOST:
320 	    do_host(argcount, argvec);
321 	    break;
322 	case CMD_UID:
323 	    do_setuid(argcount, argvec);
324 	    break;
325 	case CMD_GID:
326 	    do_setgid(argcount, argvec);
327 	    break;
328 	case CMD_CD:
329 	    do_cd(argcount, argvec);
330 	    break;
331 	case CMD_LCD:
332 	    do_lcd(argcount, argvec);
333 	    break;
334 	case CMD_CAT:
335 	    do_cat(argcount, argvec);
336 	    break;
337 	case CMD_LS:
338 	    do_ls(argcount, argvec);
339 	    break;
340 	case CMD_GET:
341 	    do_get(argcount, argvec);
342 	    break;
343 	case CMD_DF:
344 	    do_df(argcount, argvec);
345 	    break;
346 	case CMD_RM:
347 	    do_rm(argcount, argvec);
348 	    break;
349 	case CMD_LN:
350 	    do_ln(argcount, argvec);
351 	    break;
352 	case CMD_MV:
353 	    do_mv(argcount, argvec);
354 	    break;
355 	case CMD_MKDIR:
356 	    do_mkdir(argcount, argvec);
357 	    break;
358 	case CMD_RMDIR:
359 	    do_rmdir(argcount, argvec);
360 	    break;
361 	case CMD_CHMOD:
362 	    do_chmod(argcount, argvec);
363 	    break;
364 	case CMD_CHOWN:
365 	    do_chown(argcount, argvec);
366 	    break;
367 	case CMD_PUT:
368 	    do_put(argcount, argvec);
369 	    break;
370 	case CMD_HANDLE:
371 	    do_handle(argcount, argvec);
372 	    break;
373 	case CMD_MKNOD:
374 	    do_mknod(argcount, argvec);
375 	    break;
376 	case CMD_MOUNT:
377 	    do_mount(argcount, argvec);
378 	    break;
379 	case CMD_UMOUNT:
380 	    do_umount(argcount, argvec);
381 	    break;
382 	case CMD_UMOUNTALL:
383 	    do_umountall(argcount, argvec);
384 	    break;
385 	case CMD_EXPORT:
386 	    do_export(argcount, argvec);
387 	    break;
388 	case CMD_DUMP:
389 	    do_dump(argcount, argvec);
390 	    break;
391 	case CMD_STATUS:
392 	    do_status(argcount, argvec);
393 	    break;
394 	case CMD_HELP:
395 	    do_help(argcount, argvec);
396 	    break;
397 	case CMD_UNKNOWN:
398 	    if (buffer[0] == '!') {
399 		system(buffer + 1);
400 		printf("!\n");
401 	    } else
402 	        fprintf(stderr, "%s: unrecognized command\n", argvec[0]);
403 	    break;
404 	default:
405 	    fprintf(stderr, "internal error: '%s' not is case\n", argvec[0]);
406 	    break;
407 	}
408     }
409     if (remotehost) close_mount();
410     exit(0);
411 }
412 
413 void
interrupt(int signo)414 interrupt(int signo)
415 {
416     signal(SIGINT, (void (*)(int))interrupt);
417     longjmp(intenv, 1);
418 }
419 
420 /*
421  * Read a line from standard input and break
422  * it up into an argument vector.
423  */
424 int
ngetline(char * buf,int bufsize,int * argc,char ** argv,int argvsize)425 ngetline(char *buf, int bufsize, int *argc, char **argv, int argvsize)
426 {
427     register char *p;
428 
429 #ifdef READLINE
430     if (interact) {
431 	char *line;
432 	if ((line = readline("nfs> ")) == NULL)
433 	    return 0;
434 	strncpy(buf, line, bufsize);
435 	add_history(line);
436 	free(line);
437     } else {
438 	if (fgets(buf, bufsize, stdin) == NULL)
439 	    return 0;
440     }
441 #else
442     if (interact) printf("nfs> ");
443     if (fgets(buf, bufsize, stdin) == NULL)
444 	return 0;
445 #endif
446     *argc = 0;
447     for (p = buf; *p == ' ' || *p == '\t'; p++)
448 	/* skip white spaces */;
449     while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') {
450 	if (*argc > argvsize) break;
451 	argv[(*argc)++] = p;
452 	for (; *p != ' ' && *p != '\t' && *p != '\n' && *p != '\0'; p++)
453 	    /* skip word */;
454 	if (*p != '\0') *p++ ='\0';
455 	for (; *p == ' ' || *p == '\t'; p++)
456 	   /* skip white spaces */;
457     }
458     return 1;
459 }
460 
461 /*
462  * Search for command in keyword table
463  */
464 int
command(char * cmd)465 command(char *cmd)
466 {
467     register int i;
468 
469     for (i = 0; i < sizeof(keyword)/sizeof(struct keyword); i++)
470 	if (strcmp(keyword[i].kw_command, cmd) == 0)
471 	    return keyword[i].kw_value;
472     return CMD_UNKNOWN;
473 }
474 
475 /*
476  * Set remote host and initialize RPC channel
477  * to mount daemon.
478  */
479 void
do_host(int argc,char ** argv)480 do_host(int argc, char **argv)
481 {
482     if (argc != 2)
483 	fprintf(stderr, "Usage: host <host>\n");
484     else
485 	open_mount(argv[1]);
486 }
487 
488 /*
489  * Set user id (updating RPC authentication info)
490  */
491 void
do_setuid(int argc,char ** argv)492 do_setuid(int argc, char **argv)
493 {
494     if (argc > 3) {
495 	fprintf(stderr, "Usage: uid [<uid> [<secret-key>]]\n");
496 	return;
497     }
498 
499     if (argc <= 2) {
500 	authtype = AUTH_UNIX;
501 	uid = argc == 1 ? -2 : atoi(argv[1]);
502     } else if (argc == 3) {
503 	authtype = AUTH_DES;
504 	memcpy(secretkey, argv[2], HEXKEYBYTES);
505     }
506 
507     if (nfsclient) {
508 	if (nfsclient->cl_auth)
509 	    auth_destroy(nfsclient->cl_auth);
510 	nfsclient->cl_auth = create_authenticator();
511     }
512 }
513 
514 /*
515  * Set group id (updating RPC authentication info)
516  */
517 void
do_setgid(int argc,char ** argv)518 do_setgid(int argc, char **argv)
519 {
520     gid = argc == 2 ? atoi(argv[1]) : -2;
521     if (nfsclient) {
522 	if (nfsclient->cl_auth)
523 	    auth_destroy(nfsclient->cl_auth);
524 	nfsclient->cl_auth = create_authenticator();
525     }
526 }
527 
528 /*
529  * Change remote working directory
530  */
531 void
do_cd(int argc,char ** argv)532 do_cd(int argc, char **argv)
533 {
534     register char *p;
535     char *component;
536     LOOKUP3args args;
537     LOOKUP3res *res;
538     nfs_fh3 handle;
539 
540     if (mountpath == NULL) {
541 	fprintf(stderr, "cd: no remote file system mounted\n");
542 	return;
543     }
544 
545     /* easy case: cd to root */
546     if (argc == 1) {
547 	fhandle3_to_nfs_fh3(&directory_handle, &mountpoint->mountres3_u.mountinfo.fhandle);
548 	return;
549     }
550 
551     /* if a directory start with '/', we search from the root */
552     if (*(p = argv[1]) == '/') {
553 	fhandle3_to_nfs_fh3(&handle, &mountpoint->mountres3_u.mountinfo.fhandle);
554 	p++;
555     } else
556 	nfs_fh3copy(&handle, &directory_handle);
557 
558     /*
559      * Break path up into directory components and check every
560      * component for its validity.
561      */
562     for (;;) {
563 	if (*p == '\0') break;
564 	for (component = p; *p != '/' && *p != '\0'; p++)
565 	    /* do nothing */;
566 	*p++ = '\0';
567 	args.what.name = component;
568 	nfs_fh3copy(&args.what.dir, &handle);
569 	if ((res = nfs3_lookup_3(&args, nfsclient)) == NULL) {
570 	    clnt_perror(nfsclient, "nfs3_lookup");
571 	    return;
572 	}
573 	if (res->status != NFS3_OK) {
574 	    fprintf(stderr, "%s: %s\n", component, nfs_error(res->status));
575 	    return;
576 	}
577 	if (res->LOOKUP3res_u.resok.dir_attributes.post_op_attr_u.attributes.type != NF3DIR) {
578 	    fprintf(stderr, "%s: is not a directory\n", component);
579 	    return;
580 	}
581 	nfs_fh3copy(&handle, &res->LOOKUP3res_u.resok.object);
582     }
583     nfs_fh3copy(&directory_handle, &handle);
584 }
585 
586 /*
587  * Change local working directory
588  */
589 void
do_lcd(int argc,char ** argv)590 do_lcd(int argc, char **argv)
591 {
592     if (argc == 1) {
593 	char *home = getenv("HOME");
594 	if (home != NULL)
595 	    if (chdir(home) != 0) perror("lcd");
596     } else
597 	if (chdir(argv[1]) != 0) perror("lcd");
598 }
599 
600 /*
601  * Display a remote file
602  */
603 void
do_cat(int argc,char ** argv)604 do_cat(int argc, char **argv)
605 {
606     LOOKUP3args dargs;
607     LOOKUP3res *dres;
608     READ3args rargs;
609     READ3res *rres;
610     long offset;
611 
612     if (mountpath == NULL) {
613 	fprintf(stderr, "cat: no remote file system mounted\n");
614 	return;
615     }
616     if (argc != 2) {
617 	fprintf(stderr, "Usage: cat <filespec>\n");
618 	return;
619     }
620 
621     /* lookup name in current directory */
622     dargs.what.name = argv[1];
623     nfs_fh3copy(&dargs.what.dir, &directory_handle);
624     if ((dres = nfs3_lookup_3(&dargs, nfsclient)) == NULL) {
625 	clnt_perror(nfsclient, "nfs3_lookup");
626 	return;
627     }
628     if (dres->status != NFS3_OK) {
629 	fprintf(stderr, "%s: %s\n", argv[1], nfs_error(dres->status));
630 	return;
631     }
632     if (dres->LOOKUP3res_u.resok.dir_attributes.post_op_attr_u.attributes.type != NF3REG) {
633 	fprintf(stderr, "%s: is not a regular file\n", argv[1]);
634 	return;
635     }
636     nfs_fh3copy(&rargs.file, &dres->LOOKUP3res_u.resok.object);
637     for (offset = 0; offset < dres->LOOKUP3res_u.resok.dir_attributes.post_op_attr_u.attributes.size; ) {
638 	rargs.offset = offset;
639 	rargs.count = transfersize;
640 	if ((rres = nfs3_read_3(&rargs, nfsclient)) == NULL) {
641 	    clnt_perror(nfsclient, "nfs3_read_3");
642 	    break;
643         }
644 	if (rres->status != NFS3_OK) {
645 	    fprintf(stderr, "%s: %s\n", argv[1], nfs_error(rres->status));
646 	    break;
647 	}
648         fwrite(rres->READ3res_u.resok.data.data_val,
649             rres->READ3res_u.resok.data.data_len, 1, stdout);
650 	offset += transfersize;
651     }
652 }
653 
654 /*
655  * List remote directory
656  */
657 void
do_ls(int argc,char ** argv)658 do_ls(int argc, char **argv)
659 {
660     char **table, **ptr, **p;
661     int lflag = 0;
662 
663     argv++; argc--;
664     if (mountpath == NULL) {
665 	fprintf(stderr, "ls: no remote file system mounted\n");
666 	return;
667     }
668     if (argc >= 1 && strcmp(argv[0], "-l") == 0) {
669 	argv++; argc--;
670 	lflag = 1;
671     }
672 
673     if (!getdirentries(&directory_handle, &table, &ptr, 20))
674 	return;
675     for (p = table; p < ptr; p++) {
676 	if (!match(*p, argc, argv)) continue;
677 	if (lflag == 1)
678 	    printfilestatus(*p);
679 	else
680 	    printf("%s\n", *p);
681 	free(*p);
682     }
683     free(table);
684 }
685 
686 /*
687  * Print long listing of a files, much in the way ``ls -l'' does
688  */
689 void
printfilestatus(char * file)690 printfilestatus(char *file)
691 {
692     LOOKUP3args args;
693     LOOKUP3res *res;
694     int mode;
695 
696     args.what.name = file;
697     nfs_fh3copy(&args.what.dir, &directory_handle);
698 
699     if ((res = nfs3_lookup_3(&args, nfsclient)) == NULL) {
700 	clnt_perror(nfsclient, "nfs3_lookup");
701 	return;
702     }
703     if (res->status != NFS3_OK) {
704 	fprintf(stderr, "Lookup failed: %s\n", nfs_error(res->status));
705 	return;
706     }
707 
708     switch (res->LOOKUP3res_u.resok.dir_attributes.post_op_attr_u.attributes.type) {
709 	case NF3SOCK:
710 	    putchar('s');
711 	    break;
712 	case NF3FIFO:
713 	    putchar('p');
714 	    break;
715 	case NF3REG:
716 	    putchar('-');
717 	    break;
718 	case NF3DIR:
719 	    putchar('d');
720 	    break;
721 	case NF3BLK:
722 	    putchar('b');
723 	    break;
724 	case NF3CHR:
725 	    putchar('c');
726 	    break;
727 	case NF3LNK:
728 	    putchar('l');
729 	    break;
730 	default:
731 	    putchar('?');
732 	    break;
733     }
734     mode = res->LOOKUP3res_u.resok.dir_attributes.post_op_attr_u.attributes.mode;
735     if (mode & 0400) putchar('r'); else putchar('-');
736     if (mode & 0200) putchar('w'); else putchar('-');
737     if (mode & 0100)
738 	if (mode & 04000) putchar('s'); else putchar('x');
739     else
740 	if (mode & 04000) putchar('S'); else putchar('-');
741     if (mode & 040) putchar('r'); else putchar('-');
742     if (mode & 020) putchar('w'); else putchar('-');
743     if (mode & 010)
744 	if (mode & 02000) putchar('s'); else putchar('x');
745     else
746 	if (mode & 02000) putchar('S'); else putchar('-');
747     if (mode & 04) putchar('r'); else putchar('-');
748     if (mode & 02) putchar('w'); else putchar('-');
749     if (mode & 01)
750 	if (mode & 01000) putchar('t'); else putchar('x');
751     else
752 	if (mode & 01000) putchar('T'); else putchar('-');
753     printf("%3d%9d%6d%10ld ",
754 	res->LOOKUP3res_u.resok.dir_attributes.post_op_attr_u.attributes.nlink,
755 	res->LOOKUP3res_u.resok.dir_attributes.post_op_attr_u.attributes.uid,
756 	res->LOOKUP3res_u.resok.dir_attributes.post_op_attr_u.attributes.gid,
757 	res->LOOKUP3res_u.resok.dir_attributes.post_op_attr_u.attributes.size);
758     writefiledate(res->LOOKUP3res_u.resok.dir_attributes.post_op_attr_u.attributes.ctime.seconds);
759     printf(" %s", file);
760     if (res->LOOKUP3res_u.resok.dir_attributes.post_op_attr_u.attributes.type == NF3LNK) {
761 	READLINK3res *rlres;
762 	READLINK3args rlargs;
763 
764 	nfs_fh3copy(&rlargs.symlink, &res->LOOKUP3res_u.resok.object);
765 	if ((rlres = nfs3_readlink_3(&rlargs, nfsclient)) == NULL) {
766 	    clnt_perror(nfsclient, "nfs3_readlink");
767 	    return;
768 	}
769 	if (res->status != NFS3_OK) {
770 	    fprintf(stderr, "Lookup failed: %s\n", nfs_error(res->status));
771 	    return;
772 	}
773 	printf(" -> %s\n", rlres->READLINK3res_u.resok.data);
774     } else
775 	putchar('\n');
776 }
777 
778 int
writefiledate(time_t d)779 writefiledate(time_t d)
780 {
781     time_t now, sixmonthsago, onehourfromnow;
782     char *cp;
783 
784     (void) time(&now);
785     sixmonthsago = now - 6L*30L*24L*60L*60L;
786     onehourfromnow = now + 60L*60L;
787     cp = ctime(&d);
788     if ((d < sixmonthsago) || (d > onehourfromnow))
789 	return printf(" %-7.7s %-4.4s ", cp+4, cp+20);
790     else
791 	return printf(" %-12.12s ", cp+4);
792 }
793 
794 /*
795  * Get remote files
796  */
797 void
do_get(int argc,char ** argv)798 do_get(int argc, char **argv)
799 {
800     char **table, **ptr, **p;
801     char answer[512];
802     LOOKUP3args args;
803     LOOKUP3res *res;
804     READ3args rargs;
805     READ3res *rres;
806     int iflag = 0;
807     long offset;
808     FILE *fp;
809 
810     argv++; argc--;
811     if (mountpath == NULL) {
812 	fprintf(stderr, "get: no remote file system mounted\n");
813 	return;
814     }
815     if (argc >= 1 && strcmp(argv[0], "-i") == 0) {
816 	argv++; argc--;
817 	iflag = 1;
818     }
819 
820     if (!getdirentries(&directory_handle, &table, &ptr, 20))
821 	return;
822     for (p = table; p < ptr; p++) {
823 	/* match before going over the wire */
824 	if (!match(*p, argc, argv)) continue;
825 
826 	/* only regular files can be transfered */
827 	args.what.name = *p;
828 	nfs_fh3copy(&args.what.dir, &directory_handle);
829 	if ((res = nfs3_lookup_3(&args, nfsclient)) == NULL) {
830 	    clnt_perror(nfsclient, "nfs3_lookup");
831 	    return;
832 	}
833 	if (res->status != NFS3_OK) {
834 	    fprintf(stderr, "Lookup failed: %s\n", nfs_error(res->status));
835 	    return;
836 	}
837 	if (res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes.type != NF3REG)
838 	    continue;
839 
840 	/* ask for confirmation */
841 	printf("%s? ", *p);
842 	if (!iflag) {
843 	    if (fgets(answer, sizeof(answer), stdin) == NULL)
844 		continue;
845 	    if (answer[0] != 'y' && answer[0] != 'Y')
846 		continue;
847 	} else
848 	    printf("Yes\n");
849 
850 	/* get actual file */
851 	if ((fp = fopen(*p, "w")) == NULL) {
852 	    fprintf(stderr, "get: cannot create %s\n", *p);
853 	    continue;
854 	}
855 	nfs_fh3copy(&rargs.file, &res->LOOKUP3res_u.resok.object);
856 	for (offset = 0; offset < res->LOOKUP3res_u.resok.dir_attributes.post_op_attr_u.attributes.size; ) {
857 	    rargs.offset = offset;
858 	    rargs.count = transfersize;
859 	    if ((rres = nfs3_read_3(&rargs, nfsclient)) == NULL) {
860 		clnt_perror(nfsclient, "nfs3_read");
861 		break;
862             }
863 	    if (rres->status != NFS3_OK) {
864 		fprintf(stderr, "%s: %s\n", argv[1], nfs_error(rres->status));
865 		break;
866 	    }
867 	    fwrite(rres->READ3res_u.resok.data.data_val,
868 		rres->READ3res_u.resok.data.data_len, 1, fp);
869 	    offset += transfersize;
870 	}
871 	fclose(fp);
872 	free(*p);
873     }
874     free(table);
875 }
876 
877 /*
878  * Show file system information
879  */
880 /* ARGUSED */
881 void
do_df(int argc,char ** argv)882 do_df(int argc, char **argv)
883 {
884     FSSTAT3args args;
885     FSSTAT3res *res;
886 
887     if (mountpath == NULL) {
888 	fprintf(stderr, "df: no remote file system mounted\n");
889 	return;
890     }
891     if (argc != 1) {
892 	fprintf(stderr, "Usage: df\n");
893 	return;
894     }
895     fhandle3_to_nfs_fh3(&args.fsroot, &mountpoint->mountres3_u.mountinfo.fhandle);
896     if ((res = nfs3_fsstat_3(&args, nfsclient)) == NULL) {
897 	clnt_perror(nfsclient, "nfs3_fsstat");
898 	return;
899     }
900     if (res->status != NFS3_OK) {
901 	fprintf(stderr, "Df failed: %s\n", nfs_error(res->status));
902 	return;
903     }
904 
905 #define x res->FSSTAT3res_u.resok
906     printf("%s:%s    %ldK, %ldK used, %ldK free (%ldK useable).\n",
907 	remotehost, mountpath,
908 	x.tbytes/1024, (x.tbytes-x.fbytes)/1024,
909 	x.fbytes/1024, x.abytes/1024);
910 #undef x
911 }
912 
913 /*
914  * Delete a remote file
915  */
916 void
do_rm(int argc,char ** argv)917 do_rm(int argc, char **argv)
918 {
919     REMOVE3args args;
920     REMOVE3res *res;
921 
922     if (mountpath == NULL) {
923 	fprintf(stderr, "rm: no remote file system mounted\n");
924 	return;
925     }
926     if (argc != 2) {
927 	fprintf(stderr, "Usage: rm <file>\n");
928 	return;
929     }
930     args.object.name = argv[1];
931     nfs_fh3copy(&args.object.dir, &directory_handle);
932     if ((res = nfs3_remove_3(&args, nfsclient)) == NULL) {
933 	clnt_perror(nfsclient, "nfs3_remove");
934 	return;
935     }
936     if (res->status != NFS3_OK) {
937 	fprintf(stderr, "Remove failed: %s\n", nfs_error(res->status));
938 	return;
939     }
940 }
941 
942 /*
943  * Link a file
944  */
945 void
do_ln(int argc,char ** argv)946 do_ln(int argc, char **argv)
947 {
948     LOOKUP3args dargs;
949     LOOKUP3res *dres;
950     LINK3args largs;
951     LINK3res *lres;
952 
953     if (mountpath == NULL) {
954 	fprintf(stderr, "ln: no remote file system mounted\n");
955 	return;
956     }
957     if (argc != 3) {
958 	fprintf(stderr, "Usage: ln <file1> <file2>\n");
959 	return;
960     }
961 
962     dargs.what.name = argv[1];
963     nfs_fh3copy(&dargs.what.dir, &directory_handle);
964     if ((dres = nfs3_lookup_3(&dargs, nfsclient)) == NULL) {
965 	clnt_perror(nfsclient, "nfs3_lookup");
966 	return;
967     }
968     if (dres->status != NFS3_OK) {
969 	fprintf(stderr, "%s: %s\n", argv[1], nfs_error(dres->status));
970 	return;
971     }
972 
973     nfs_fh3copy(&largs.file, &dres->LOOKUP3res_u.resok.object);
974     largs.link.name = argv[2];
975     nfs_fh3copy(&largs.link.dir, &directory_handle);
976 
977     if ((lres = nfs3_link_3(&largs, nfsclient)) == NULL) {
978 	clnt_perror(nfsclient, "nfs3_link");
979 	return;
980     }
981     if (lres->status != NFS3_OK) {
982 	fprintf(stderr, "Link failed: %s\n", nfs_error(lres->status));
983 	return;
984     }
985 }
986 
987 /*
988  * Move a file or directory
989  */
990 void
do_mv(int argc,char ** argv)991 do_mv(int argc, char **argv)
992 {
993     RENAME3args args;
994     RENAME3res *res;
995 
996     if (mountpath == NULL) {
997 	fprintf(stderr, "mv: no remote file system mounted\n");
998 	return;
999     }
1000     if (argc != 3) {
1001 	fprintf(stderr, "Usage: mv <file1> <file2>\n");
1002 	return;
1003     }
1004     args.from.name = argv[1];
1005     nfs_fh3copy(&args.from.dir, &directory_handle);
1006     args.to.name = argv[2];
1007     nfs_fh3copy(&args.to.dir, &directory_handle);
1008     if ((res = nfs3_rename_3(&args, nfsclient)) == NULL) {
1009 	clnt_perror(nfsclient, "nfs3_rename");
1010 	return;
1011     }
1012     if (res->status != NFS3_OK) {
1013 	fprintf(stderr, "Rename failed: %s\n", nfs_error(res->status));
1014 	return;
1015     }
1016 }
1017 
1018 /*
1019  * Make remote directory
1020  */
1021 void
do_mkdir(int argc,char ** argv)1022 do_mkdir(int argc, char **argv)
1023 {
1024     MKDIR3args args;
1025     MKDIR3res *res;
1026 
1027     if (mountpath == NULL) {
1028 	fprintf(stderr, "mkdir: no remote file system mounted\n");
1029 	return;
1030     }
1031     if (argc != 2) {
1032 	fprintf(stderr, "Usage: mkdir <directory>\n");
1033 	return;
1034     }
1035 
1036     args.where.name = argv[1];
1037     nfs_fh3copy(&args.where.dir, &directory_handle);
1038     args.attributes.mode  = (set_mode3) { .set_it=TRUE, .set_mode3_u.mode=040755 };
1039     args.attributes.uid   = (set_uid3)  { .set_it=TRUE, .set_uid3_u.uid=uid };
1040     args.attributes.gid   = (set_gid3)  { .set_it=TRUE, .set_gid3_u.gid=gid };
1041     args.attributes.size  = (set_size3) { .set_it=FALSE };
1042     args.attributes.atime = (set_atime) { .set_it=FALSE };
1043     args.attributes.mtime = (set_mtime) { .set_it=FALSE };
1044 
1045     if ((res = nfs3_mkdir_3(&args, nfsclient)) == NULL) {
1046 	clnt_perror(nfsclient, "nfs3_mkdir");
1047 	return;
1048     }
1049     if (res->status != NFS3_OK) {
1050 	fprintf(stderr, "Make directory failed: %s\n", nfs_error(res->status));
1051 	return;
1052     }
1053 }
1054 
1055 /* XXX */
1056 void
do_create(int argc,char ** argv)1057 do_create(int argc, char **argv)
1058 {
1059     CREATE3args args;
1060     CREATE3res *res;
1061 
1062     if (mountpath == NULL) {
1063 	fprintf(stderr, "mkdir: no remote file system mounted\n");
1064 	return;
1065     }
1066     if (argc != 2) {
1067 	fprintf(stderr, "Usage: mkdir <directory>\n");
1068 	return;
1069     }
1070 
1071     args.where.name = argv[1];
1072     nfs_fh3copy(&args.where.dir, &directory_handle);
1073     args.how.mode = EXCLUSIVE;
1074     args.how.createhow3_u.obj_attributes.mode  = (set_mode3) { .set_it=TRUE, .set_mode3_u.mode=040755 };
1075     args.how.createhow3_u.obj_attributes.uid   = (set_uid3)  { .set_it=TRUE, .set_uid3_u.uid=uid };
1076     args.how.createhow3_u.obj_attributes.gid   = (set_gid3)  { .set_it=TRUE, .set_gid3_u.gid=gid };
1077     args.how.createhow3_u.obj_attributes.size  = (set_size3) { .set_it=FALSE };
1078     args.how.createhow3_u.obj_attributes.atime = (set_atime) { .set_it=FALSE };
1079     args.how.createhow3_u.obj_attributes.mtime = (set_mtime) { .set_it=FALSE };
1080 
1081     if ((res = nfs3_create_3(&args, nfsclient)) == NULL) {
1082 	clnt_perror(nfsclient, "nfs3_mkdir");
1083 	return;
1084     }
1085     if (res->status != NFS3_OK) {
1086 	fprintf(stderr, "Make directory failed: %s\n", nfs_error(res->status));
1087 	return;
1088     }
1089 }
1090 
1091 /*
1092  * Remove remote directory
1093  */
1094 void
do_rmdir(int argc,char ** argv)1095 do_rmdir(int argc, char **argv)
1096 {
1097     RMDIR3args args;
1098     RMDIR3res *res;
1099 
1100     if (mountpath == NULL) {
1101 	fprintf(stderr, "rmdir: no remote file system mounted\n");
1102 	return;
1103     }
1104     if (argc != 2) {
1105 	fprintf(stderr, "Usage: rmdir <directory>\n");
1106 	return;
1107     }
1108 
1109     args.object.name = argv[1];
1110     nfs_fh3copy(&args.object.dir, &directory_handle);
1111     if ((res = nfs3_rmdir_3(&args, nfsclient)) == NULL) {
1112 	clnt_perror(nfsclient, "nfs3_rmdir");
1113 	return;
1114     }
1115     if (res->status != NFS3_OK) {
1116 	fprintf(stderr, "Remove directory failed: %s\n", nfs_error(res->status));
1117 	return;
1118     }
1119 }
1120 
1121 /*
1122  * Change mode of remote file or directory
1123  */
1124 void
do_chmod(int argc,char ** argv)1125 do_chmod(int argc, char **argv)
1126 {
1127     LOOKUP3args dargs;
1128     LOOKUP3res *dres;
1129     SETATTR3args aargs;
1130     SETATTR3res *ares;
1131     int mode;
1132 
1133     if (mountpath == NULL) {
1134 	fprintf(stderr, "chmod: no remote file system mounted\n");
1135 	return;
1136     }
1137     if (argc != 3) {
1138 	fprintf(stderr, "Usage: chmod <mode> <file>\n");
1139 	return;
1140     }
1141     if (sscanf(argv[1], "%o", &mode) != 1) {
1142 	fprintf(stderr, "chmod: invalid mode\n");
1143 	return;
1144     }
1145 
1146     dargs.what.name = argv[2];
1147     nfs_fh3copy(&dargs.what.dir, &directory_handle);
1148     if ((dres = nfs3_lookup_3(&dargs, nfsclient)) == NULL) {
1149 	clnt_perror(nfsclient, "nfs3_lookup");
1150 	return;
1151     }
1152     if (dres->status != NFS3_OK) {
1153 	fprintf(stderr, "%s: %s\n", argv[2], nfs_error(dres->status));
1154 	return;
1155     }
1156 
1157     nfs_fh3copy(&aargs.object, &dres->LOOKUP3res_u.resok.object);
1158     aargs.new_attributes.mode  = (set_mode3) { .set_it=TRUE, .set_mode3_u.mode=mode };
1159     aargs.new_attributes.uid   = (set_uid3)  { .set_it=FALSE };
1160     aargs.new_attributes.gid   = (set_gid3)  { .set_it=FALSE };
1161     aargs.new_attributes.size  = (set_size3) { .set_it=FALSE };
1162     aargs.new_attributes.atime = (set_atime) { .set_it=FALSE };
1163     aargs.new_attributes.mtime = (set_mtime) { .set_it=FALSE };
1164 
1165     if ((ares = nfs3_setattr_3(&aargs, nfsclient)) == NULL) {
1166 	clnt_perror(nfsclient, "nfs3_setattr");
1167 	return;
1168     }
1169     if (ares->status != NFS3_OK) {
1170 	fprintf(stderr, "Set attributes failed: %s\n", nfs_error(ares->status));
1171 	return;
1172     }
1173 }
1174 
1175 /*
1176  * Make new device node
1177  */
1178 void
do_mknod(int argc,char ** argv)1179 do_mknod(int argc, char **argv)
1180 {
1181     int mode, maj, min, device;
1182     CREATE3args cargs;
1183     CREATE3res *cres;
1184 
1185     if (mountpath == NULL) {
1186 	fprintf(stderr, "mknod: no remote file system mounted\n");
1187 	return;
1188     }
1189     if ((argc != 3 && argc != 5) || argv[2][1] != '\0')  {
1190 usage:	fprintf(stderr, "Usage: mknod <name> [b/c major minor] [p]\n");
1191 	return;
1192     }
1193     if (argc == 3) {
1194 	if (argv[2][0] != 'p')
1195 	    goto usage;
1196 	mode = IFCHR;
1197 	device = NF3FIFO;
1198     } else if (argc == 5) {
1199 	switch (argv[2][0]) {
1200 	case 'b':
1201 	    mode = IFBLK;
1202 	    break;
1203 	case 'c':
1204 	    mode = IFCHR;
1205 	    break;
1206 	}
1207 	maj = atoi(argv[3]);
1208 	min = atoi(argv[4]);
1209 	device = makedev(maj, min);
1210     }
1211 
1212     /*
1213      * Make remote device node
1214      */
1215     cargs.where.name = argv[1];
1216     nfs_fh3copy(&cargs.where.dir, &directory_handle);
1217     cargs.how.createhow3_u.obj_attributes.mode  = (set_mode3) { .set_it=TRUE, .set_mode3_u.mode=mode | 0777};
1218     cargs.how.createhow3_u.obj_attributes.uid   = (set_uid3)  { .set_it=TRUE, .set_uid3_u = uid };
1219     cargs.how.createhow3_u.obj_attributes.gid   = (set_gid3)  { .set_it=TRUE, .set_gid3_u = gid };
1220     cargs.how.createhow3_u.obj_attributes.size  = (set_size3) { .set_it=TRUE, .set_size3_u = device };
1221     cargs.how.createhow3_u.obj_attributes.atime = (set_atime) { .set_it=FALSE };
1222     cargs.how.createhow3_u.obj_attributes.mtime = (set_mtime) { .set_it=FALSE };
1223     if ((cres = nfs3_create_3(&cargs, nfsclient)) == NULL) {
1224 	clnt_perror(nfsclient, "nfs3_create");
1225 	return;
1226     }
1227     if (cres->status != NFS3_OK)
1228 	fprintf(stderr, "WARNING: Mknod failed: %s\n", nfs_error(cres->status));
1229 }
1230 
1231 /*
1232  * Change owner (and group) of remote file or directory
1233  */
1234 void
do_chown(int argc,char ** argv)1235 do_chown(int argc, char **argv)
1236 {
1237     LOOKUP3args dargs;
1238     LOOKUP3res *dres;
1239     SETATTR3args aargs;
1240     SETATTR3res *ares;
1241     int own_uid, own_gid;
1242 
1243     if (mountpath == NULL) {
1244 	fprintf(stderr, "chown: no remote file system mounted\n");
1245 	return;
1246     }
1247     if (argc != 3) {
1248 	fprintf(stderr, "Usage: chown <uid>[.<gid>] <file>\n");
1249 	return;
1250     }
1251     if (sscanf(argv[1], "%d.%d", &own_uid, &own_gid) != 2) {
1252 	own_gid = -1;
1253 	if (sscanf(argv[1], "%d", &own_uid) != 1) {
1254 	    fprintf(stderr, "chown: invalid uid[.gid]\n");
1255 	    return;
1256 	}
1257     }
1258 
1259     dargs.what.name = argv[2];
1260     nfs_fh3copy(&dargs.what.dir, &directory_handle);
1261     if ((dres = nfs3_lookup_3(&dargs, nfsclient)) == NULL) {
1262 	clnt_perror(nfsclient, "nfs3_lookup");
1263 	return;
1264     }
1265     if (dres->status != NFS3_OK) {
1266 	fprintf(stderr, "%s: %s\n", argv[2], nfs_error(dres->status));
1267 	return;
1268     }
1269 
1270     nfs_fh3copy(&aargs.object, &dres->LOOKUP3res_u.resok.object);
1271     aargs.new_attributes.mode  = (set_mode3) { .set_it=FALSE };
1272     aargs.new_attributes.uid   = (set_uid3)  { .set_it=TRUE, .set_uid3_u.uid = own_uid };
1273     aargs.new_attributes.gid   = (set_gid3)  { .set_it=TRUE, .set_gid3_u.gid = own_gid };
1274     aargs.new_attributes.size  = (set_size3) { .set_it=FALSE };
1275     aargs.new_attributes.atime = (set_atime) { .set_it=FALSE };
1276     aargs.new_attributes.mtime = (set_mtime) { .set_it=FALSE };
1277 
1278     if ((ares = nfs3_setattr_3(&aargs, nfsclient)) == NULL) {
1279 	clnt_perror(nfsclient, "nfs3_setattr");
1280 	return;
1281     }
1282     if (ares->status != NFS3_OK) {
1283 	fprintf(stderr, "Set attributes failed: %s\n", nfs_error(ares->status));
1284 	return;
1285     }
1286 }
1287 
1288 /*
1289  * Put file from local to remote
1290  */
1291 void
do_put(int argc,char ** argv)1292 do_put(int argc, char **argv)
1293 {
1294     LOOKUP3args dargs;
1295     LOOKUP3res *dres;
1296     CREATE3args cargs;
1297     CREATE3res *cres;
1298     char buf[BUFSIZ];
1299     nfs_fh3 handle;
1300     FILE *fp;
1301     int n;
1302     long offset;
1303 
1304     if (mountpath == NULL) {
1305 	fprintf(stderr, "put: no remote file system mounted\n");
1306 	return;
1307     }
1308     if (argc != 2 && argc != 3) {
1309 	fprintf(stderr, "Usage: put <local-file> [<remote-file>]\n");
1310 	return;
1311     }
1312 
1313     if ((fp = fopen(argv[1], "r")) == NULL) {
1314 	fprintf(stderr, "put: cannot open %s\n", argv[1]);
1315 	return;
1316     }
1317 
1318     /*
1319      * Create remote file name
1320      */
1321     cargs.where.name = argc == 3 ? argv[2] : argv[1];
1322     nfs_fh3copy(&cargs.where.dir, &directory_handle);
1323     cargs.how.mode = EXCLUSIVE;
1324     cargs.how.createhow3_u.obj_attributes.mode  = (set_mode3) { .set_it=TRUE, .set_mode3_u.mode= 0666 };
1325     cargs.how.createhow3_u.obj_attributes.uid   = (set_uid3)  { .set_it=TRUE, .set_uid3_u.uid=uid };
1326     cargs.how.createhow3_u.obj_attributes.gid   = (set_gid3)  { .set_it=TRUE, .set_gid3_u.gid=gid };
1327     cargs.how.createhow3_u.obj_attributes.size  = (set_size3) { .set_it=FALSE };
1328     cargs.how.createhow3_u.obj_attributes.atime = (set_atime) { .set_it=FALSE };
1329     cargs.how.createhow3_u.obj_attributes.mtime = (set_mtime) { .set_it=FALSE };
1330 
1331     if ((cres = nfs3_create_3(&cargs, nfsclient)) == NULL) {
1332 	clnt_perror(nfsclient, "nfs3_create");
1333 	fclose(fp);
1334 	return;
1335     }
1336     if (cres->status != NFS3_OK)
1337 	fprintf(stderr, "WARNING: Create failed: %s\n", nfs_error(cres->status));
1338 
1339     /*
1340      * Look up remote file name, to get its handle
1341      */
1342     dargs.what.name = argc == 3 ? argv[2] : argv[1];
1343     nfs_fh3copy(&dargs.what.dir, &directory_handle);
1344     if ((dres = nfs3_lookup_3(&dargs, nfsclient)) == NULL) {
1345 	clnt_perror(nfsclient, "nfs3_lookup");
1346 	fclose(fp);
1347 	return;
1348     }
1349     if (dres->status != NFS3_OK) {
1350 	fprintf(stderr, "%s: %s\n", argv[1], nfs_error(dres->status));
1351 	fclose(fp);
1352 	return;
1353     }
1354     nfs_fh3copy(&handle, &dres->LOOKUP3res_u.resok.object);
1355 
1356     for (offset = 0; (n = fread(buf, 1, sizeof(buf), fp)) > 0; offset += n) {
1357 	WRITE3args wargs;
1358 	WRITE3res *wres;
1359 
1360 	nfs_fh3copy(&wargs.file, &handle);
1361 	wargs.offset = offset;
1362 	wargs.count = n;
1363 	wargs.data.data_len = n;
1364 	wargs.data.data_val = buf;
1365 	if ((wres = nfs3_write_3(&wargs, nfsclient)) == NULL) {
1366 	    clnt_perror(nfsclient, "nfs3_write");
1367 	    fclose(fp);
1368 	    return;
1369 	}
1370 	if (wres->status != NFS3_OK) {
1371 	    fprintf(stderr, "Write failed: %s\n", nfs_error(wres->status));
1372 	    fclose(fp);
1373 	    return;
1374 	}
1375     }
1376     fclose(fp);
1377 }
1378 
1379 /*
1380  * Get/set file handle
1381  */
1382 void
do_handle(int argc,char ** argv)1383 do_handle(int argc, char **argv)
1384 {
1385     int sock, port, flags;
1386     register char *p;
1387     register int i;
1388 
1389     port = 0;
1390     flags = 0;
1391     argv++; argc--;
1392     while (argc > 0 && argv[0][0] == '-') {
1393 	for (p = argv[0]+1; *p; p++) {
1394 	    switch (*p) {
1395 	    case 'P':
1396 		if (argc <= 1)
1397 		   goto usage;
1398 		argv++; argc--;
1399 		port = atoi(*argv);
1400 		break;
1401 	    case 'T':
1402 		flags |= NFS_OVER_TCP;
1403 		break;
1404 	    case 'U':
1405 		flags |= NFS_OVER_UDP;
1406 		break;
1407 	    default:
1408 		goto usage;
1409 	    }
1410 	}
1411 	argv++; argc--;
1412     }
1413     if (argc <= 1) {
1414 	if (mountpath == NULL) {
1415 	    fprintf(stderr, "handle: no remote file system mounted\n");
1416 	    return;
1417 	}
1418 	printf("%s:", mountpath);
1419 	for (i = 0, p = (char *)&directory_handle; i < sizeof(nfs_fh3); i++)
1420 	    printf(" %02x", *p++ & 0xFF);
1421 	printf("\n");
1422 	return;
1423     }
1424 
1425     if (argc != sizeof(nfs_fh3)) {
1426 usage:
1427 	fprintf(stderr, "Usage: handle [-TU] <file handle>\n");
1428 	return;
1429     }
1430 
1431     if (remotehost == NULL) {
1432 	fprintf(stderr, "handle: no host specified\n");
1433 	return;
1434     }
1435 
1436     /* copy handle from command line argument */
1437     for (i = 0, p = (char *)&directory_handle; i < sizeof(nfs_fh3); i++)
1438 	*p++ = (char) strtol(argv[i], NULL, 16);
1439 
1440     open_nfs(NULL, port, flags);
1441 }
1442 
1443 /*
1444  * Set up a channel to the NFS server and
1445  * mount remote file system.
1446  */
1447 void
do_mount(int argc,char ** argv)1448 do_mount(int argc, char **argv)
1449 {
1450     int port, flags;
1451     char *p, *path;
1452 
1453     port = 0;
1454     flags = 0;
1455     argv++; argc--;
1456     while (argc > 0 && argv[0][0] == '-') {
1457 	for (p = argv[0]+1; *p; p++) {
1458 	    switch (*p) {
1459 	    case 'u':
1460 		flags |= MOUNT_UMOUNT;
1461 		break;
1462 	    case 'p':
1463 		flags |= THRU_PORTMAP;
1464 		break;
1465 	    case 'P':
1466 		if (argc <= 1)
1467 		   goto usage;
1468 		argv++; argc--;
1469 		port = atoi(*argv);
1470 		break;
1471 	    case 'T':
1472 		flags |= NFS_OVER_TCP;
1473 		break;
1474 	    case 'U':
1475 		flags |= NFS_OVER_UDP;
1476 		break;
1477 	    default:
1478 		goto usage;
1479 	    }
1480 	}
1481 	argv++; argc--;
1482     }
1483     if (argc != 1) {
1484 usage:
1485 	fprintf(stderr, "Usage: mount [-upTU] [-P port] <path>\n");
1486 	return;
1487     }
1488     path = argv[0];
1489     if (remotehost == NULL) {
1490 	fprintf(stderr, "mount: no host specified\n");
1491 	return;
1492     }
1493     open_nfs(path, port, flags);
1494 }
1495 
1496 /*
1497  * Unmount remote file system, and close
1498  * RPC channel.
1499  */
1500 /* ARGUSED */
1501 void
do_umount(int argc,char ** argv)1502 do_umount(int argc, char **argv)
1503 {
1504     if (argc != 1) {
1505 	fprintf(stderr, "Usage: umount\n");
1506 	return;
1507     }
1508     if (mountpath == NULL)
1509 	fprintf(stderr, "umount: no remote file system mounted\n");
1510     else
1511 	close_nfs();
1512 }
1513 
1514 /*
1515  * Unmount all remote file system from this host
1516  */
1517 /* ARGUSED */
1518 void
do_umountall(int argc,char ** argv)1519 do_umountall(int argc, char **argv)
1520 {
1521     if (argc != 1) {
1522 	fprintf(stderr, "Usage: umountall\n");
1523 	return;
1524     }
1525     if (remotehost == NULL) {
1526 	fprintf(stderr, "umountall: no host specified\n");
1527 	return;
1528     }
1529     if (mountpath != NULL) close_nfs();
1530     (void) mount3_umntall_3(NULL, mntclient);
1531 }
1532 
1533 /*
1534  * Display all exported file systems on remote system
1535  */
1536 /* ARGUSED */
1537 void
do_export(int argc,char ** argv)1538 do_export(int argc, char **argv)
1539 {
1540     exports ex, *exp;
1541     groups gr;
1542     int hostsonly = 0;
1543 
1544     argv++; argc--;
1545     if (argc >= 1 && strcmp(argv[0], "-h") == 0) {
1546 	argv++; argc--;
1547 	hostsonly = 1;
1548     }
1549     if (argc != 0) {
1550 	fprintf(stderr, "Usage: export [-h] \n");
1551 	return;
1552     }
1553     if (remotehost == NULL) {
1554 	fprintf(stderr, "export: no host specified\n");
1555 	return;
1556     }
1557     if ((exp = mount3_export_3(NULL, mntclient)) == NULL) {
1558 	clnt_perror(mntclient, "mountproc_export");
1559 	return;
1560     }
1561     printf("Export list for %s:\n", remotehost);
1562     for (ex = *exp; ex != NULL; ex = ex->ex_next) {
1563 	printf("%-25s", ex->ex_dir);
1564 	if (hostsonly == 0) {
1565 	    if ((int)strlen(ex->ex_dir) >= 25)
1566 		printf("\n                    ");
1567 	    if ((gr = ex->ex_groups) == NULL)
1568 		printf("everyone");
1569 	    while (gr) {
1570 		printf("%s ", gr->gr_name);
1571 		gr = gr->gr_next;
1572 	    }
1573 	}
1574 	putchar('\n');
1575     }
1576 }
1577 
1578 /*
1579  * Display all remote mounted file systems
1580  */
1581 /* ARGUSED */
1582 void
do_dump(int argc,char ** argv)1583 do_dump(int argc, char **argv)
1584 {
1585     mountlist ml, *mlp;
1586 
1587     if (argc != 1) {
1588 	fprintf(stderr, "Usage: dump\n");
1589 	return;
1590     }
1591     if (remotehost == NULL) {
1592 	fprintf(stderr, "dump: no host specified\n");
1593 	return;
1594     }
1595     if ((mlp = mount3_dump_3(NULL, mntclient)) == NULL) {
1596 	clnt_perror(mntclient, "mountproc_dump");
1597 	return;
1598     }
1599     for (ml = *mlp; ml != NULL; ml = ml->ml_next)
1600 	printf("%s:%s\n", ml->ml_hostname, ml->ml_directory);
1601 }
1602 
1603 /*
1604  * Generic status report
1605  */
1606 /* ARGUSED */
1607 void
do_status(int argc,char ** argv)1608 do_status(int argc, char **argv)
1609 {
1610     if (argc != 1) {
1611 	fprintf(stderr, "Usage: status\n");
1612 	return;
1613     }
1614     printf("User id      : %d\n", uid);
1615     printf("Group id     : %d\n", gid);
1616     if (remotehost)
1617 	printf("Remote host  : `%s'\n", remotehost);
1618     if (mountpath)
1619 	printf("Mount path   : `%s'\n", mountpath);
1620     printf("Transfer size: %d\n", transfersize);
1621 }
1622 
1623 /*
1624  * Simple on-line help facility
1625  */
1626 /* ARGUSED */
1627 void
do_help(int argc,char ** argv)1628 do_help(int argc, char **argv)
1629 {
1630     register int i;
1631 
1632     for (i = 0; i < sizeof(keyword)/sizeof(struct keyword); i++) {
1633 	if (argc == 2 && strcmp(keyword[i].kw_command, argv[1]) != 0)
1634 	    continue;
1635 	printf("%s %s\n", keyword[i].kw_command, keyword[i].kw_help);
1636     }
1637 }
1638 
1639 /*
1640  * Open a channel to remote Mount daemon, possibly closing an
1641  * already open connection. There are four possibilities here.
1642  * Either the channel has a privileged port number or not, and
1643  * it is a TCP stream or an UDP stream.
1644  */
1645 int
open_mount(char * host)1646 open_mount(char *host)
1647 {
1648     char *tmp, *src = 0;
1649     int proto, sock;
1650 
1651     tmp = strrchr(host,':');
1652     if (tmp) {
1653 	src = host;
1654 	host = tmp+1;
1655     } else if ((tmp = strchr(host,'@'))) {
1656 	src = host;
1657 	host = tmp+1;
1658     }
1659     /* close previous mounted host */
1660     if (remotehost != NULL)
1661 	close_mount();
1662 
1663     /* convert hostname to IP address */
1664     if (isdigit(*host)) {
1665         server_addr.sin_addr.s_addr = inet_addr(host);
1666     } else {
1667         struct hostent *hp = gethostbyname(host);
1668         if (hp == NULL) {
1669             fprintf(stderr, "%s: unknown host\n", host);
1670 	    return 0;
1671         }
1672         memcpy(&server_addr.sin_addr.s_addr, hp->h_addr, hp->h_length);
1673         host = (char *) hp->h_name;
1674     }
1675     server_addr.sin_family = AF_INET;
1676     server_addr.sin_port = 0;
1677 
1678     /* set host name */
1679     if ((remotehost = strdup(host)) == NULL) {
1680 	fprintf(stderr, "internal error: no more core for host\n");
1681 	return 0;
1682     }
1683 
1684     /* setup communication channel with mount daemon */
1685     proto = IPPROTO_TCP;
1686     mntserver_addr = server_addr;
1687     if (src)
1688 	sock = sourceroute(src, &mntserver_addr, MOUNT_PROGRAM, MOUNT_V3);
1689     else
1690 	sock = setup(SOCK_STREAM, &mntserver_addr, MOUNT_PROGRAM, MOUNT_V3);
1691 
1692     if ((mntclient = clnttcp_create(&mntserver_addr,
1693       MOUNT_PROGRAM, MOUNT_V3, &sock, 0, 0)) == (CLIENT *)0) {
1694 	clnt_pcreateerror("mount/tcp");
1695 	if (sock != RPC_ANYSOCK)
1696 	    close(sock);
1697 	proto = IPPROTO_UDP;
1698 	sock = setup(SOCK_DGRAM, &mntserver_addr, MOUNT_PROGRAM, MOUNT_V3);
1699 	if ((mntclient = clntudp_create(&mntserver_addr,
1700 	  MOUNT_PROGRAM, MOUNT_V3, timeout, &sock)) == (CLIENT *)0) {
1701 	    clnt_pcreateerror("mount");
1702 	    if (sock != RPC_ANYSOCK)
1703 		close(sock);
1704 	    return 0;
1705 	}
1706     }
1707     clnt_control(mntclient, CLSET_TIMEOUT, (char *)&timeout);
1708     clnt_control(mntclient, CLSET_FD_CLOSE, (char *)NULL);
1709     mntclient->cl_auth = create_authenticator();
1710     if (verbose) {
1711 	printf("Open %s (%s) %s\n",
1712 	    remotehost, inet_ntoa(server_addr.sin_addr),
1713 	    proto == IPPROTO_TCP ? "TCP" : "UDP");
1714     }
1715     return 1;
1716 }
1717 
1718 /*
1719  * Close channel to mount daemon,
1720  * possibly umounting a NFS file system.
1721  */
1722 void
close_mount(void)1723 close_mount(void)
1724 {
1725     if (mountpath) close_nfs();
1726     if (verbose) printf("Close `%s'\n", remotehost);
1727     free(remotehost);
1728     remotehost = NULL;
1729     if (mntclient) {
1730 	auth_destroy(mntclient->cl_auth);
1731 	clnt_destroy(mntclient);
1732     }
1733 }
1734 
1735 struct in_addr
convert_name(char * host)1736 convert_name(char *host)
1737 {
1738     struct in_addr ret;
1739 
1740     ret.s_addr = ~0;
1741     /* convert hostname to IP address */
1742     if (isdigit(*host)) {
1743         ret.s_addr = inet_addr(host);
1744     } else {
1745         struct hostent *hp = gethostbyname(host);
1746         if (hp == NULL) {
1747             fprintf(stderr, "%s: unknown host\n", host);
1748 	    return ret;
1749         }
1750         memcpy(&ret.s_addr, hp->h_addr, hp->h_length);
1751     }
1752     return ret;
1753 }
1754 
1755 /*
1756  * Set the source route attributes for a socket.
1757  * Source route attributes have the following form:
1758  *
1759  * [<localaddr>]@[<host>:...]<dest>
1760  */
1761 int
sourceroute(char * src,struct sockaddr_in * svr,int prog,int vers)1762 sourceroute(char *src, struct sockaddr_in *svr, int prog, int vers)
1763 {
1764     char *ind = strchr(src,'@');
1765     char ipopts[32];
1766     char *opts = ipopts+3;
1767     int sock;
1768 
1769     memset(ipopts, 0, sizeof(ipopts));
1770 
1771     if (ind == src) {
1772 	sock = privileged(SOCK_STREAM, NULL);
1773     } else {
1774 	/* convert address and bind */
1775 	struct sockaddr_in sin;
1776 
1777 	*ind = '\0';
1778 	memset(&sin, 0, sizeof(sin));
1779 	sin.sin_family = AF_INET;
1780 	sin.sin_addr = convert_name(src);
1781 
1782 	sock = privileged(SOCK_STREAM, &sin);
1783 	if (sock == RPC_ANYSOCK) {
1784 	    sin.sin_port = 0;
1785 	    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1786 	    if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) != 0) {
1787 		fprintf(stderr,"Couldn't bind to src %s\n", src);
1788 		close(sock);
1789 		return RPC_ANYSOCK;
1790 	    }
1791 	} else if (verbose)
1792 	    printf("Bound to %s\n", src);
1793     }
1794     if (ind == 0)
1795 	return 0;
1796     src = ++ind;
1797 
1798     ipopts[0] = (char) IPOPT_LSRR;
1799     ipopts[2] = (char) IPOPT_MINOFF;
1800     while (src && *src) {
1801 	struct in_addr addr;
1802 	ind = strchr(src, ':');
1803 	if (ind)
1804 	    *ind++ = '\0';
1805 	addr = convert_name(src);
1806 	if (verbose)
1807 	    printf("Routed through %s\n", inet_ntoa(addr));
1808 	memcpy(opts, &addr.s_addr, 4); opts += 4;
1809 	src = ind;
1810     }
1811     ipopts[IPOPT_OLEN] = opts - ipopts;
1812     while ((opts - ipopts) & 3)
1813 	opts++;
1814     if (setsockopt(sock, IPPROTO_IP,IP_OPTIONS, ipopts, opts - ipopts) == -1) {
1815 	perror("setsockopt");
1816 	return RPC_ANYSOCK;
1817     }
1818 
1819     svr->sin_port = pmap_getport(svr, prog, vers, IPPROTO_TCP);
1820     svr->sin_port = htons(svr->sin_port);
1821     if (connect(sock, (struct sockaddr *) svr, sizeof(*svr)) != 0) {
1822 	perror("connect");
1823 	return RPC_ANYSOCK;
1824     }
1825     return sock;
1826 }
1827 
1828 /*
1829  * Mount an NFS file system, perhaps closing a previous mounted
1830  * one. The umount option fools the accounting system. The portmap
1831  * option allows mounts via the portmapper and transport allows
1832  * you to choose the transport type (TCP or UDP).
1833  */
1834 int
open_nfs(char * path,int port,int flags)1835 open_nfs(char *path, int port, int flags)
1836 {
1837     int proto, sock;
1838 
1839     /* umount previous mounted remote file system */
1840     if (mountpath != NULL)
1841 	close_nfs();
1842 
1843     /* set up an connection with the NFS server */
1844     switch (flags & TRANSPORT_MASK) {
1845     case NFS_OVER_UDP:
1846 	/* try using NFS over UDP (standard Sun setup) */
1847 	proto = IPPROTO_UDP;
1848 	nfsserver_addr = server_addr;
1849 	nfsserver_addr.sin_port = ntohs(port);
1850 	sock = setup(SOCK_DGRAM, &mntserver_addr, NFS_PROGRAM, NFS_V3);
1851 	if ((nfsclient = clntudp_create(&nfsserver_addr,
1852 	  NFS_PROGRAM, NFS_V3, timeout, &sock)) == (CLIENT *)0) {
1853 	    clnt_pcreateerror("nfs clntudp_create");
1854 	    if (sock != RPC_ANYSOCK)
1855 		close(sock);
1856 	    return 0;
1857 	}
1858 	break;
1859     case NFS_OVER_TCP:
1860 	/* try using NFS over TCP (standard Sun setup) */
1861 	proto = IPPROTO_TCP;
1862 	nfsserver_addr = server_addr;
1863 	nfsserver_addr.sin_port = ntohs(port);
1864 	sock = setup(SOCK_STREAM, &mntserver_addr, NFS_PROGRAM, NFS_V3);
1865 	if ((nfsclient = clnttcp_create(&nfsserver_addr,
1866 	  NFS_PROGRAM, NFS_V3, &sock, 0, 0)) == (CLIENT *)0) {
1867 	    clnt_pcreateerror("nfs clnttcp_create");
1868 	    if (sock != RPC_ANYSOCK)
1869 		close(sock);
1870 	    return 0;
1871 	}
1872 	break;
1873     default:
1874 	/* try using NFS over TCP, if that fails try UDP */
1875 	proto = IPPROTO_TCP;
1876 	nfsserver_addr = server_addr;
1877 	nfsserver_addr.sin_port = ntohs(port);
1878 	sock = setup(SOCK_STREAM, &mntserver_addr, NFS_PROGRAM, NFS_V3);
1879 	if ((nfsclient = clnttcp_create(&nfsserver_addr,
1880 	  NFS_PROGRAM, NFS_V3, &sock, 0, 0)) == (CLIENT *)0) {
1881 	    proto = IPPROTO_UDP;
1882 	    nfsserver_addr = server_addr;
1883 	    nfsserver_addr.sin_port = ntohs(port);
1884 	    if (sock != RPC_ANYSOCK)
1885 		close(sock);
1886 	    sock = setup(SOCK_DGRAM, &mntserver_addr, NFS_PROGRAM, NFS_V3);
1887 	    if ((nfsclient = clntudp_create(&nfsserver_addr,
1888 	      NFS_PROGRAM, NFS_V3, timeout, &sock)) == (CLIENT *)0) {
1889 		clnt_pcreateerror("nfs clntudp_create");
1890 		if (sock != RPC_ANYSOCK)
1891 		    close(sock);
1892 		return 0;
1893 	    }
1894 	}
1895     }
1896     clnt_control(nfsclient, CLSET_TIMEOUT, (char *)&timeout);
1897     clnt_control(mntclient, CLSET_FD_CLOSE, (char *)NULL);
1898     nfsclient->cl_auth = create_authenticator();
1899 
1900     /*
1901      * When no path is given we assume the caller
1902      * set the directory file handle.
1903      */
1904     if (path != NULL) {
1905 	/*
1906 	 * Get file handle for this path from the mount daemon. There
1907 	 * are two ways to get it, either ask it directly or get it
1908 	 * through the port mapper.
1909 	 */
1910 	if (flags & THRU_PORTMAP) {
1911 	    if ((mountpoint = pmap_mnt(&path, &mntserver_addr)) == NULL)
1912 		return 0;
1913 	} else if ((mountpoint = mount3_mnt_3(&path, mntclient)) == NULL) {
1914 	    clnt_perror(mntclient, "mount3_mnt");
1915 	    return 0;
1916 	}
1917 	if (mountpoint->fhs_status != MNT3_OK) {
1918             fprintf(stderr, "Mount failed: %s\n",
1919 		mount_error(mountpoint->fhs_status));
1920 	    return 0;
1921 	}
1922 	fhandle3_to_nfs_fh3(&directory_handle, &mountpoint->mountres3_u.mountinfo.fhandle);
1923 
1924 	/* we got the file handle, unmount if don't want to get noticed */
1925 	if (flags & MOUNT_UMOUNT)
1926 	    (void) mount3_umnt_3(&path, mntclient);
1927 
1928 	/* set mount path */
1929 	if ((mountpath = strdup(path)) == NULL) {
1930 	    fprintf(stderr, "internal error: no more core for mountpath\n");
1931 	    return 0;
1932 	}
1933     } else if ((mountpath = strdup("<handle>")) == NULL) {
1934 	fprintf(stderr, "internal error: no more core for mountpath\n");
1935 	return 0;
1936     }
1937 
1938     /* get transfer size */
1939     transfersize = determine_transfersize();
1940 
1941     if (verbose) {
1942 	printf("Mount `%s'", mountpath);
1943 	if (flags & MOUNT_UMOUNT)
1944 	    printf(" (unmount)");
1945 	if (proto == IPPROTO_TCP)
1946 	    printf(", TCP, ");
1947 	else
1948 	    printf(", UDP, ");
1949 	if (port != 0)
1950 	    printf("port %d, ", port);
1951 	printf("transfer size %d bytes.\n", transfersize);
1952     }
1953     return 1;
1954 }
1955 
1956 /*
1957  * Make a mount call via the port mapper
1958  */
1959 mountres3 *
pmap_mnt(dirpath * argp,struct sockaddr_in * server_addr)1960 pmap_mnt(dirpath *argp, struct sockaddr_in *server_addr)
1961 {
1962     enum clnt_stat stat;
1963     static mountres3 res;
1964     u_long port;
1965 
1966     memset(&res, 0, sizeof(res));
1967     if ((stat = pmap_rmtcall(server_addr, MOUNT_PROGRAM, MOUNT_V3,
1968       MOUNT3_MNT, (xdrproc_t)xdr_dirpath, (caddr_t) argp,
1969       (xdrproc_t) xdr_mountres3, (caddr_t)&res, timeout, &port)) != RPC_SUCCESS){
1970 	clnt_perrno(stat);
1971 	return NULL;
1972     }
1973     return &res;
1974 
1975 /*
1976        enum clnt_stat pmap_rmtcall(struct sockaddr_in *addr,
1977                            unsigned long prognum, unsigned long versnum,
1978                            unsigned long procnum,
1979                            xdrproc_t inproc, char *in,
1980                            xdrproc_t outproc, char *out,
1981                            struct timeval tout, unsigned long *portp);
1982 */
1983 
1984 }
1985 
1986 /*
1987 void
1988 copy_nfs_fh3(nfs_fh3 dst, nfs_fh3 src)
1989 {
1990 
1991 }
1992 */
1993 
1994 /*
1995  * Determine NFS server's transfer size
1996  */
1997 int
determine_transfersize(void)1998 determine_transfersize(void)
1999 {
2000     FSINFO3args args = { 0 };
2001     FSINFO3res *res;
2002 
2003     nfs_fh3copy(&args.fsroot, &directory_handle);
2004     if ((res = nfs3_fsinfo_3(&args, nfsclient)) == NULL)
2005 	return 8192;
2006     if (res->status != NFS3_OK)
2007 	return 8192;
2008     return res->FSINFO3res_u.resok.wtmax;
2009 }
2010 
2011 /*
2012  * Setup a connection to host "svr", program "prog" and version "vers"
2013  * using a privileged port.
2014  */
2015 int
setup(int type,struct sockaddr_in * svr,int prog,int vers)2016 setup(int type, struct sockaddr_in *svr, int prog, int vers)
2017 {
2018     int s = privileged(type, NULL);
2019 
2020     if (s != RPC_ANYSOCK) {
2021 	svr->sin_port = pmap_getport(svr, prog, vers,
2022 	    type == SOCK_STREAM ? IPPROTO_TCP: IPPROTO_UDP);
2023 	svr->sin_port = htons(svr->sin_port);
2024 	if (connect(s, (struct sockaddr *) svr, sizeof(*svr)) != 0) {
2025 	    perror("connect");
2026 	    return RPC_ANYSOCK;
2027 	}
2028     }
2029     return s;
2030 }
2031 
2032 /*
2033  * Acquire a privileged port when possible
2034  */
2035 int
privileged(int type,struct sockaddr_in * sinp)2036 privileged(int type, struct sockaddr_in *sinp)
2037 {
2038     int s, lport = IPPORT_RESERVED - 1;
2039     struct sockaddr_in sin;
2040 
2041     if (sinp == (struct sockaddr_in *)0) {
2042 	sinp = &sin;
2043 	memset(&sin, 0, sizeof(sin));
2044 	sin.sin_family = AF_INET;
2045 	sin.sin_addr.s_addr = INADDR_ANY;
2046     }
2047     /* fix to make privileged work for TCP, make sure you connect yourself */
2048     s = socket(AF_INET, type, type == SOCK_STREAM ? IPPROTO_TCP: IPPROTO_UDP);
2049     if (s < 0)
2050 	return RPC_ANYSOCK;
2051     for (;;) {
2052 	sinp->sin_port = htons((u_short)lport);
2053 	if (bind(s, (struct sockaddr *)sinp, sizeof(*sinp)) >= 0) {
2054 	    if (verbose)
2055 		fprintf(stderr, "Using a privileged port (%d)\n", lport);
2056 	    return s;
2057 	}
2058 	if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
2059 	    close(s);
2060 	    return RPC_ANYSOCK;
2061 	}
2062 	lport--;
2063 	if (lport == IPPORT_RESERVED/2) {
2064 	    fprintf(stderr, "privileged socket: All ports in use\n");
2065 	    close(s);
2066 	    return RPC_ANYSOCK;
2067 	}
2068     }
2069 }
2070 
2071 /*
2072  * Close an NFS mounted file system
2073  */
2074 void
close_nfs(void)2075 close_nfs(void)
2076 {
2077     if (mountpath == NULL) return;
2078     if (verbose) printf("Unmount `%s'\n", mountpath);
2079     (void) mount3_umnt_3(&mountpath, mntclient);
2080     free(mountpath);
2081     mountpath = NULL;
2082     if (nfsclient) {
2083 	auth_destroy(nfsclient->cl_auth);
2084 	clnt_destroy(nfsclient);
2085     }
2086 }
2087 
2088 /*
2089  * Returns an auth handle with parameters determined by doing lots of
2090  * syscalls.
2091  */
2092 AUTH *
create_authenticator(void)2093 create_authenticator(void)
2094 {
2095     char machname[MAX_MACHINE_NAME + 1];
2096     gid_t gids[1];
2097 
2098     if (authtype == AUTH_UNIX) {
2099 	if (gethostname(machname, MAX_MACHINE_NAME) == -1) {
2100 	    fprintf(stderr, "create_authenticator: cannot get hostname\n");
2101 	    exit(1);
2102 	}
2103 	machname[MAX_MACHINE_NAME] = 0;
2104 	gids[0] = gid;
2105 	return authunix_create(machname, uid, gid, 1, gids);
2106     } else {
2107 	fprintf(stderr, "create_authenticator: no secure nfs support\n");
2108 	exit(1);
2109     }
2110 }
2111 
2112 /*
2113  * Read all entries (names) in directory 'dirhandle' into
2114  * a dynamically build table. It is up to the caller to free
2115  * this table.
2116  */
2117 int
getdirentries(nfs_fh3 * dirhandle,char *** table,char *** ptr,int nentries)2118 getdirentries(nfs_fh3 *dirhandle, char ***table, char ***ptr, int nentries)
2119 {
2120     READDIR3args args;
2121     READDIR3res *res;
2122     entry3 *ep;
2123     int dircmp();
2124     char **last;
2125 
2126     *ptr = *table = (char **) calloc(nentries, sizeof(char *));
2127     last = *ptr + nentries;
2128     if (*ptr == NULL) {
2129 	fprintf(stderr, "getdirentries: out of memory\n");
2130 	return 0;
2131     }
2132 
2133     nfs_fh3copy(&args.dir, dirhandle);
2134 
2135     memset(&args.cookie, 0, sizeof(args.cookie));
2136     args.count = 8192;
2137     for (;;) {
2138         if ((res = nfs3_readdir_3(&args, nfsclient)) == NULL) {
2139             clnt_perror(nfsclient, "nfs3_readdir");
2140             break;
2141         }
2142         if (res->status != NFS3_OK) {
2143             fprintf(stderr, "Readdir failed: %s\n", nfs_error(res->status));
2144             break;
2145         }
2146 
2147         ep = res->READDIR3res_u.resok.reply.entries;
2148         while (ep != NULL) {
2149 	    if (*ptr == last) {
2150 		*table = (char **)realloc(*table, 2*nentries*sizeof(char *));
2151 		if (*table == NULL) {
2152 		    fprintf(stderr, "getdirentries: out of memory\n");
2153 		    exit(1);
2154 		}
2155 		*ptr = *table + nentries;
2156 		last = *ptr + nentries;
2157 		nentries *= 2;
2158 	    }
2159 	    if ((*(*ptr)++ = strdup(ep->name)) == NULL)
2160 		return 0;
2161 
2162             if (ep->nextentry == NULL)
2163                 break;
2164             ep = ep->nextentry;
2165         }
2166         if (res->READDIR3res_u.resok.reply.eof)
2167             break;
2168         memcpy(&args.cookie, &ep->cookie, sizeof(args.cookie));
2169     }
2170     qsort(*table, *ptr - *table, sizeof(char **), dircmp);
2171     return 1;
2172 }
2173 
2174 int
dircmp(char ** p,char ** q)2175 dircmp(char **p, char **q)
2176 {
2177     return strcmp(*p, *q);
2178 }
2179 
2180 /*
2181  * Match string against a normal shell pattern (*?[])
2182  */
2183 int
match(char * s,int argc,char ** argv)2184 match(char *s, int argc, char **argv)
2185 {
2186     register int i;
2187 
2188     if (argc == 0) return 1;
2189     for (i = 0; i < argc; i++)
2190 	if (matchpattern(s, argv[i]))
2191 	    return 1;
2192     return 0;
2193 }
2194 
2195 int
matchpattern(char * s,char * p)2196 matchpattern(char *s, char *p)
2197 {
2198     if (*s == '.' && *p != '.')
2199 	return 0;
2200     return amatchpattern(s, p);
2201 }
2202 
2203 int
amatchpattern(char * s,char * p)2204 amatchpattern(char *s, char *p)
2205 {
2206     register int scc;
2207     int c, cc, ok, lc;
2208 
2209     if ((scc = *s++))
2210 	if ((scc &= 0177) == 0)
2211 	    scc = 0200;
2212 
2213     switch (c = *p++) {
2214     case '[':
2215 	ok = 0;
2216 	lc = 077777;
2217 	while ((cc = *p++)) {
2218 	    if (cc == ']') {
2219 		if (ok)
2220 		    return amatchpattern(s, p);
2221 		else
2222 		    return 0;
2223 	    } else if (cc == '-') {
2224 		if (lc <= scc && scc <= (c = *p++))
2225 		    ok++;
2226 	    } else
2227 		if (scc == (lc = cc))
2228 		    ok++;
2229 	}
2230 	return 0;
2231     case '*':
2232 	return umatchpattern(--s, p);
2233     case '\0':
2234 	return !scc;
2235     default:
2236 	if (c != scc)
2237 	    return 0;
2238     case '?':
2239 	if (scc)
2240 	    return amatchpattern(s, p);
2241 	return 0;
2242     }
2243 }
2244 
2245 int
umatchpattern(char * s,char * p)2246 umatchpattern(char *s, char *p)
2247 {
2248     if (*p == '\0')
2249 	return 1;
2250     while (*s != '\0')
2251 	if (amatchpattern(s++, p))
2252 	    return 1;
2253     return 0;
2254 }
2255 
2256 /*
2257  * MOUNT errors
2258  */
2259 char *
mount_error(enum mountstat3 stat)2260 mount_error(enum mountstat3 stat)
2261 {
2262     switch (stat) {
2263     case MNT3_OK:
2264 	return "No error";
2265     case MNT3ERR_PERM:
2266 	return "Not owner";
2267     case MNT3ERR_NOENT:
2268 	return "No such file or directory";
2269     case MNT3ERR_IO:
2270 	return "I/O error";
2271     case MNT3ERR_ACCES:
2272 	return "Permission denied";
2273     case MNT3ERR_NOTDIR:
2274 	return "Not a directory";
2275     case MNT3ERR_INVAL:
2276 	return "Invalid parameter";
2277     case MNT3ERR_NAMETOOLONG:
2278 	return "File name too long";
2279     case MNT3ERR_NOTSUPP:
2280 	return "Operation is not supported";
2281     case MNT3ERR_SERVERFAULT:
2282 	return "Other server error";
2283     default:
2284 	return "UKNOWN MOUNT ERROR";
2285     }
2286 }
2287 
2288 /*
2289  * NFS errors
2290  */
2291 char *
nfs_error(enum nfsstat3 stat)2292 nfs_error(enum nfsstat3 stat)
2293 {
2294     switch (stat) {
2295     case NFS3_OK:
2296 	return "No error";
2297     case NFS3ERR_PERM:
2298 	return "Not owner";
2299     case NFS3ERR_NOENT:
2300 	return "No such file or directory";
2301     case NFS3ERR_IO:
2302 	return "I/O error";
2303     case NFS3ERR_NXIO:
2304 	return "No such device or address";
2305     case NFS3ERR_ACCES:
2306 	return "Permission denied";
2307     case NFS3ERR_EXIST:
2308 	return "File exists";
2309     case NFS3ERR_NODEV:
2310 	return "No such device";
2311     case NFS3ERR_NOTDIR:
2312 	return "Not a directory";
2313     case NFS3ERR_ISDIR:
2314 	return "Is a directory";
2315     case NFS3ERR_FBIG:
2316 	return "File too large";
2317     case NFS3ERR_NOSPC:
2318 	return "No space left on device";
2319     case NFS3ERR_ROFS:
2320 	return "Read-only file system";
2321     case NFS3ERR_MLINK:
2322 	return "Too many hard links";
2323     case NFS3ERR_NAMETOOLONG:
2324 	return "File name too long";
2325     case NFS3ERR_NOTEMPTY:
2326 	return "Directory not empty";
2327     case NFS3ERR_DQUOT:
2328 	return "Disc quota exceeded";
2329     case NFS3ERR_STALE:
2330 	return "Stale NFS file handle";
2331     case NFS3ERR_REMOTE:
2332 	return "Too many levels of remote in path";
2333     case NFS3ERR_BADHANDLE:
2334 	return "Illegal NFS file handle";
2335     case NFS3ERR_NOT_SYNC:
2336 	return "Update synchronization mismatch";
2337     case NFS3ERR_BAD_COOKIE:
2338 	return "READDIR or READDIRPLUS cookie is stale";
2339     case NFS3ERR_NOTSUPP:
2340 	return "Operation is not supported";
2341     case NFS3ERR_TOOSMALL:
2342 	return "Buffer or request is too small";
2343     case NFS3ERR_SERVERFAULT:
2344 	return "Other server error";
2345     case NFS3ERR_BADTYPE:
2346 	return "Type not supported by server";
2347     case NFS3ERR_JUKEBOX:
2348 	return "Retrieval pending";
2349     default:
2350 	return "UKNOWN NFS ERROR";
2351     }
2352 }
2353