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