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