]> git.proxmox.com Git - mirror_zfs.git/blame - lib/libshare/nfs.c
Disable 'zfs remap' command
[mirror_zfs.git] / lib / libshare / nfs.c
CommitLineData
46e18b3f
GB
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2011 Gunnar Beutner
27ccd414 25 * Copyright (c) 2012 Cyril Plisko. All rights reserved.
46e18b3f
GB
26 */
27
28#include <stdio.h>
93ce2b4c 29#include <string.h>
46e18b3f
GB
30#include <strings.h>
31#include <fcntl.h>
93ce2b4c 32#include <errno.h>
46e18b3f
GB
33#include <sys/wait.h>
34#include <unistd.h>
35#include <libzfs.h>
36#include <libshare.h>
37#include "libshare_impl.h"
38
27ccd414
CP
39static boolean_t nfs_available(void);
40
46e18b3f 41static sa_fstype_t *nfs_fstype;
46e18b3f 42
5333eb0b
J
43/*
44 * nfs_exportfs_temp_fd refers to a temporary copy of the output
45 * from exportfs -v.
46 */
47static int nfs_exportfs_temp_fd = -1;
48
46e18b3f
GB
49typedef int (*nfs_shareopt_callback_t)(const char *opt, const char *value,
50 void *cookie);
51
52typedef int (*nfs_host_callback_t)(const char *sharepath, const char *host,
53 const char *security, const char *access, void *cookie);
54
d1d7e268 55/*
590338f6
GB
56 * Invokes the specified callback function for each Solaris share option
57 * listed in the specified string.
58 */
46e18b3f
GB
59static int
60foreach_nfs_shareopt(const char *shareopts,
61 nfs_shareopt_callback_t callback, void *cookie)
62{
63 char *shareopts_dup, *opt, *cur, *value;
64 int was_nul, rc;
65
66 if (shareopts == NULL)
d1d7e268 67 return (SA_OK);
46e18b3f
GB
68
69 shareopts_dup = strdup(shareopts);
70
71 if (shareopts_dup == NULL)
d1d7e268 72 return (SA_NO_MEMORY);
46e18b3f
GB
73
74 opt = shareopts_dup;
75 was_nul = 0;
76
77 while (1) {
78 cur = opt;
79
80 while (*cur != ',' && *cur != '\0')
81 cur++;
82
83 if (*cur == '\0')
84 was_nul = 1;
85
86 *cur = '\0';
87
88 if (cur > opt) {
89 value = strchr(opt, '=');
90
91 if (value != NULL) {
92 *value = '\0';
93 value++;
94 }
95
96 rc = callback(opt, value, cookie);
97
98 if (rc != SA_OK) {
99 free(shareopts_dup);
d1d7e268 100 return (rc);
46e18b3f
GB
101 }
102 }
103
104 opt = cur + 1;
105
106 if (was_nul)
107 break;
108 }
109
110 free(shareopts_dup);
111
d1d7e268 112 return (0);
46e18b3f
GB
113}
114
115typedef struct nfs_host_cookie_s {
116 nfs_host_callback_t callback;
117 const char *sharepath;
118 void *cookie;
119 const char *security;
120} nfs_host_cookie_t;
121
d1d7e268 122/*
590338f6
GB
123 * Helper function for foreach_nfs_host. This function checks whether the
124 * current share option is a host specification and invokes a callback
125 * function with information about the host.
126 */
46e18b3f
GB
127static int
128foreach_nfs_host_cb(const char *opt, const char *value, void *pcookie)
129{
130 int rc;
131 const char *access;
132 char *host_dup, *host, *next;
133 nfs_host_cookie_t *udata = (nfs_host_cookie_t *)pcookie;
134
135#ifdef DEBUG
136 fprintf(stderr, "foreach_nfs_host_cb: key=%s, value=%s\n", opt, value);
137#endif
138
139 if (strcmp(opt, "sec") == 0)
140 udata->security = value;
141
142 if (strcmp(opt, "rw") == 0 || strcmp(opt, "ro") == 0) {
143 if (value == NULL)
144 value = "*";
145
146 access = opt;
147
148 host_dup = strdup(value);
149
150 if (host_dup == NULL)
d1d7e268 151 return (SA_NO_MEMORY);
46e18b3f
GB
152
153 host = host_dup;
154
155 do {
156 next = strchr(host, ':');
157 if (next != NULL) {
158 *next = '\0';
159 next++;
160 }
161
162 rc = udata->callback(udata->sharepath, host,
163 udata->security, access, udata->cookie);
164
165 if (rc != SA_OK) {
166 free(host_dup);
167
d1d7e268 168 return (rc);
46e18b3f
GB
169 }
170
171 host = next;
172 } while (host != NULL);
173
174 free(host_dup);
175 }
176
d1d7e268 177 return (SA_OK);
46e18b3f
GB
178}
179
d1d7e268 180/*
590338f6
GB
181 * Invokes a callback function for all NFS hosts that are set for a share.
182 */
46e18b3f
GB
183static int
184foreach_nfs_host(sa_share_impl_t impl_share, nfs_host_callback_t callback,
185 void *cookie)
186{
187 nfs_host_cookie_t udata;
188 char *shareopts;
189
190 udata.callback = callback;
191 udata.sharepath = impl_share->sharepath;
192 udata.cookie = cookie;
193 udata.security = "sys";
194
195 shareopts = FSINFO(impl_share, nfs_fstype)->shareopts;
196
197 return foreach_nfs_shareopt(shareopts, foreach_nfs_host_cb,
198 &udata);
199}
200
d1d7e268 201/*
590338f6
GB
202 * Converts a Solaris NFS host specification to its Linux equivalent.
203 */
46e18b3f
GB
204static int
205get_linux_hostspec(const char *solaris_hostspec, char **plinux_hostspec)
206{
207 /*
208 * For now we just support CIDR masks (e.g. @192.168.0.0/16) and host
209 * wildcards (e.g. *.example.org).
210 */
211 if (solaris_hostspec[0] == '@') {
212 /*
213 * Solaris host specifier, e.g. @192.168.0.0/16; we just need
214 * to skip the @ in this case
215 */
216 *plinux_hostspec = strdup(solaris_hostspec + 1);
217 } else {
218 *plinux_hostspec = strdup(solaris_hostspec);
219 }
220
221 if (*plinux_hostspec == NULL) {
d1d7e268 222 return (SA_NO_MEMORY);
46e18b3f
GB
223 }
224
d1d7e268 225 return (SA_OK);
46e18b3f
GB
226}
227
d1d7e268 228/*
590338f6
GB
229 * Used internally by nfs_enable_share to enable sharing for a single host.
230 */
46e18b3f
GB
231static int
232nfs_enable_share_one(const char *sharepath, const char *host,
233 const char *security, const char *access, void *pcookie)
234{
ddd0fd9e 235 int rc;
46e18b3f
GB
236 char *linuxhost, *hostpath, *opts;
237 const char *linux_opts = (const char *)pcookie;
ddd0fd9e 238 char *argv[6];
46e18b3f
GB
239
240 /* exportfs -i -o sec=XX,rX,<opts> <host>:<sharepath> */
241
242 rc = get_linux_hostspec(host, &linuxhost);
243
244 if (rc < 0)
245 exit(1);
246
247 hostpath = malloc(strlen(linuxhost) + 1 + strlen(sharepath) + 1);
248
249 if (hostpath == NULL) {
250 free(linuxhost);
251
252 exit(1);
253 }
254
255 sprintf(hostpath, "%s:%s", linuxhost, sharepath);
256
257 free(linuxhost);
258
259 if (linux_opts == NULL)
260 linux_opts = "";
261
262 opts = malloc(4 + strlen(security) + 4 + strlen(linux_opts) + 1);
263
264 if (opts == NULL)
265 exit(1);
266
267 sprintf(opts, "sec=%s,%s,%s", security, access, linux_opts);
268
269#ifdef DEBUG
270 fprintf(stderr, "sharing %s with opts %s\n", hostpath, opts);
271#endif
272
ddd0fd9e
GB
273 argv[0] = "/usr/sbin/exportfs";
274 argv[1] = "-i";
275 argv[2] = "-o";
276 argv[3] = opts;
277 argv[4] = hostpath;
278 argv[5] = NULL;
46e18b3f 279
ddd0fd9e 280 rc = libzfs_run_process(argv[0], argv, 0);
46e18b3f 281
ddd0fd9e
GB
282 free(hostpath);
283 free(opts);
284
285 if (rc < 0)
d1d7e268 286 return (SA_SYSTEM_ERR);
ddd0fd9e 287 else
d1d7e268 288 return (SA_OK);
46e18b3f
GB
289}
290
d1d7e268 291/*
590338f6
GB
292 * Adds a Linux share option to an array of NFS options.
293 */
46e18b3f
GB
294static int
295add_linux_shareopt(char **plinux_opts, const char *key, const char *value)
296{
297 size_t len = 0;
298 char *new_linux_opts;
299
300 if (*plinux_opts != NULL)
301 len = strlen(*plinux_opts);
302
303 new_linux_opts = realloc(*plinux_opts, len + 1 + strlen(key) +
304 (value ? 1 + strlen(value) : 0) + 1);
305
306 if (new_linux_opts == NULL)
d1d7e268 307 return (SA_NO_MEMORY);
46e18b3f
GB
308
309 new_linux_opts[len] = '\0';
310
311 if (len > 0)
312 strcat(new_linux_opts, ",");
313
314 strcat(new_linux_opts, key);
315
316 if (value != NULL) {
317 strcat(new_linux_opts, "=");
318 strcat(new_linux_opts, value);
319 }
320
321 *plinux_opts = new_linux_opts;
322
d1d7e268 323 return (SA_OK);
46e18b3f
GB
324}
325
d1d7e268 326/*
590338f6
GB
327 * Validates and converts a single Solaris share option to its Linux
328 * equivalent.
329 */
46e18b3f
GB
330static int
331get_linux_shareopts_cb(const char *key, const char *value, void *cookie)
332{
333 char **plinux_opts = (char **)cookie;
334
335 /* host-specific options, these are taken care of elsewhere */
336 if (strcmp(key, "ro") == 0 || strcmp(key, "rw") == 0 ||
337 strcmp(key, "sec") == 0)
d1d7e268 338 return (SA_OK);
46e18b3f
GB
339
340 if (strcmp(key, "anon") == 0)
341 key = "anonuid";
342
d1d7e268
MK
343 if (strcmp(key, "root_mapping") == 0) {
344 (void) add_linux_shareopt(plinux_opts, "root_squash", NULL);
345 key = "anonuid";
346 }
46e18b3f
GB
347
348 if (strcmp(key, "nosub") == 0)
349 key = "subtree_check";
350
351 if (strcmp(key, "insecure") != 0 && strcmp(key, "secure") != 0 &&
352 strcmp(key, "async") != 0 && strcmp(key, "sync") != 0 &&
353 strcmp(key, "no_wdelay") != 0 && strcmp(key, "wdelay") != 0 &&
354 strcmp(key, "nohide") != 0 && strcmp(key, "hide") != 0 &&
355 strcmp(key, "crossmnt") != 0 &&
356 strcmp(key, "no_subtree_check") != 0 &&
357 strcmp(key, "subtree_check") != 0 &&
358 strcmp(key, "insecure_locks") != 0 &&
359 strcmp(key, "secure_locks") != 0 &&
360 strcmp(key, "no_auth_nlm") != 0 && strcmp(key, "auth_nlm") != 0 &&
361 strcmp(key, "no_acl") != 0 && strcmp(key, "mountpoint") != 0 &&
362 strcmp(key, "mp") != 0 && strcmp(key, "fsuid") != 0 &&
363 strcmp(key, "refer") != 0 && strcmp(key, "replicas") != 0 &&
364 strcmp(key, "root_squash") != 0 &&
365 strcmp(key, "no_root_squash") != 0 &&
366 strcmp(key, "all_squash") != 0 &&
d2e032ca 367 strcmp(key, "no_all_squash") != 0 && strcmp(key, "fsid") != 0 &&
46e18b3f 368 strcmp(key, "anonuid") != 0 && strcmp(key, "anongid") != 0) {
d1d7e268 369 return (SA_SYNTAX_ERR);
46e18b3f
GB
370 }
371
372 (void) add_linux_shareopt(plinux_opts, key, value);
373
d1d7e268 374 return (SA_OK);
46e18b3f
GB
375}
376
d1d7e268 377/*
590338f6
GB
378 * Takes a string containing Solaris share options (e.g. "sync,no_acl") and
379 * converts them to a NULL-terminated array of Linux NFS options.
380 */
46e18b3f
GB
381static int
382get_linux_shareopts(const char *shareopts, char **plinux_opts)
383{
384 int rc;
385
386 assert(plinux_opts != NULL);
387
388 *plinux_opts = NULL;
389
390 /* default options for Solaris shares */
391 (void) add_linux_shareopt(plinux_opts, "no_subtree_check", NULL);
392 (void) add_linux_shareopt(plinux_opts, "no_root_squash", NULL);
393 (void) add_linux_shareopt(plinux_opts, "mountpoint", NULL);
394
d1d7e268
MK
395 rc = foreach_nfs_shareopt(shareopts, get_linux_shareopts_cb,
396 plinux_opts);
46e18b3f
GB
397
398 if (rc != SA_OK) {
399 free(*plinux_opts);
400 *plinux_opts = NULL;
401 }
402
d1d7e268 403 return (rc);
46e18b3f
GB
404}
405
d1d7e268 406/*
590338f6
GB
407 * Enables NFS sharing for the specified share.
408 */
46e18b3f
GB
409static int
410nfs_enable_share(sa_share_impl_t impl_share)
411{
412 char *shareopts, *linux_opts;
413 int rc;
414
27ccd414 415 if (!nfs_available()) {
d1d7e268 416 return (SA_SYSTEM_ERR);
46e18b3f
GB
417 }
418
419 shareopts = FSINFO(impl_share, nfs_fstype)->shareopts;
420
421 if (shareopts == NULL)
d1d7e268 422 return (SA_OK);
46e18b3f
GB
423
424 rc = get_linux_shareopts(shareopts, &linux_opts);
425
426 if (rc != SA_OK)
d1d7e268 427 return (rc);
46e18b3f
GB
428
429 rc = foreach_nfs_host(impl_share, nfs_enable_share_one, linux_opts);
430
431 free(linux_opts);
432
d1d7e268 433 return (rc);
46e18b3f
GB
434}
435
d1d7e268 436/*
590338f6
GB
437 * Used internally by nfs_disable_share to disable sharing for a single host.
438 */
46e18b3f
GB
439static int
440nfs_disable_share_one(const char *sharepath, const char *host,
441 const char *security, const char *access, void *cookie)
442{
ddd0fd9e 443 int rc;
46e18b3f 444 char *linuxhost, *hostpath;
ddd0fd9e 445 char *argv[4];
46e18b3f
GB
446
447 rc = get_linux_hostspec(host, &linuxhost);
448
449 if (rc < 0)
450 exit(1);
451
452 hostpath = malloc(strlen(linuxhost) + 1 + strlen(sharepath) + 1);
453
454 if (hostpath == NULL) {
455 free(linuxhost);
456 exit(1);
457 }
458
459 sprintf(hostpath, "%s:%s", linuxhost, sharepath);
460
461 free(linuxhost);
462
463#ifdef DEBUG
464 fprintf(stderr, "unsharing %s\n", hostpath);
465#endif
466
ddd0fd9e
GB
467 argv[0] = "/usr/sbin/exportfs";
468 argv[1] = "-u";
469 argv[2] = hostpath;
470 argv[3] = NULL;
46e18b3f 471
ddd0fd9e 472 rc = libzfs_run_process(argv[0], argv, 0);
46e18b3f 473
ddd0fd9e
GB
474 free(hostpath);
475
476 if (rc < 0)
d1d7e268 477 return (SA_SYSTEM_ERR);
ddd0fd9e 478 else
d1d7e268 479 return (SA_OK);
46e18b3f
GB
480}
481
d1d7e268 482/*
590338f6
GB
483 * Disables NFS sharing for the specified share.
484 */
46e18b3f
GB
485static int
486nfs_disable_share(sa_share_impl_t impl_share)
487{
27ccd414 488 if (!nfs_available()) {
46e18b3f
GB
489 /*
490 * The share can't possibly be active, so nothing
491 * needs to be done to disable it.
492 */
d1d7e268 493 return (SA_OK);
46e18b3f
GB
494 }
495
d1d7e268 496 return (foreach_nfs_host(impl_share, nfs_disable_share_one, NULL));
46e18b3f
GB
497}
498
d1d7e268 499/*
590338f6
GB
500 * Checks whether the specified NFS share options are syntactically correct.
501 */
46e18b3f
GB
502static int
503nfs_validate_shareopts(const char *shareopts)
504{
505 char *linux_opts;
506 int rc;
507
508 rc = get_linux_shareopts(shareopts, &linux_opts);
509
510 if (rc != SA_OK)
d1d7e268 511 return (rc);
46e18b3f
GB
512
513 free(linux_opts);
514
d1d7e268 515 return (SA_OK);
46e18b3f
GB
516}
517
d1d7e268 518/*
590338f6
GB
519 * Checks whether a share is currently active.
520 */
46e18b3f 521static boolean_t
645fb9cc 522nfs_is_share_active(sa_share_impl_t impl_share)
46e18b3f 523{
470f12d6 524 int fd;
46e18b3f
GB
525 char line[512];
526 char *tab, *cur;
5333eb0b 527 FILE *nfs_exportfs_temp_fp;
46e18b3f 528
27ccd414 529 if (!nfs_available())
d1d7e268 530 return (B_FALSE);
46e18b3f 531
470f12d6
G
532 if ((fd = dup(nfs_exportfs_temp_fd)) == -1)
533 return (B_FALSE);
534
535 nfs_exportfs_temp_fp = fdopen(fd, "r");
46e18b3f 536
aed0e9f3 537 if (nfs_exportfs_temp_fp == NULL)
538 return (B_FALSE);
539
540 if (fseek(nfs_exportfs_temp_fp, 0, SEEK_SET) < 0) {
5333eb0b 541 fclose(nfs_exportfs_temp_fp);
d1d7e268 542 return (B_FALSE);
5333eb0b 543 }
46e18b3f 544
d1d7e268 545 while (fgets(line, sizeof (line), nfs_exportfs_temp_fp) != NULL) {
5333eb0b
J
546 /*
547 * exportfs uses separate lines for the share path
548 * and the export options when the share path is longer
549 * than a certain amount of characters; this ignores
550 * the option lines
551 */
552 if (line[0] == '\t')
553 continue;
46e18b3f 554
5333eb0b 555 tab = strchr(line, '\t');
46e18b3f 556
5333eb0b
J
557 if (tab != NULL) {
558 *tab = '\0';
559 cur = tab - 1;
560 } else {
46e18b3f 561 /*
5333eb0b
J
562 * there's no tab character, which means the
563 * NFS options are on a separate line; we just
564 * need to remove the new-line character
565 * at the end of the line
46e18b3f 566 */
5333eb0b 567 cur = line + strlen(line) - 1;
46e18b3f
GB
568 }
569
5333eb0b
J
570 /* remove trailing spaces and new-line characters */
571 while (cur >= line && (*cur == ' ' || *cur == '\n'))
572 *cur-- = '\0';
46e18b3f 573
5333eb0b
J
574 if (strcmp(line, impl_share->sharepath) == 0) {
575 fclose(nfs_exportfs_temp_fp);
d1d7e268 576 return (B_TRUE);
5333eb0b 577 }
46e18b3f
GB
578 }
579
5333eb0b 580 fclose(nfs_exportfs_temp_fp);
46e18b3f 581
d1d7e268 582 return (B_FALSE);
46e18b3f
GB
583}
584
d1d7e268 585/*
590338f6
GB
586 * Called to update a share's options. A share's options might be out of
587 * date if the share was loaded from disk (i.e. /etc/dfs/sharetab) and the
588 * "sharenfs" dataset property has changed in the meantime. This function
589 * also takes care of re-enabling the share if necessary.
590 */
46e18b3f
GB
591static int
592nfs_update_shareopts(sa_share_impl_t impl_share, const char *resource,
593 const char *shareopts)
594{
595 char *shareopts_dup;
596 boolean_t needs_reshare = B_FALSE;
597 char *old_shareopts;
598
645fb9cc
TF
599 FSINFO(impl_share, nfs_fstype)->active =
600 nfs_is_share_active(impl_share);
46e18b3f
GB
601
602 old_shareopts = FSINFO(impl_share, nfs_fstype)->shareopts;
603
604 if (strcmp(shareopts, "on") == 0)
9b77d1c9 605 shareopts = "rw,crossmnt";
46e18b3f
GB
606
607 if (FSINFO(impl_share, nfs_fstype)->active && old_shareopts != NULL &&
608 strcmp(old_shareopts, shareopts) != 0) {
609 needs_reshare = B_TRUE;
610 nfs_disable_share(impl_share);
611 }
612
613 shareopts_dup = strdup(shareopts);
614
615 if (shareopts_dup == NULL)
d1d7e268 616 return (SA_NO_MEMORY);
46e18b3f
GB
617
618 if (old_shareopts != NULL)
619 free(old_shareopts);
620
621 FSINFO(impl_share, nfs_fstype)->shareopts = shareopts_dup;
622
623 if (needs_reshare)
624 nfs_enable_share(impl_share);
625
d1d7e268 626 return (SA_OK);
46e18b3f
GB
627}
628
d1d7e268 629/*
590338f6
GB
630 * Clears a share's NFS options. Used by libshare to
631 * clean up shares that are about to be free()'d.
632 */
46e18b3f
GB
633static void
634nfs_clear_shareopts(sa_share_impl_t impl_share)
635{
636 free(FSINFO(impl_share, nfs_fstype)->shareopts);
637 FSINFO(impl_share, nfs_fstype)->shareopts = NULL;
638}
639
640static const sa_share_ops_t nfs_shareops = {
641 .enable_share = nfs_enable_share,
642 .disable_share = nfs_disable_share,
643
644 .validate_shareopts = nfs_validate_shareopts,
645 .update_shareopts = nfs_update_shareopts,
646 .clear_shareopts = nfs_clear_shareopts,
647};
648
5333eb0b
J
649/*
650 * nfs_check_exportfs() checks that the exportfs command runs
651 * and also maintains a temporary copy of the output from
652 * exportfs -v.
653 * To update this temporary copy simply call this function again.
654 *
655 * TODO : Use /var/lib/nfs/etab instead of our private copy.
656 * But must implement locking to prevent concurrent access.
657 *
658 * TODO : The temporary file descriptor is never closed since
659 * there is no libshare_nfs_fini() function.
660 */
46e18b3f
GB
661static int
662nfs_check_exportfs(void)
663{
664 pid_t pid;
5333eb0b
J
665 int rc, status;
666 static char nfs_exportfs_tempfile[] = "/tmp/exportfs.XXXXXX";
667
668 /*
669 * Close any existing temporary copies of output from exportfs.
670 * We have already called unlink() so file will be deleted.
671 */
672 if (nfs_exportfs_temp_fd >= 0)
673 close(nfs_exportfs_temp_fd);
674
675 nfs_exportfs_temp_fd = mkstemp(nfs_exportfs_tempfile);
676
677 if (nfs_exportfs_temp_fd < 0)
d1d7e268 678 return (SA_SYSTEM_ERR);
5333eb0b
J
679
680 unlink(nfs_exportfs_tempfile);
681
af4db70f 682 (void) fcntl(nfs_exportfs_temp_fd, F_SETFD, FD_CLOEXEC);
46e18b3f
GB
683
684 pid = fork();
685
27ccd414
CP
686 if (pid < 0) {
687 (void) close(nfs_exportfs_temp_fd);
688 nfs_exportfs_temp_fd = -1;
d1d7e268 689 return (SA_SYSTEM_ERR);
27ccd414 690 }
46e18b3f
GB
691
692 if (pid > 0) {
02730c33
BB
693 while ((rc = waitpid(pid, &status, 0)) <= 0 &&
694 errno == EINTR) { }
46e18b3f 695
27ccd414
CP
696 if (rc <= 0) {
697 (void) close(nfs_exportfs_temp_fd);
698 nfs_exportfs_temp_fd = -1;
d1d7e268 699 return (SA_SYSTEM_ERR);
27ccd414 700 }
46e18b3f 701
27ccd414
CP
702 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
703 (void) close(nfs_exportfs_temp_fd);
704 nfs_exportfs_temp_fd = -1;
d1d7e268 705 return (SA_CONFIG_ERR);
27ccd414 706 }
46e18b3f 707
d1d7e268 708 return (SA_OK);
46e18b3f
GB
709 }
710
711 /* child */
712
5333eb0b 713 /* exportfs -v */
46e18b3f 714
5333eb0b 715 if (dup2(nfs_exportfs_temp_fd, STDOUT_FILENO) < 0)
46e18b3f
GB
716 exit(1);
717
5333eb0b 718 rc = execlp("/usr/sbin/exportfs", "exportfs", "-v", NULL);
46e18b3f
GB
719
720 if (rc < 0) {
721 exit(1);
722 }
723
724 exit(0);
725}
726
27ccd414 727/*
4e33ba4c 728 * Provides a convenient wrapper for determining nfs availability
27ccd414
CP
729 */
730static boolean_t
731nfs_available(void)
732{
733 if (nfs_exportfs_temp_fd == -1)
734 (void) nfs_check_exportfs();
735
d1d7e268 736 return ((nfs_exportfs_temp_fd != -1) ? B_TRUE : B_FALSE);
27ccd414
CP
737}
738
d1d7e268 739/*
590338f6
GB
740 * Initializes the NFS functionality of libshare.
741 */
46e18b3f
GB
742void
743libshare_nfs_init(void)
744{
46e18b3f
GB
745 nfs_fstype = register_fstype("nfs", &nfs_shareops);
746}