BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.sbin / amd / amd / host_ops.c
CommitLineData
e1a31032 1/*
e1a31032
KM
2 * Copyright (c) 1990 Jan-Simon Pendry
3 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4 * Copyright (c) 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Jan-Simon Pendry at Imperial College, London.
9 *
af359dea
C
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)host_ops.c 5.3 (Berkeley) 5/12/91
39 *
40 * $Id: host_ops.c,v 5.2.1.6 91/05/07 22:17:53 jsp Alpha $
e1a31032 41 *
e1a31032
KM
42 */
43
44#include "am.h"
45
46#ifdef HAS_HOST
47
48#include "mount.h"
49#include <sys/stat.h>
50
51/*
2664d859
JSP
52 * NFS host file system.
53 * Mounts all exported filesystems from a given host.
54 * This has now degenerated into a mess but will not
55 * be rewritten. Amd 6 will support the abstractions
56 * needed to make this work correctly.
e1a31032
KM
57 */
58
59/*
60 * Define HOST_RPC_UDP to use dgram instead of stream RPC.
61 * Datagrams are generally much faster.
62 */
63#define HOST_RPC_UDP
64
65/*
66 * Define HOST_MKDIRS to make Amd automatically try
67 * to create the mount points.
68 */
69#define HOST_MKDIRS
70
2664d859
JSP
71/*
72 * Determine the mount point
73 */
74#define MAKE_MNTPT(mntpt, ex, mf) { \
75 if (strcmp((ex)->ex_dir, "/") == 0) \
76 strcpy((mntpt), (mf)->mf_mount); \
77 else \
78 sprintf((mntpt), "%s%s", (mf)->mf_mount, (ex)->ex_dir); \
79}
80
e1a31032
KM
81/*
82 * Execute needs the same as NFS plus a helper command
83 */
2664d859
JSP
84static char *host_match P((am_opts *fo));
85static char *host_match(fo)
e1a31032
KM
86am_opts *fo;
87{
88#ifdef HOST_EXEC
89 if (!host_helper) {
90 plog(XLOG_USER, "No host helper command given");
91 return FALSE;
92 }
93#endif /* HOST_EXEC */
94
95 /*
96 * Make sure rfs is specified to keep nfs_match happy...
97 */
98 if (!fo->opt_rfs)
99 fo->opt_rfs = "/";
100
2664d859
JSP
101
102 return (*nfs_ops.fs_match)(fo);
e1a31032
KM
103}
104
105static int host_init(mf)
106mntfs *mf;
107{
108 if (strchr(mf->mf_info, ':') == 0)
109 return ENOENT;
110 return 0;
111}
112
113/*
114 * Two implementations:
115 * HOST_EXEC gets you the external version. The program specified with
116 * the -h option is called. The external program is not published...
117 * roll your own.
118 *
119 * Otherwise you get the native version. Faster but makes the program
120 * bigger.
121 */
122
123#ifndef HOST_EXEC
124
125static bool_t
126xdr_pri_free(xdr_args, args_ptr)
127xdrproc_t xdr_args;
128caddr_t args_ptr;
129{
130 XDR xdr;
131 xdr.x_op = XDR_FREE;
132 return ((*xdr_args)(&xdr, args_ptr));
133}
134
2664d859 135static int do_mount P((fhstatus *fhp, char *dir, char *fs_name, char *opts, mntfs *mf));
e1a31032
KM
136static int do_mount(fhp, dir, fs_name, opts, mf)
137fhstatus *fhp;
138char *dir;
139char *fs_name;
140char *opts;
141mntfs *mf;
142{
143 struct stat stb;
144#ifdef DEBUG
145 dlog("host: mounting fs %s on %s\n", fs_name, dir);
146#endif /* DEBUG */
147#ifdef HOST_MKDIRS
148 (void) mkdirs(dir, 0555);
149#endif /* HOST_MKDIRS */
150 if (stat(dir, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR) {
151 plog(XLOG_ERROR, "No mount point for %s - skipping", dir);
152 return ENOENT;
153 }
154
155 return mount_nfs_fh(fhp, dir, fs_name, opts, mf);
156}
157
2664d859
JSP
158static int sortfun P((exports *a, exports *b));
159static int sortfun(a, b)
e1a31032
KM
160exports *a,*b;
161{
162 return strcmp((*a)->ex_dir, (*b)->ex_dir);
163}
164
165/*
166 * Get filehandle
167 */
2664d859 168static int fetch_fhandle P((CLIENT *client, char *dir, fhstatus *fhp));
e1a31032
KM
169static int fetch_fhandle(client, dir, fhp)
170CLIENT *client;
171char *dir;
172fhstatus *fhp;
173{
174 struct timeval tv;
175 enum clnt_stat clnt_stat;
176
177 /*
178 * Pick a number, any number...
179 */
af359dea 180 tv.tv_sec = 20;
e1a31032
KM
181 tv.tv_usec = 0;
182
183#ifdef DEBUG
184 dlog("Fetching fhandle for %s", dir);
185#endif /* DEBUG */
186 /*
187 * Call the mount daemon on the remote host to
188 * get the filehandle.
189 */
190 clnt_stat = clnt_call(client, MOUNTPROC_MNT, xdr_dirpath, &dir, xdr_fhstatus, fhp, tv);
191 if (clnt_stat != RPC_SUCCESS) {
192 extern char *clnt_sperrno();
193 char *msg = clnt_sperrno(clnt_stat);
194 plog(XLOG_ERROR, "mountd rpc failed: %s", msg);
195 return EIO;
196 }
197 /*
198 * Check status of filehandle
199 */
200 if (fhp->fhs_status) {
201#ifdef DEBUG
202 errno = fhp->fhs_status;
203 dlog("fhandle fetch failed: %m");
204#endif /* DEBUG */
205 return fhp->fhs_status;
206 }
207 return 0;
208}
209
2664d859
JSP
210/*
211 * Scan mount table to see if something already mounted
212 */
213static int already_mounted P((mntlist *mlist, char*dir));
214static int already_mounted(mlist, dir)
215mntlist *mlist;
216char *dir;
217{
218 mntlist *ml;
219
220 for (ml = mlist; ml; ml = ml->mnext)
221 if (strcmp(ml->mnt->mnt_dir, dir) == 0)
222 return 1;
223 return 0;
224}
225
e1a31032
KM
226/*
227 * Mount the export tree from a host
228 */
2664d859
JSP
229static int host_fmount P((mntfs *mf));
230static int host_fmount(mf)
231mntfs *mf;
e1a31032
KM
232{
233 struct timeval tv2;
234 CLIENT *client;
235 enum clnt_stat clnt_stat;
236 int n_export;
2664d859 237 int j, k;
e1a31032
KM
238 exports exlist = 0, ex;
239 exports *ep = 0;
240 fhstatus *fp = 0;
e1a31032
KM
241 char *host = mf->mf_server->fs_host;
242 int error = 0;
243 struct sockaddr_in sin;
244 int sock = RPC_ANYSOCK;
245 int ok = FALSE;
2664d859
JSP
246 mntlist *mlist;
247 char fs_name[MAXPATHLEN], *rfs_dir;
248 char mntpt[MAXPATHLEN];
249
e1a31032
KM
250#ifdef HOST_RPC_UDP
251 struct timeval tv;
252 tv.tv_sec = 10; tv.tv_usec = 0;
253#endif /* HOST_RPC_UDP */
254
2664d859
JSP
255 /*
256 * Read the mount list
257 */
258 mlist = read_mtab(mf->mf_mount);
259
260 /*
261 * Unlock the mount list
262 */
263 unlock_mntlist();
264
e1a31032
KM
265 /*
266 * Take a copy of the server address
267 */
268 sin = *mf->mf_server->fs_ip;
269
270 /*
271 * Zero out the port - make sure we recompute
272 */
273 sin.sin_port = 0;
274 /*
275 * Make a client end-point
276 */
277#ifdef HOST_RPC_UDP
278 if ((client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS, tv, &sock)) == NULL)
279#else
280 if ((client = clnttcp_create(&sin, MOUNTPROG, MOUNTVERS, &sock, 0, 0)) == NULL)
281#endif /* HOST_RPC_UDP */
282 {
283 plog(XLOG_ERROR, "Failed to make rpc connection to mountd on %s", host);
284 error = EIO;
285 goto out;
286 }
287
288 if (!nfs_auth) {
af359dea
C
289 error = make_nfs_auth();
290 if (error)
e1a31032 291 goto out;
e1a31032
KM
292 }
293
294 client->cl_auth = nfs_auth;
295
296#ifdef DEBUG
297 dlog("Fetching export list from %s", host);
298#endif /* DEBUG */
299
300 /*
301 * Fetch the export list
302 */
303 tv2.tv_sec = 10; tv2.tv_usec = 0;
304 clnt_stat = clnt_call(client, MOUNTPROC_EXPORT, xdr_void, 0, xdr_exports, &exlist, tv2);
305 if (clnt_stat != RPC_SUCCESS) {
306 /*clnt_perror(client, "rpc");*/
307 error = EIO;
308 goto out;
309 }
310
311 /*
312 * Figure out how many exports were returned
313 */
314 for (n_export = 0, ex = exlist; ex; ex = ex->ex_next) {
315 /*printf("export %s\n", ex->ex_dir);*/
316 n_export++;
317 }
318#ifdef DEBUG
319 /*dlog("%d exports returned\n", n_export);*/
320#endif /* DEBUG */
321
322 /*
323 * Allocate an array of pointers into the list
2664d859
JSP
324 * so that they can be sorted. If the filesystem
325 * is already mounted then ignore it.
e1a31032
KM
326 */
327 ep = (exports *) xmalloc(n_export * sizeof(exports));
2664d859
JSP
328 for (j = 0, ex = exlist; ex; ex = ex->ex_next) {
329 MAKE_MNTPT(mntpt, ex, mf);
330 if (!already_mounted(mlist, mntpt))
331 ep[j++] = ex;
332 }
333 n_export = j;
e1a31032
KM
334
335 /*
336 * Sort into order.
337 * This way the mounts are done in order down the tree,
338 * instead of any random order returned by the mount
339 * daemon (the protocol doesn't specify...).
340 */
341 qsort(ep, n_export, sizeof(exports), sortfun);
342
343 /*
344 * Allocate an array of filehandles
345 */
346 fp = (fhstatus *) xmalloc(n_export * sizeof(fhstatus));
347
348 /*
349 * Try to obtain filehandles for each directory.
350 * If a fetch fails then just zero out the array
351 * reference but discard the error.
352 */
2664d859
JSP
353 for (j = k = 0; j < n_export; j++) {
354 /* Check and avoid a duplicated export entry */
355 if (j > k && ep[k] && strcmp(ep[j]->ex_dir, ep[k]->ex_dir) == 0) {
356#ifdef DEBUG
357 dlog("avoiding dup fhandle requested for %s", ep[j]->ex_dir);
358#endif
e1a31032 359 ep[j] = 0;
2664d859
JSP
360 } else {
361 k = j;
362 if (error = fetch_fhandle(client, ep[j]->ex_dir, &fp[j]))
363 ep[j] = 0;
364 }
e1a31032
KM
365 }
366
367 /*
368 * Mount each filesystem for which we have a filehandle.
369 * If any of the mounts succeed then mark "ok" and return
370 * error code 0 at the end. If they all fail then return
371 * the last error code.
372 */
2664d859
JSP
373 strncpy(fs_name, mf->mf_info, sizeof(fs_name));
374 if ((rfs_dir = strchr(fs_name, ':')) == (char *) 0) {
375 plog(XLOG_FATAL, "host_fmount: mf_info has no colon");
376 error = EINVAL;
377 goto out;
378 }
379 ++rfs_dir;
e1a31032
KM
380 for (j = 0; j < n_export; j++) {
381 ex = ep[j];
382 if (ex) {
2664d859
JSP
383 strcpy(rfs_dir, ex->ex_dir);
384 MAKE_MNTPT(mntpt, ex, mf);
385 if (do_mount(&fp[j], mntpt, fs_name, mf->mf_mopts, mf) == 0)
e1a31032
KM
386 ok = TRUE;
387 }
388 }
389
390 /*
391 * Clean up and exit
392 */
393out:
2664d859 394 discard_mntlist(mlist);
e1a31032
KM
395 if (ep)
396 free(ep);
397 if (fp)
398 free(fp);
399 if (client)
400 clnt_destroy(client);
401 if (exlist)
402 xdr_pri_free(xdr_exports, &exlist);
403 if (ok)
404 return 0;
405 return error;
406}
407
408/*
409 * Return true if pref is a directory prefix of dir.
410 *
411 * TODO:
412 * Does not work if pref is "/".
413 */
2664d859 414static int directory_prefix P((char *pref, char *dir));
e1a31032
KM
415static int directory_prefix(pref, dir)
416char *pref;
417char *dir;
418{
419 int len = strlen(pref);
420 if (strncmp(pref, dir, len) != 0)
421 return FALSE;
422 if (dir[len] == '/' || dir[len] == '\0')
423 return TRUE;
424 return FALSE;
425}
426
427/*
428 * Unmount a mount tree
429 */
2664d859
JSP
430static int host_fumount P((mntfs *mf));
431static int host_fumount(mf)
432mntfs *mf;
e1a31032 433{
e1a31032
KM
434 mntlist *ml, *mprev;
435 int xerror = 0;
436
437 /*
438 * Read the mount list
439 */
440 mntlist *mlist = read_mtab(mf->mf_mount);
441
442 /*
443 * Unlock the mount list
444 */
445 unlock_mntlist();
446
447 /*
448 * Reverse list...
449 */
450 ml = mlist;
451 mprev = 0;
452 while (ml) {
453 mntlist *ml2 = ml->mnext;
454 ml->mnext = mprev;
455 mprev = ml;
456 ml = ml2;
457 }
458 mlist = mprev;
459
460 /*
461 * Unmount all filesystems...
462 */
2664d859 463 for (ml = mlist; ml && !xerror; ml = ml->mnext) {
e1a31032
KM
464 char *dir = ml->mnt->mnt_dir;
465 if (directory_prefix(mf->mf_mount, dir)) {
466 int error;
467#ifdef DEBUG
468 dlog("host: unmounts %s", dir);
469#endif /* DEBUG */
470 /*
471 * Unmount "dir"
472 */
473 error = UMOUNT_FS(dir);
474 /*
475 * Keep track of errors
476 */
477 if (error) {
478 if (!xerror)
479 xerror = error;
480 if (error != EBUSY) {
481 errno = error;
482 plog("Tree unmount of %s failed: %m", ml->mnt->mnt_dir);
483 }
484 } else {
485#ifdef HOST_MKDIRS
486 (void) rmdirs(dir);
487#endif /* HOST_MKDIRS */
488 }
489 }
490 }
491
492 /*
493 * Throw away mount list
494 */
495 discard_mntlist(mlist);
496
2664d859
JSP
497 /*
498 * Try to remount, except when we are shutting down.
499 */
500 if (xerror && amd_state != Finishing) {
501 xerror = host_fmount(mf);
502 if (!xerror) {
af359dea
C
503 /*
504 * Don't log this - it's usually too verbose
2664d859 505 plog(XLOG_INFO, "Remounted host %s", mf->mf_info);
af359dea 506 */
2664d859
JSP
507 xerror = EBUSY;
508 }
509 }
e1a31032
KM
510 return xerror;
511}
512
513#else /* HOST_EXEC */
514
2664d859 515static int host_exec P((char*op, char*host, char*fs, char*opts));
e1a31032
KM
516static int host_exec(op, host, fs, opts)
517char *op;
518char *host;
519char *fs;
520char *opts;
521{
522 int error;
523 char *argv[7];
524
525 /*
526 * Build arg vector
527 */
528 argv[0] = host_helper;
529 argv[1] = host_helper;
530 argv[2] = op;
531 argv[3] = host;
532 argv[4] = fs;
533 argv[5] = opts && *opts ? opts : "rw,default";
534 argv[6] = 0;
535
536 /*
537 * Put stdout to stderr
538 */
539 (void) fclose(stdout);
540 (void) dup(fileno(logfp));
541 if (fileno(logfp) != fileno(stderr)) {
542 (void) fclose(stderr);
543 (void) dup(fileno(logfp));
544 }
545 /*
546 * Try the exec
547 */
548#ifdef DEBUG
549 Debug(D_FULL) {
550 char **cp = argv;
551 plog(XLOG_DEBUG, "executing (un)mount command...");
552 while (*cp) {
553 plog(XLOG_DEBUG, "arg[%d] = '%s'", cp-argv, *cp);
554 cp++;
555 }
556 }
557#endif /* DEBUG */
558 if (argv[0] == 0 || argv[1] == 0) {
559 errno = EINVAL;
560 plog(XLOG_USER, "1st/2nd args missing to (un)mount program");
561 } else {
562 (void) execv(argv[0], argv+1);
563 }
564 /*
565 * Save error number
566 */
567 error = errno;
568 plog(XLOG_ERROR, "exec %s failed: %m", argv[0]);
569
570 /*
571 * Return error
572 */
573 return error;
574}
575
2664d859 576static int host_mount P((am_node *mp));
e1a31032
KM
577static int host_mount(mp)
578am_node *mp;
579{
580 mntfs *mf = mp->am_mnt;
581
2664d859 582 return host_exec("mount", mf->mf_server->fs_host, mf->mf_mount, mf->mf_opts);
e1a31032
KM
583}
584
2664d859 585static int host_umount P((am_node *mp));
e1a31032
KM
586static int host_umount(mp)
587am_node *mp;
588{
589 mntfs *mf = mp->am_mnt;
590
591 return host_exec("unmount", mf->mf_server->fs_host, mf->mf_mount, "xxx");
592}
593
594#endif /* HOST_EXEC */
595
596/*
597 * Ops structure
598 */
599am_ops host_ops = {
600 "host",
601 host_match,
602 host_init,
2664d859
JSP
603 auto_fmount,
604 host_fmount,
605 auto_fumount,
606 host_fumount,
e1a31032
KM
607 efs_lookuppn,
608 efs_readdir,
609 0, /* host_readlink */
610 0, /* host_mounted */
611 0, /* host_umounted */
612 find_nfs_srvr,
613 FS_MKMNT|FS_BACKGROUND|FS_AMQINFO
614};
615
616#endif /* HAS_HOST */