16185db85Sdougm /* 26185db85Sdougm * CDDL HEADER START 36185db85Sdougm * 46185db85Sdougm * The contents of this file are subject to the terms of the 56185db85Sdougm * Common Development and Distribution License (the "License"). 66185db85Sdougm * You may not use this file except in compliance with the License. 76185db85Sdougm * 86185db85Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96185db85Sdougm * or http://www.opensolaris.org/os/licensing. 106185db85Sdougm * See the License for the specific language governing permissions 116185db85Sdougm * and limitations under the License. 126185db85Sdougm * 136185db85Sdougm * When distributing Covered Code, include this CDDL HEADER in each 146185db85Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156185db85Sdougm * If applicable, add the following below this CDDL HEADER, with the 166185db85Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 176185db85Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 186185db85Sdougm * 196185db85Sdougm * CDDL HEADER END 206185db85Sdougm */ 216185db85Sdougm 226185db85Sdougm /* 23f345c0beSdougm * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 246185db85Sdougm * Use is subject to license terms. 256185db85Sdougm */ 266185db85Sdougm 276185db85Sdougm #pragma ident "%Z%%M% %I% %E% SMI" 286185db85Sdougm 296185db85Sdougm /* 306185db85Sdougm * core library for common functions across all config store types 316185db85Sdougm * and file systems to be exported. This includes legacy dfstab/sharetab 326185db85Sdougm * parsing. Need to eliminate XML where possible. 336185db85Sdougm */ 346185db85Sdougm 356185db85Sdougm #include <stdio.h> 366185db85Sdougm #include <string.h> 376185db85Sdougm #include <ctype.h> 386185db85Sdougm #include <unistd.h> 396185db85Sdougm #include <limits.h> 406185db85Sdougm #include <errno.h> 416185db85Sdougm #include <sys/types.h> 426185db85Sdougm #include <sys/stat.h> 436185db85Sdougm #include <libxml/parser.h> 446185db85Sdougm #include <libxml/tree.h> 456185db85Sdougm #include "libshare.h" 466185db85Sdougm #include "libshare_impl.h" 476185db85Sdougm #include <fcntl.h> 486185db85Sdougm #include <sys/stat.h> 496185db85Sdougm #include <grp.h> 506185db85Sdougm #include <limits.h> 516185db85Sdougm #include <sys/param.h> 526185db85Sdougm #include <signal.h> 536185db85Sdougm #include <libintl.h> 546185db85Sdougm 556185db85Sdougm #include "sharetab.h" 566185db85Sdougm 576185db85Sdougm #define DFSTAB_NOTICE_LINES 5 586185db85Sdougm static char *notice[DFSTAB_NOTICE_LINES] = { 596185db85Sdougm "# Do not modify this file directly.\n", 606185db85Sdougm "# Use the sharemgr(1m) command for all share management\n", 616185db85Sdougm "# This file is reconstructed and only maintained for backward\n", 626185db85Sdougm "# compatibility. Configuration lines could be lost.\n", 636185db85Sdougm "#\n" 646185db85Sdougm }; 656185db85Sdougm 666185db85Sdougm #define STRNCAT(x, y, z) (xmlChar *)strncat((char *)x, (char *)y, z) 676185db85Sdougm 686185db85Sdougm /* will be much smaller, but this handles bad syntax in the file */ 696185db85Sdougm #define MAXARGSFORSHARE 256 706185db85Sdougm 716185db85Sdougm /* used internally only */ 726185db85Sdougm typedef 736185db85Sdougm struct sharelist { 746185db85Sdougm struct sharelist *next; 756185db85Sdougm int persist; 766185db85Sdougm char *path; 776185db85Sdougm char *resource; 786185db85Sdougm char *fstype; 796185db85Sdougm char *options; 806185db85Sdougm char *description; 816185db85Sdougm char *group; 826185db85Sdougm char *origline; 836185db85Sdougm int lineno; 846185db85Sdougm } xfs_sharelist_t; 85*549ec3ffSdougm static void parse_dfstab(sa_handle_t, char *, xmlNodePtr); 866185db85Sdougm extern char *get_token(char *); 876185db85Sdougm static void dfs_free_list(xfs_sharelist_t *); 886185db85Sdougm /* prototypes */ 89*549ec3ffSdougm void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); 906185db85Sdougm extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *); 91*549ec3ffSdougm extern sa_group_t _sa_create_group(sa_handle_impl_t, char *); 926185db85Sdougm static void outdfstab(FILE *, xfs_sharelist_t *); 936185db85Sdougm extern int _sa_remove_optionset(sa_optionset_t); 946185db85Sdougm extern int set_node_share(void *, char *, char *); 956185db85Sdougm extern void set_node_attr(void *, char *, char *); 966185db85Sdougm 97a99982a7Sdougm /* 98a99982a7Sdougm * sablocksigs(*sigs) 99a99982a7Sdougm * 100a99982a7Sdougm * block important signals for a critical region. Arg is a pointer to 101a99982a7Sdougm * a sigset_t that is used later for the unblock. 102a99982a7Sdougm */ 103a99982a7Sdougm void 104a99982a7Sdougm sablocksigs(sigset_t *sigs) 105a99982a7Sdougm { 106a99982a7Sdougm sigset_t new; 107a99982a7Sdougm 108a99982a7Sdougm if (sigs != NULL) { 109a99982a7Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 110a99982a7Sdougm (void) sigaddset(&new, SIGHUP); 111a99982a7Sdougm (void) sigaddset(&new, SIGINT); 112a99982a7Sdougm (void) sigaddset(&new, SIGQUIT); 113a99982a7Sdougm (void) sigaddset(&new, SIGTSTP); 114a99982a7Sdougm (void) sigprocmask(SIG_SETMASK, &new, sigs); 115a99982a7Sdougm } 116a99982a7Sdougm } 117a99982a7Sdougm 118a99982a7Sdougm /* 119a99982a7Sdougm * saunblocksigs(*sigs) 120a99982a7Sdougm * 121a99982a7Sdougm * unblock previously blocked signals from the sigs arg. 122a99982a7Sdougm */ 123a99982a7Sdougm void 124a99982a7Sdougm saunblocksigs(sigset_t *sigs) 125a99982a7Sdougm { 126a99982a7Sdougm if (sigs != NULL) 127a99982a7Sdougm (void) sigprocmask(SIG_SETMASK, sigs, NULL); 128a99982a7Sdougm } 129a99982a7Sdougm 1306185db85Sdougm /* 1316185db85Sdougm * alloc_sharelist() 1326185db85Sdougm * 1336185db85Sdougm * allocator function to return an zfs_sharelist_t 1346185db85Sdougm */ 1356185db85Sdougm 1366185db85Sdougm static xfs_sharelist_t * 1376185db85Sdougm alloc_sharelist() 1386185db85Sdougm { 1396185db85Sdougm xfs_sharelist_t *item; 1406185db85Sdougm 1416185db85Sdougm item = (xfs_sharelist_t *)malloc(sizeof (xfs_sharelist_t)); 1426185db85Sdougm if (item != NULL) 1436185db85Sdougm (void) memset(item, '\0', sizeof (xfs_sharelist_t)); 1446185db85Sdougm return (item); 1456185db85Sdougm } 1466185db85Sdougm 1476185db85Sdougm /* 1486185db85Sdougm * fix_notice(list) 1496185db85Sdougm * 1506185db85Sdougm * Look at the beginning of the current /etc/dfs/dfstab file and add 1516185db85Sdougm * the do not modify notice if it doesn't exist. 1526185db85Sdougm */ 1536185db85Sdougm 1546185db85Sdougm static xfs_sharelist_t * 1556185db85Sdougm fix_notice(xfs_sharelist_t *list) 1566185db85Sdougm { 1576185db85Sdougm xfs_sharelist_t *item, *prev; 1586185db85Sdougm int i; 1596185db85Sdougm 1607d968cb8Sdougm if (list == NULL) { 1617d968cb8Sdougm /* zero length dfstab */ 1627d968cb8Sdougm list = alloc_sharelist(); 1637d968cb8Sdougm if (list == NULL) 1647d968cb8Sdougm return (NULL); 1657d968cb8Sdougm list->description = strdup("#\n"); 1667d968cb8Sdougm } 1676185db85Sdougm if (list->path == NULL && list->description != NULL && 1686185db85Sdougm strcmp(list->description, notice[0]) != 0) { 1696185db85Sdougm for (prev = NULL, i = 0; i < DFSTAB_NOTICE_LINES; i++) { 1706185db85Sdougm item = alloc_sharelist(); 1716185db85Sdougm if (item != NULL) { 1726185db85Sdougm item->description = strdup(notice[i]); 1736185db85Sdougm if (prev == NULL) { 1746185db85Sdougm item->next = list; 1756185db85Sdougm prev = item; 1766185db85Sdougm list = item; 1776185db85Sdougm } else { 1786185db85Sdougm item->next = prev->next; 1796185db85Sdougm prev->next = item; 1806185db85Sdougm prev = item; 1816185db85Sdougm } 1826185db85Sdougm } 1836185db85Sdougm } 1846185db85Sdougm } 1856185db85Sdougm return (list); 1866185db85Sdougm } 1876185db85Sdougm 1886185db85Sdougm /* 1896185db85Sdougm * getdfstab(dfs) 1906185db85Sdougm * 1916185db85Sdougm * Returns an zfs_sharelist_t list of lines from the dfstab file 1926185db85Sdougm * pointed to by the FILE pointer dfs. Each entry is parsed and the 1936185db85Sdougm * original line is also preserved. Used in parsing and updating the 1946185db85Sdougm * dfstab file. 1956185db85Sdougm */ 1966185db85Sdougm 1976185db85Sdougm static xfs_sharelist_t * 1986185db85Sdougm getdfstab(FILE *dfs) 1996185db85Sdougm { 2006185db85Sdougm char buff[_POSIX_ARG_MAX]; /* reasonable size given syntax of share */ 2016185db85Sdougm char *bp; 2026185db85Sdougm char *token; 2036185db85Sdougm char *args[MAXARGSFORSHARE]; 2046185db85Sdougm int argc; 2056185db85Sdougm int c; 2066185db85Sdougm static int line = 0; 2077d968cb8Sdougm xfs_sharelist_t *item = NULL, *first = NULL, *last; 2086185db85Sdougm 2096185db85Sdougm if (dfs != NULL) { 2106185db85Sdougm first = NULL; 2116185db85Sdougm line = 0; 2126185db85Sdougm while (fgets(buff, sizeof (buff), dfs) != NULL) { 2136185db85Sdougm line++; 2146185db85Sdougm bp = buff; 2156185db85Sdougm if (buff[0] == '#') { 2166185db85Sdougm item = alloc_sharelist(); 2176185db85Sdougm if (item != NULL) { 2186185db85Sdougm /* if no path, then comment */ 2196185db85Sdougm item->lineno = line; 2206185db85Sdougm item->description = strdup(buff); 2216185db85Sdougm if (first == NULL) { 2226185db85Sdougm first = item; 2236185db85Sdougm last = item; 2246185db85Sdougm } else { 2256185db85Sdougm last->next = item; 2266185db85Sdougm last = item; 2276185db85Sdougm } 2286185db85Sdougm } else { 2296185db85Sdougm break; 2306185db85Sdougm } 2316185db85Sdougm continue; 2326185db85Sdougm } else if (buff[0] == '\n') { 2336185db85Sdougm continue; 2346185db85Sdougm } 2356185db85Sdougm optind = 1; 2366185db85Sdougm item = alloc_sharelist(); 2376185db85Sdougm if (item == NULL) { 2386185db85Sdougm break; 2396185db85Sdougm } else if (first == NULL) { 2406185db85Sdougm first = item; 2416185db85Sdougm last = item; 2426185db85Sdougm } else { 2436185db85Sdougm last->next = item; 2446185db85Sdougm last = item; 2456185db85Sdougm } 2466185db85Sdougm item->lineno = line; 2476185db85Sdougm item->origline = strdup(buff); 2486185db85Sdougm (void) get_token(NULL); /* reset to new pointers */ 2496185db85Sdougm argc = 0; 2506185db85Sdougm while ((token = get_token(bp)) != NULL) { 2516185db85Sdougm if (argc < MAXARGSFORSHARE) { 2526185db85Sdougm args[argc++] = token; 2536185db85Sdougm } 2546185db85Sdougm } 2556185db85Sdougm while ((c = getopt(argc, args, "F:o:d:pg:")) != -1) { 2566185db85Sdougm switch (c) { 2576185db85Sdougm case 'p': 2586185db85Sdougm item->persist = 1; 2596185db85Sdougm break; 2606185db85Sdougm case 'F': 2616185db85Sdougm item->fstype = strdup(optarg); 2626185db85Sdougm break; 2636185db85Sdougm case 'o': 2646185db85Sdougm item->options = strdup(optarg); 2656185db85Sdougm break; 2666185db85Sdougm case 'd': 2676185db85Sdougm item->description = strdup(optarg); 2686185db85Sdougm break; 2696185db85Sdougm case 'g': 2706185db85Sdougm item->group = strdup(optarg); 2716185db85Sdougm break; 2726185db85Sdougm default: 2736185db85Sdougm break; 2746185db85Sdougm } 2756185db85Sdougm } 2766185db85Sdougm if (optind < argc) { 2776185db85Sdougm item->path = strdup(args[optind]); 2786185db85Sdougm optind++; 2796185db85Sdougm if (optind < argc) { 2806185db85Sdougm char *resource; 2816185db85Sdougm char *optgroup; 2826185db85Sdougm /* resource and/or groupname */ 2836185db85Sdougm resource = args[optind]; 2846185db85Sdougm optgroup = strchr(resource, '@'); 2856185db85Sdougm if (optgroup != NULL) { 2866185db85Sdougm *optgroup++ = '\0'; 2876185db85Sdougm } 2886185db85Sdougm if (optgroup != NULL) 2896185db85Sdougm item->group = strdup(optgroup); 2906185db85Sdougm if (resource != NULL && strlen(resource) > 0) 2916185db85Sdougm item->resource = strdup(resource); 2926185db85Sdougm } 2936185db85Sdougm } 294a99982a7Sdougm if (item != NULL && item->fstype == NULL) { 295a99982a7Sdougm item->fstype = strdup("nfs"); /* this is the default */ 296a99982a7Sdougm } 2976185db85Sdougm } 2986185db85Sdougm } 2996185db85Sdougm first = fix_notice(first); 3006185db85Sdougm return (first); 3016185db85Sdougm } 3026185db85Sdougm 3036185db85Sdougm /* 3046185db85Sdougm * finddfsentry(list, path) 3056185db85Sdougm * 3067d968cb8Sdougm * Look for path in the zfs_sharelist_t list and return the entry if it 3076185db85Sdougm * exists. 3086185db85Sdougm */ 3096185db85Sdougm 3106185db85Sdougm static xfs_sharelist_t * 3116185db85Sdougm finddfsentry(xfs_sharelist_t *list, char *path) 3126185db85Sdougm { 3136185db85Sdougm xfs_sharelist_t *item; 3146185db85Sdougm 3156185db85Sdougm for (item = list; item != NULL; item = item->next) { 3166185db85Sdougm if (item->path != NULL && strcmp(item->path, path) == 0) 3176185db85Sdougm return (item); 3186185db85Sdougm } 3196185db85Sdougm return (NULL); 3206185db85Sdougm } 3216185db85Sdougm 3226185db85Sdougm /* 3236185db85Sdougm * remdfsentry(list, path, proto) 3246185db85Sdougm * 3256185db85Sdougm * Remove the specified path (with protocol) from the list. This will 3266185db85Sdougm * remove it from dfstab when the file is rewritten. 3276185db85Sdougm */ 3286185db85Sdougm 3296185db85Sdougm static xfs_sharelist_t * 3306185db85Sdougm remdfsentry(xfs_sharelist_t *list, char *path, char *proto) 3316185db85Sdougm { 3326185db85Sdougm xfs_sharelist_t *item, *prev = NULL; 3336185db85Sdougm 3346185db85Sdougm 3356185db85Sdougm for (item = prev = list; item != NULL; item = item->next) { 3366185db85Sdougm /* skip comment entry but don't lose it */ 3376185db85Sdougm if (item->path == NULL) { 3386185db85Sdougm prev = item; 3396185db85Sdougm continue; 3406185db85Sdougm } 3416185db85Sdougm /* if proto is NULL, remove all protocols */ 3426185db85Sdougm if (proto == NULL || (strcmp(item->path, path) == 0 && 3436185db85Sdougm (item->fstype != NULL && strcmp(item->fstype, proto) == 0))) 3446185db85Sdougm break; 3456185db85Sdougm if (item->fstype == NULL && 3466185db85Sdougm (proto == NULL || strcmp(proto, "nfs") == 0)) 3476185db85Sdougm break; 3486185db85Sdougm prev = item; 3496185db85Sdougm } 3506185db85Sdougm if (item != NULL) { 3516185db85Sdougm if (item == prev) { 3526185db85Sdougm list = item->next; /* this must be the first one */ 3536185db85Sdougm } else { 3546185db85Sdougm prev->next = item->next; 3556185db85Sdougm } 3566185db85Sdougm item->next = NULL; 3576185db85Sdougm dfs_free_list(item); 3586185db85Sdougm } 3596185db85Sdougm return (list); 3606185db85Sdougm } 3616185db85Sdougm 3626185db85Sdougm /* 3636185db85Sdougm * remdfsline(list, line) 3646185db85Sdougm * 3656185db85Sdougm * Remove the line specified from the list. 3666185db85Sdougm */ 3676185db85Sdougm 3686185db85Sdougm static xfs_sharelist_t * 3696185db85Sdougm remdfsline(xfs_sharelist_t *list, char *line) 3706185db85Sdougm { 3716185db85Sdougm xfs_sharelist_t *item, *prev = NULL; 3726185db85Sdougm 3736185db85Sdougm for (item = prev = list; item != NULL; item = item->next) { 3746185db85Sdougm /* skip comment entry but don't lose it */ 3756185db85Sdougm if (item->path == NULL) { 3766185db85Sdougm prev = item; 3776185db85Sdougm continue; 3786185db85Sdougm } 3796185db85Sdougm if (strcmp(item->origline, line) == 0) { 3806185db85Sdougm break; 3816185db85Sdougm } 3826185db85Sdougm prev = item; 3836185db85Sdougm } 3846185db85Sdougm if (item != NULL) { 3856185db85Sdougm if (item == prev) { 3866185db85Sdougm list = item->next; /* this must be the first one */ 3876185db85Sdougm } else { 3886185db85Sdougm prev->next = item->next; 3896185db85Sdougm } 3906185db85Sdougm item->next = NULL; 3916185db85Sdougm dfs_free_list(item); 3926185db85Sdougm } 3936185db85Sdougm return (list); 3946185db85Sdougm } 3956185db85Sdougm 3966185db85Sdougm /* 3976185db85Sdougm * adddfsentry(list, share, proto) 3986185db85Sdougm * 3996185db85Sdougm * Add an entry to the dfstab list for share (relative to proto). This 4006185db85Sdougm * is used to update dfstab for legacy purposes. 4016185db85Sdougm */ 4026185db85Sdougm 4036185db85Sdougm static xfs_sharelist_t * 4046185db85Sdougm adddfsentry(xfs_sharelist_t *list, sa_share_t share, char *proto) 4056185db85Sdougm { 4066185db85Sdougm xfs_sharelist_t *item, *tmp; 4076185db85Sdougm sa_group_t parent; 4086185db85Sdougm char *groupname; 4096185db85Sdougm 4106185db85Sdougm item = alloc_sharelist(); 4116185db85Sdougm if (item != NULL) { 4126185db85Sdougm parent = sa_get_parent_group(share); 4136185db85Sdougm groupname = sa_get_group_attr(parent, "name"); 4146185db85Sdougm if (strcmp(groupname, "default") == 0) { 4156185db85Sdougm sa_free_attr_string(groupname); 4166185db85Sdougm groupname = NULL; 4176185db85Sdougm } 4186185db85Sdougm item->path = sa_get_share_attr(share, "path"); 4196185db85Sdougm item->resource = sa_get_share_attr(share, "resource"); 4206185db85Sdougm item->group = groupname; 4216185db85Sdougm item->fstype = strdup(proto); 4226185db85Sdougm item->options = sa_proto_legacy_format(proto, share, 1); 4236185db85Sdougm if (item->options != NULL && strlen(item->options) == 0) { 4246185db85Sdougm free(item->options); 4256185db85Sdougm item->options = NULL; 4266185db85Sdougm } 4276185db85Sdougm item->description = sa_get_share_description(share); 4286185db85Sdougm if (item->description != NULL && strlen(item->description) == 0) { 4296185db85Sdougm sa_free_share_description(item->description); 4306185db85Sdougm item->description = NULL; 4316185db85Sdougm } 4326185db85Sdougm if (list == NULL) { 4336185db85Sdougm list = item; 4346185db85Sdougm } else { 4356185db85Sdougm for (tmp = list; tmp->next != NULL; tmp = tmp->next) 4366185db85Sdougm /* do nothing */; 4376185db85Sdougm tmp->next = item; 4386185db85Sdougm } 4396185db85Sdougm } 4406185db85Sdougm return (list); 4416185db85Sdougm } 4426185db85Sdougm 4436185db85Sdougm /* 4446185db85Sdougm * outdfstab(dfstab, list) 4456185db85Sdougm * 4466185db85Sdougm * Output the list to dfstab making sure the file is truncated. 4476185db85Sdougm * Comments and errors are preserved. 4486185db85Sdougm */ 4496185db85Sdougm 4506185db85Sdougm static void 4516185db85Sdougm outdfstab(FILE *dfstab, xfs_sharelist_t *list) 4526185db85Sdougm { 4536185db85Sdougm xfs_sharelist_t *item; 4546185db85Sdougm 4556185db85Sdougm (void) ftruncate(fileno(dfstab), 0); 4566185db85Sdougm 4576185db85Sdougm for (item = list; item != NULL; item = item->next) { 4586185db85Sdougm if (item->path != NULL) { 4596185db85Sdougm if (*item->path == '/') 4606185db85Sdougm (void) fprintf(dfstab, "share %s%s%s%s%s%s%s %s%s%s%s%s\n", 4616185db85Sdougm (item->fstype != NULL) ? "-F " : "", 4626185db85Sdougm (item->fstype != NULL) ? item->fstype : "", 4636185db85Sdougm (item->options != NULL) ? " -o " : "", 4646185db85Sdougm (item->options != NULL) ? item->options : "", 4656185db85Sdougm (item->description != NULL) ? " -d \"" : "", 4666185db85Sdougm (item->description != NULL) ? 4676185db85Sdougm item->description : "", 4686185db85Sdougm (item->description != NULL) ? "\"" : "", 4696185db85Sdougm item->path, 4706185db85Sdougm ((item->resource != NULL) || 4716185db85Sdougm (item->group != NULL)) ? " " : "", 4726185db85Sdougm (item->resource != NULL) ? item->resource : "", 4736185db85Sdougm item->group != NULL ? "@" : "", 4746185db85Sdougm item->group != NULL ? item->group : ""); 4756185db85Sdougm else 4766185db85Sdougm (void) fprintf(dfstab, "%s", item->origline); 4776185db85Sdougm } else { 4786185db85Sdougm if (item->description != NULL) { 4796185db85Sdougm (void) fprintf(dfstab, "%s", item->description); 4806185db85Sdougm } else { 4816185db85Sdougm (void) fprintf(dfstab, "%s", item->origline); 4826185db85Sdougm } 4836185db85Sdougm } 4846185db85Sdougm } 4856185db85Sdougm } 4866185db85Sdougm 4876185db85Sdougm /* 4886185db85Sdougm * open_dfstab(file) 4896185db85Sdougm * 4906185db85Sdougm * Open the specified dfstab file. If the owner/group/perms are wrong, 4916185db85Sdougm * fix them. 4926185db85Sdougm */ 4936185db85Sdougm 4946185db85Sdougm static FILE * 4956185db85Sdougm open_dfstab(char *file) 4966185db85Sdougm { 4976185db85Sdougm struct group *grp; 4986185db85Sdougm struct group group; 4996185db85Sdougm char *buff; 5006185db85Sdougm int grsize; 5016185db85Sdougm FILE *dfstab; 5026185db85Sdougm 5036185db85Sdougm dfstab = fopen(file, "r+"); 5046185db85Sdougm if (dfstab == NULL) { 5056185db85Sdougm dfstab = fopen(file, "w+"); 5066185db85Sdougm } 5076185db85Sdougm if (dfstab != NULL) { 5086185db85Sdougm grsize = sysconf(_SC_GETGR_R_SIZE_MAX); 5096185db85Sdougm buff = malloc(grsize); 5106185db85Sdougm if (buff != NULL) 5116185db85Sdougm grp = getgrnam_r(SA_DEFAULT_FILE_GRP, &group, buff, grsize); 5126185db85Sdougm else 5136185db85Sdougm grp = getgrnam(SA_DEFAULT_FILE_GRP); /* take the risk */ 5146185db85Sdougm (void) fchmod(fileno(dfstab), 0644); 5156185db85Sdougm (void) fchown(fileno(dfstab), 0, 5166185db85Sdougm grp != NULL ? grp->gr_gid : 3); 5176185db85Sdougm if (buff != NULL) 5186185db85Sdougm free(buff); 5196185db85Sdougm rewind(dfstab); 5206185db85Sdougm } 5216185db85Sdougm return (dfstab); 5226185db85Sdougm } 5236185db85Sdougm 5246185db85Sdougm /* 5256185db85Sdougm * sa_comment_line(line, err) 5266185db85Sdougm * 5276185db85Sdougm * Add a comment to the dfstab file with err as a prefix to the 5286185db85Sdougm * original line. 5296185db85Sdougm */ 5306185db85Sdougm 5316185db85Sdougm static void 5326185db85Sdougm sa_comment_line(char *line, char *err) 5336185db85Sdougm { 5346185db85Sdougm FILE *dfstab; 5356185db85Sdougm xfs_sharelist_t *list; 536a99982a7Sdougm sigset_t old; 5376185db85Sdougm 5386185db85Sdougm dfstab = open_dfstab(SA_LEGACY_DFSTAB); 5396185db85Sdougm if (dfstab != NULL) { 5406185db85Sdougm (void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8); 541a99982a7Sdougm sablocksigs(&old); 5426185db85Sdougm (void) lockf(fileno(dfstab), F_LOCK, 0); 5436185db85Sdougm list = getdfstab(dfstab); 5446185db85Sdougm rewind(dfstab); 545f345c0beSdougm /* 546f345c0beSdougm * don't ignore the return since the list could have 547f345c0beSdougm * gone to NULL if the file only had one line in it. 548f345c0beSdougm */ 549f345c0beSdougm list = remdfsline(list, line); 5506185db85Sdougm outdfstab(dfstab, list); 5516185db85Sdougm (void) fprintf(dfstab, "# Error: %s: %s", err, line); 5526185db85Sdougm (void) fsync(fileno(dfstab)); 5536185db85Sdougm (void) lockf(fileno(dfstab), F_ULOCK, 0); 5546185db85Sdougm (void) fclose(dfstab); 555a99982a7Sdougm saunblocksigs(&old); 5566185db85Sdougm if (list != NULL) 5576185db85Sdougm dfs_free_list(list); 5586185db85Sdougm } 5596185db85Sdougm } 5606185db85Sdougm 5616185db85Sdougm /* 5626185db85Sdougm * sa_delete_legacy(share) 5636185db85Sdougm * 5646185db85Sdougm * Delete the specified share from the legacy config file. 5656185db85Sdougm */ 5666185db85Sdougm 5676185db85Sdougm int 5686185db85Sdougm sa_delete_legacy(sa_share_t share) 5696185db85Sdougm { 5706185db85Sdougm FILE *dfstab; 5716185db85Sdougm int err; 5726185db85Sdougm int ret = SA_OK; 5736185db85Sdougm xfs_sharelist_t *list; 5746185db85Sdougm char *path; 5756185db85Sdougm sa_optionset_t optionset; 5766185db85Sdougm sa_group_t parent; 577a99982a7Sdougm sigset_t old; 5786185db85Sdougm 5796185db85Sdougm dfstab = open_dfstab(SA_LEGACY_DFSTAB); 5806185db85Sdougm if (dfstab != NULL) { 5816185db85Sdougm (void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8); 582a99982a7Sdougm sablocksigs(&old); 5836185db85Sdougm path = sa_get_share_attr(share, "path"); 5846185db85Sdougm parent = sa_get_parent_group(share); 5856185db85Sdougm if (parent != NULL) { 5866185db85Sdougm (void) lockf(fileno(dfstab), F_LOCK, 0); 5876185db85Sdougm list = getdfstab(dfstab); 5886185db85Sdougm rewind(dfstab); 5896185db85Sdougm for (optionset = sa_get_optionset(parent, NULL); 5906185db85Sdougm optionset != NULL; 5916185db85Sdougm optionset = sa_get_next_optionset(optionset)) { 5926185db85Sdougm char *proto = sa_get_optionset_attr(optionset, "type"); 5936185db85Sdougm if (list != NULL && proto != NULL) 5947d968cb8Sdougm list = remdfsentry(list, path, proto); 5956185db85Sdougm if (proto == NULL) 5966185db85Sdougm ret = SA_NO_MEMORY; 5976185db85Sdougm /* 5986185db85Sdougm * may want to only do the dfstab if this call 5996185db85Sdougm * returns NOT IMPLEMENTED but it shouldn't 6006185db85Sdougm * hurt. 6016185db85Sdougm */ 6026185db85Sdougm if (ret == SA_OK) { 6036185db85Sdougm err = sa_proto_delete_legacy(proto, share); 6046185db85Sdougm if (err != SA_NOT_IMPLEMENTED) 6056185db85Sdougm ret = err; 6066185db85Sdougm } 6076185db85Sdougm if (proto != NULL) 6086185db85Sdougm sa_free_attr_string(proto); 6096185db85Sdougm } 6106185db85Sdougm outdfstab(dfstab, list); 6116185db85Sdougm if (list != NULL) 6126185db85Sdougm dfs_free_list(list); 6136185db85Sdougm (void) fflush(dfstab); 6146185db85Sdougm (void) lockf(fileno(dfstab), F_ULOCK, 0); 6156185db85Sdougm } 6166185db85Sdougm (void) fsync(fileno(dfstab)); 617a99982a7Sdougm saunblocksigs(&old); 6186185db85Sdougm (void) fclose(dfstab); 6196185db85Sdougm sa_free_attr_string(path); 6206185db85Sdougm } else { 6216185db85Sdougm if (errno == EACCES || errno == EPERM) { 6226185db85Sdougm ret = SA_NO_PERMISSION; 6236185db85Sdougm } else { 6246185db85Sdougm ret = SA_CONFIG_ERR; 6256185db85Sdougm } 6266185db85Sdougm } 6276185db85Sdougm return (ret); 6286185db85Sdougm } 6296185db85Sdougm 6306185db85Sdougm /* 6316185db85Sdougm * sa_update_legacy(share, proto) 6326185db85Sdougm * 6336185db85Sdougm * There is an assumption that dfstab will be the most common form of 6346185db85Sdougm * legacy configuration file for shares, but not the only one. Because 6356185db85Sdougm * of that, dfstab handling is done in the main code with calls to 6366185db85Sdougm * this function and protocol specific calls to deal with formating 6376185db85Sdougm * options into dfstab/share compatible syntax. Since not everything 6386185db85Sdougm * will be dfstab, there is a provision for calling a protocol 6396185db85Sdougm * specific plugin interface that allows the protocol plugin to do its 6406185db85Sdougm * own legacy files and skip the dfstab update. 6416185db85Sdougm */ 6426185db85Sdougm 6436185db85Sdougm int 6446185db85Sdougm sa_update_legacy(sa_share_t share, char *proto) 6456185db85Sdougm { 6466185db85Sdougm FILE *dfstab; 6476185db85Sdougm int ret = SA_OK; 6486185db85Sdougm xfs_sharelist_t *list; 6496185db85Sdougm char *path; 650a99982a7Sdougm sigset_t old; 6516185db85Sdougm char *persist; 6526185db85Sdougm 6536185db85Sdougm ret = sa_proto_update_legacy(proto, share); 6546185db85Sdougm if (ret != SA_NOT_IMPLEMENTED) 6556185db85Sdougm return (ret); 6566185db85Sdougm /* do the dfstab format */ 6576185db85Sdougm persist = sa_get_share_attr(share, "type"); 6586185db85Sdougm /* 6596185db85Sdougm * only update if the share is not transient -- no share type 6606185db85Sdougm * set or the type is not "transient". 6616185db85Sdougm */ 6626185db85Sdougm if (persist == NULL || strcmp(persist, "transient") != 0) { 6636185db85Sdougm dfstab = open_dfstab(SA_LEGACY_DFSTAB); 6646185db85Sdougm if (dfstab != NULL) { 6656185db85Sdougm (void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8); 666a99982a7Sdougm sablocksigs(&old); 6676185db85Sdougm path = sa_get_share_attr(share, "path"); 6686185db85Sdougm (void) lockf(fileno(dfstab), F_LOCK, 0); 6696185db85Sdougm list = getdfstab(dfstab); 6706185db85Sdougm rewind(dfstab); 6716185db85Sdougm if (list != NULL) 6726185db85Sdougm list = remdfsentry(list, path, proto); 6736185db85Sdougm list = adddfsentry(list, share, proto); 6746185db85Sdougm outdfstab(dfstab, list); 6756185db85Sdougm (void) fflush(dfstab); 6766185db85Sdougm (void) lockf(fileno(dfstab), F_ULOCK, 0); 6776185db85Sdougm (void) fsync(fileno(dfstab)); 678a99982a7Sdougm saunblocksigs(&old); 6796185db85Sdougm (void) fclose(dfstab); 6806185db85Sdougm sa_free_attr_string(path); 6816185db85Sdougm if (list != NULL) 6826185db85Sdougm dfs_free_list(list); 6836185db85Sdougm } else { 6846185db85Sdougm if (errno == EACCES || errno == EPERM) { 6856185db85Sdougm ret = SA_NO_PERMISSION; 6866185db85Sdougm } else { 6876185db85Sdougm ret = SA_CONFIG_ERR; 6886185db85Sdougm } 6896185db85Sdougm } 6906185db85Sdougm } 6916185db85Sdougm if (persist != NULL) 6926185db85Sdougm sa_free_attr_string(persist); 6936185db85Sdougm return (ret); 6946185db85Sdougm } 6956185db85Sdougm 6966185db85Sdougm /* 6976185db85Sdougm * sa_is_security(optname, proto) 6986185db85Sdougm * 6996185db85Sdougm * Check to see if optname is a security (named optionset) specific 7006185db85Sdougm * property for the specified protocol. 7016185db85Sdougm */ 7026185db85Sdougm 7036185db85Sdougm int 7046185db85Sdougm sa_is_security(char *optname, char *proto) 7056185db85Sdougm { 7066185db85Sdougm int ret = 0; 7076185db85Sdougm if (proto != NULL) 7086185db85Sdougm ret = sa_proto_security_prop(proto, optname); 7096185db85Sdougm return (ret); 7106185db85Sdougm } 7116185db85Sdougm 7126185db85Sdougm /* 7136185db85Sdougm * add_syntax_comment(root, line, err, todfstab) 7146185db85Sdougm * 7156185db85Sdougm * add a comment to the document indicating a syntax error. If 7166185db85Sdougm * todfstab is set, write it back to the dfstab file as well. 7176185db85Sdougm */ 7186185db85Sdougm 7196185db85Sdougm static void 7206185db85Sdougm add_syntax_comment(xmlNodePtr root, char *line, char *err, int todfstab) 7216185db85Sdougm { 7226185db85Sdougm xmlNodePtr node; 7236185db85Sdougm 7246185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"error", (xmlChar *)line); 7256185db85Sdougm if (node != NULL) { 7266185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)err); 7276185db85Sdougm } 7286185db85Sdougm if (todfstab) 7296185db85Sdougm sa_comment_line(line, err); 7306185db85Sdougm } 7316185db85Sdougm 7326185db85Sdougm /* 7336185db85Sdougm * sa_is_share(object) 7346185db85Sdougm * 7356185db85Sdougm * returns true of the object is of type "share". 7366185db85Sdougm */ 7376185db85Sdougm 7386185db85Sdougm int 7396185db85Sdougm sa_is_share(void *object) 7406185db85Sdougm { 7416185db85Sdougm if (object != NULL) { 7426185db85Sdougm if (strcmp((char *)((xmlNodePtr)object)->name, "share") == 0) 7436185db85Sdougm return (1); 7446185db85Sdougm } 7456185db85Sdougm return (0); 7466185db85Sdougm } 7476185db85Sdougm 7486185db85Sdougm /* 7496185db85Sdougm * _sa_remove_property(property) 7506185db85Sdougm * 7516185db85Sdougm * remove a property only from the document. 7526185db85Sdougm */ 7536185db85Sdougm 7546185db85Sdougm static void 7556185db85Sdougm _sa_remove_property(sa_property_t property) 7566185db85Sdougm { 7576185db85Sdougm xmlUnlinkNode((xmlNodePtr)property); 7586185db85Sdougm xmlFreeNode((xmlNodePtr)property); 7596185db85Sdougm } 7606185db85Sdougm 7616185db85Sdougm /* 7626185db85Sdougm * sa_parse_legacy_options(group, options, proto) 7636185db85Sdougm * 7646185db85Sdougm * In order to support legacy configurations, we allow the protocol 7656185db85Sdougm * specific plugin to parse legacy syntax options (like those in 7666185db85Sdougm * /etc/dfs/dfstab). This adds a new optionset to the group (or 7676185db85Sdougm * share). 7686185db85Sdougm * 7696185db85Sdougm * Once the optionset has been created, we then get the derived 7706185db85Sdougm * optionset of the parent (options from the optionset of the parent 7716185db85Sdougm * and any parent it might have) and remove those from the created 7726185db85Sdougm * optionset. This avoids duplication of options. 7736185db85Sdougm */ 7746185db85Sdougm 7756185db85Sdougm int 7766185db85Sdougm sa_parse_legacy_options(sa_group_t group, char *options, char *proto) 7776185db85Sdougm { 7786185db85Sdougm int ret = SA_INVALID_PROTOCOL; 7796185db85Sdougm sa_group_t parent; 7806185db85Sdougm parent = sa_get_parent_group(group); 7816185db85Sdougm 7826185db85Sdougm if (proto != NULL) 7836185db85Sdougm ret = sa_proto_legacy_opts(proto, group, options); 7846185db85Sdougm /* 7856185db85Sdougm * if in a group, remove the inherited options and security 7866185db85Sdougm */ 7876185db85Sdougm if (ret == SA_OK) { 7886185db85Sdougm if (parent != NULL) { 7896185db85Sdougm sa_optionset_t optionset; 7906185db85Sdougm sa_property_t popt, prop; 7916185db85Sdougm sa_optionset_t localoptions; 7926185db85Sdougm /* find parent options to remove from child */ 7936185db85Sdougm optionset = sa_get_derived_optionset(parent, proto, 1); 7946185db85Sdougm localoptions = sa_get_optionset(group, proto); 7956185db85Sdougm if (optionset != NULL) { 7966185db85Sdougm for (popt = sa_get_property(optionset, NULL); 7976185db85Sdougm popt != NULL; 7986185db85Sdougm popt = sa_get_next_property(popt)) { 7996185db85Sdougm char *tag; 8006185db85Sdougm char *value1; 8016185db85Sdougm char *value2; 8026185db85Sdougm 8036185db85Sdougm tag = sa_get_property_attr(popt, "type"); 8046185db85Sdougm if (tag != NULL) { 8056185db85Sdougm prop = sa_get_property(localoptions, tag); 8066185db85Sdougm if (prop != NULL) { 8076185db85Sdougm value1 = sa_get_property_attr(popt, "value"); 8086185db85Sdougm value2 = sa_get_property_attr(prop, "value"); 8096185db85Sdougm if (value1 != NULL && value2 != NULL && 8106185db85Sdougm strcmp(value1, value2) == 0) { 8116185db85Sdougm /* remove the property from the child */ 8126185db85Sdougm (void) _sa_remove_property(prop); 8136185db85Sdougm } 8146185db85Sdougm if (value1 != NULL) 8156185db85Sdougm sa_free_attr_string(value1); 8166185db85Sdougm if (value2 != NULL) 8176185db85Sdougm sa_free_attr_string(value2); 8186185db85Sdougm } 8196185db85Sdougm sa_free_attr_string(tag); 8206185db85Sdougm } 8216185db85Sdougm } 8226185db85Sdougm prop = sa_get_property(localoptions, NULL); 8236185db85Sdougm if (prop == NULL && sa_is_share(group)) { 8246185db85Sdougm /* 8256185db85Sdougm * all properties removed so remove the 8266185db85Sdougm * optionset if it is on a share 8276185db85Sdougm */ 8286185db85Sdougm (void) _sa_remove_optionset(localoptions); 8296185db85Sdougm } 8306185db85Sdougm sa_free_derived_optionset(optionset); 8316185db85Sdougm } 8326185db85Sdougm /* 8336185db85Sdougm * need to remove security here. If there are no 8346185db85Sdougm * security options on the local group/share, don't 8356185db85Sdougm * bother since those are the only ones that would be 8366185db85Sdougm * affected. 8376185db85Sdougm */ 8386185db85Sdougm localoptions = sa_get_all_security_types(group, proto, 0); 8396185db85Sdougm if (localoptions != NULL) { 8406185db85Sdougm for (prop = sa_get_property(localoptions, NULL); 8416185db85Sdougm prop != NULL; prop = sa_get_next_property(prop)) { 8426185db85Sdougm char *tag; 8436185db85Sdougm sa_security_t security; 8446185db85Sdougm tag = sa_get_property_attr(prop, "type"); 8456185db85Sdougm if (tag != NULL) { 8466185db85Sdougm security = sa_get_security(group, tag, proto); 8476185db85Sdougm sa_free_attr_string(tag); 8486185db85Sdougm for (popt = sa_get_property(security, NULL); 8496185db85Sdougm popt != NULL; 8506185db85Sdougm popt = sa_get_next_property(popt)) { 8516185db85Sdougm char *value1; 8526185db85Sdougm char *value2; 8536185db85Sdougm 8546185db85Sdougm /* remove duplicates from this level */ 8556185db85Sdougm value1 = sa_get_property_attr(popt, "value"); 8566185db85Sdougm value2 = sa_get_property_attr(prop, "value"); 8576185db85Sdougm if (value1 != NULL && value2 != NULL && 8586185db85Sdougm strcmp(value1, value2) == 0) { 8596185db85Sdougm /* remove the property from the child */ 8606185db85Sdougm (void) _sa_remove_property(prop); 8616185db85Sdougm } 8626185db85Sdougm if (value1 != NULL) 8636185db85Sdougm sa_free_attr_string(value1); 8646185db85Sdougm if (value2 != NULL) 8656185db85Sdougm sa_free_attr_string(value2); 8666185db85Sdougm } 8676185db85Sdougm } 8686185db85Sdougm } 8696185db85Sdougm (void) sa_destroy_optionset(localoptions); 8706185db85Sdougm } 8716185db85Sdougm } 8726185db85Sdougm } 8736185db85Sdougm return (ret); 8746185db85Sdougm } 8756185db85Sdougm 8766185db85Sdougm /* 8776185db85Sdougm * dfs_free_list(list) 8786185db85Sdougm * 8796185db85Sdougm * Free the data in each list entry of the list as well as freeing the 8806185db85Sdougm * entries themselves. We need to avoid memory leaks and don't want to 8816185db85Sdougm * dereference any NULL members. 8826185db85Sdougm */ 8836185db85Sdougm 8846185db85Sdougm static void 8856185db85Sdougm dfs_free_list(xfs_sharelist_t *list) 8866185db85Sdougm { 8876185db85Sdougm xfs_sharelist_t *entry; 8886185db85Sdougm for (entry = list; entry != NULL; entry = list) { 8896185db85Sdougm if (entry->path != NULL) 8906185db85Sdougm free(entry->path); 8916185db85Sdougm if (entry->resource != NULL) 8926185db85Sdougm free(entry->resource); 8936185db85Sdougm if (entry->fstype != NULL) 8946185db85Sdougm free(entry->fstype); 8956185db85Sdougm if (entry->options != NULL) 8966185db85Sdougm free(entry->options); 8976185db85Sdougm if (entry->description != NULL) 8986185db85Sdougm free(entry->description); 8996185db85Sdougm if (entry->origline != NULL) 9006185db85Sdougm free(entry->origline); 9016185db85Sdougm if (entry->group != NULL) 9026185db85Sdougm free(entry->group); 9036185db85Sdougm list = list->next; 9046185db85Sdougm free(entry); 9056185db85Sdougm } 9066185db85Sdougm } 9076185db85Sdougm 9086185db85Sdougm /* 9096185db85Sdougm * parse_dfstab(dfstab, root) 9106185db85Sdougm * 9116185db85Sdougm * Open and read the existing dfstab, parsing each line and adding it 9126185db85Sdougm * to the internal configuration. Make sure syntax errors, etc are 9136185db85Sdougm * preserved as comments. 9146185db85Sdougm */ 9156185db85Sdougm 9166185db85Sdougm static void 917*549ec3ffSdougm parse_dfstab(sa_handle_t handle, char *dfstab, xmlNodePtr root) 9186185db85Sdougm { 9196185db85Sdougm sa_share_t share; 9206185db85Sdougm sa_group_t group; 9216185db85Sdougm sa_group_t sgroup = NULL; 9226185db85Sdougm sa_group_t defgroup; 9236185db85Sdougm xfs_sharelist_t *head, *list; 9246185db85Sdougm int err; 9256185db85Sdougm int defined_group; 9266185db85Sdougm FILE *dfs; 9276185db85Sdougm char *oldprops; 9286185db85Sdougm 9296185db85Sdougm /* read the dfstab format file and fill in the doc tree */ 9306185db85Sdougm 9316185db85Sdougm dfs = fopen(dfstab, "r"); 9326185db85Sdougm if (dfs == NULL) { 9336185db85Sdougm return; 9346185db85Sdougm } 9356185db85Sdougm 936*549ec3ffSdougm defgroup = sa_get_group(handle, "default"); 9376185db85Sdougm 9386185db85Sdougm for (head = list = getdfstab(dfs); 9396185db85Sdougm list != NULL; 9406185db85Sdougm list = list->next) { 9416185db85Sdougm share = NULL; 9426185db85Sdougm group = NULL; 9436185db85Sdougm defined_group = 0; 9446185db85Sdougm err = 0; 9456185db85Sdougm 9466185db85Sdougm if (list->origline == NULL) { 9476185db85Sdougm /* 9486185db85Sdougm * Comment line that we will likely skip. 9496185db85Sdougm * If the line has the syntax: 9506185db85Sdougm * # error: string: string 9516185db85Sdougm * It should be preserved until manually deleted. 9526185db85Sdougm */ 9536185db85Sdougm if (list->description != NULL && 9546185db85Sdougm strncmp(list->description, "# Error: ", 9) == 0) { 9556185db85Sdougm char *line; 9566185db85Sdougm char *error; 9576185db85Sdougm char *cmd; 9586185db85Sdougm line = strdup(list->description); 9596185db85Sdougm if (line != NULL) { 9606185db85Sdougm error = line + 9; 9616185db85Sdougm cmd = strchr(error, ':'); 9626185db85Sdougm if (cmd != NULL) { 9636185db85Sdougm int len; 9646185db85Sdougm *cmd = '\0'; 9656185db85Sdougm cmd += 2; 9666185db85Sdougm len = strlen(cmd); 9676185db85Sdougm cmd[len - 1] = '\0'; 9686185db85Sdougm add_syntax_comment(root, cmd, error, 0); 9696185db85Sdougm } 9706185db85Sdougm free(line); 9716185db85Sdougm } 9726185db85Sdougm } 9736185db85Sdougm continue; 9746185db85Sdougm } 9756185db85Sdougm if (list->path != NULL && strlen(list->path) > 0 && 976*549ec3ffSdougm *list->path == '/') { 977*549ec3ffSdougm share = sa_find_share(handle, list->path); 9786185db85Sdougm if (share != NULL) 9796185db85Sdougm sgroup = sa_get_parent_group(share); 9806185db85Sdougm else 9816185db85Sdougm sgroup = NULL; 9826185db85Sdougm } else { 98324424a35Sdougm (void) printf(dgettext(TEXT_DOMAIN, 98424424a35Sdougm "No share specified in dfstab: " 9856185db85Sdougm "line %d: %s\n"), 9866185db85Sdougm list->lineno, list->origline); 9876185db85Sdougm add_syntax_comment(root, list->origline, 98824424a35Sdougm dgettext(TEXT_DOMAIN, "No share specified"), 9896185db85Sdougm 1); 9906185db85Sdougm continue; 9916185db85Sdougm } 9926185db85Sdougm if (list->group != NULL && strlen(list->group) > 0) { 993*549ec3ffSdougm group = sa_get_group(handle, list->group); 9946185db85Sdougm defined_group = 1; 9956185db85Sdougm } else { 9966185db85Sdougm group = defgroup; 9976185db85Sdougm } 9986185db85Sdougm if (defined_group && group == NULL) { 99924424a35Sdougm (void) printf(dgettext(TEXT_DOMAIN, 100024424a35Sdougm "Unknown group used in dfstab: " 10016185db85Sdougm "line %d: %s\n"), 10026185db85Sdougm list->lineno, list->origline); 10036185db85Sdougm add_syntax_comment(root, list->origline, 100424424a35Sdougm dgettext(TEXT_DOMAIN, 100524424a35Sdougm "Unknown group specified"), 1); 10066185db85Sdougm continue; 10076185db85Sdougm } 10086185db85Sdougm if (group != NULL) { 10096185db85Sdougm if (share == NULL) { 10106185db85Sdougm if (!defined_group && group == defgroup) { 10116185db85Sdougm /* this is an OK add for legacy */ 10126185db85Sdougm share = sa_add_share(defgroup, list->path, 10136185db85Sdougm SA_SHARE_PERMANENT | SA_SHARE_PARSER, 10146185db85Sdougm &err); 10156185db85Sdougm if (share != NULL) { 10166185db85Sdougm if (list->description != NULL && 10176185db85Sdougm strlen(list->description) > 0) 10186185db85Sdougm (void) sa_set_share_description(share, 10196185db85Sdougm list->description); 10206185db85Sdougm if (list->options != NULL && 10216185db85Sdougm strlen(list->options) > 0) { 10226185db85Sdougm (void) sa_parse_legacy_options(share, 10236185db85Sdougm list->options, 10246185db85Sdougm list->fstype); 10256185db85Sdougm } 10266185db85Sdougm if (list->resource != NULL) 10276185db85Sdougm (void) sa_set_share_attr(share, "resource", 10286185db85Sdougm list->resource); 10296185db85Sdougm } else { 103024424a35Sdougm (void) printf(dgettext(TEXT_DOMAIN, 103124424a35Sdougm "Error in dfstab: " 10326185db85Sdougm "line %d: %s\n"), 10336185db85Sdougm list->lineno, list->origline); 10346185db85Sdougm if (err != SA_BAD_PATH) 10356185db85Sdougm add_syntax_comment(root, list->origline, 103624424a35Sdougm dgettext(TEXT_DOMAIN, 103724424a35Sdougm "Syntax"), 1); 10386185db85Sdougm else 10396185db85Sdougm add_syntax_comment(root, list->origline, 104024424a35Sdougm dgettext(TEXT_DOMAIN, 104124424a35Sdougm "Path"), 1); 10426185db85Sdougm continue; 10436185db85Sdougm } 10446185db85Sdougm } 10456185db85Sdougm } else { 10466185db85Sdougm if (group != sgroup) { 104724424a35Sdougm (void) printf(dgettext(TEXT_DOMAIN, "Attempt to change" 10486185db85Sdougm "configuration in" 10496185db85Sdougm "dfstab: line %d: %s\n"), 10506185db85Sdougm list->lineno, list->origline); 10516185db85Sdougm add_syntax_comment(root, list->origline, 105224424a35Sdougm dgettext(TEXT_DOMAIN, 105324424a35Sdougm "Attempt to change configuration"), 105424424a35Sdougm 1); 10556185db85Sdougm continue; 10566185db85Sdougm } 10576185db85Sdougm /* its the same group but could have changed options */ 10586185db85Sdougm oldprops = sa_proto_legacy_format(list->fstype, share, 0); 10596185db85Sdougm if (oldprops != NULL) { 10606185db85Sdougm if (list->options != NULL && 10616185db85Sdougm strcmp(oldprops, list->options) != 0) { 10626185db85Sdougm sa_optionset_t opts; 10636185db85Sdougm sa_security_t secs; 10646185db85Sdougm /* possibly different values */ 10656185db85Sdougm opts = sa_get_optionset((sa_group_t)share, 10666185db85Sdougm list->fstype); 10676185db85Sdougm (void) sa_destroy_optionset(opts); 10686185db85Sdougm for (secs = sa_get_security((sa_group_t)share, 10696185db85Sdougm NULL, list->fstype); 10706185db85Sdougm secs != NULL; 10716185db85Sdougm secs = sa_get_security((sa_group_t)share, 10726185db85Sdougm NULL, list->fstype)) { 10736185db85Sdougm (void) sa_destroy_security(secs); 10746185db85Sdougm } 10756185db85Sdougm (void) sa_parse_legacy_options(share, 10766185db85Sdougm list->options, 10776185db85Sdougm list->fstype); 10786185db85Sdougm } 1079a99982a7Sdougm sa_format_free(oldprops); 10806185db85Sdougm } 10816185db85Sdougm } 10826185db85Sdougm } else { 10836185db85Sdougm /* shouldn't happen */ 10846185db85Sdougm err = SA_CONFIG_ERR; 10856185db85Sdougm } 10866185db85Sdougm 10876185db85Sdougm } 10886185db85Sdougm dfs_free_list(head); 10896185db85Sdougm } 10906185db85Sdougm 10916185db85Sdougm /* 10926185db85Sdougm * legacy_removes(group, file) 10936185db85Sdougm * 10946185db85Sdougm * Find any shares that are "missing" from the legacy file. These 10956185db85Sdougm * should be removed from the configuration since they are likely from 10966185db85Sdougm * a legacy app or the admin modified the dfstab file directly. We 10976185db85Sdougm * have to support this even if it is not the recommended way to do 10986185db85Sdougm * things. 10996185db85Sdougm */ 11006185db85Sdougm 11016185db85Sdougm static void 11026185db85Sdougm legacy_removes(sa_group_t group, char *file) 11036185db85Sdougm { 11046185db85Sdougm sa_share_t share; 11056185db85Sdougm char *path; 11066185db85Sdougm xfs_sharelist_t *list, *item; 11076185db85Sdougm FILE *dfstab; 11086185db85Sdougm 11096185db85Sdougm dfstab = fopen(file, "r"); 11106185db85Sdougm if (dfstab != NULL) { 11116185db85Sdougm list = getdfstab(dfstab); 11126185db85Sdougm (void) fclose(dfstab); 1113f345c0beSdougm retry: 11146185db85Sdougm for (share = sa_get_share(group, NULL); share != NULL; 11156185db85Sdougm share = sa_get_next_share(share)) { 11166185db85Sdougm /* now see if the share is in the dfstab file */ 11176185db85Sdougm path = sa_get_share_attr(share, "path"); 11186185db85Sdougm if (path != NULL) { 11196185db85Sdougm item = finddfsentry(list, path); 1120f345c0beSdougm sa_free_attr_string(path); 11216185db85Sdougm if (item == NULL) { 11226185db85Sdougm /* the share was removed this way */ 11236185db85Sdougm (void) sa_remove_share(share); 1124f345c0beSdougm 11256185db85Sdougm /* start over since the list was broken */ 1126f345c0beSdougm goto retry; 11276185db85Sdougm } 11286185db85Sdougm } 11296185db85Sdougm } 11306185db85Sdougm if (list != NULL) 11316185db85Sdougm dfs_free_list(list); 11326185db85Sdougm } 11336185db85Sdougm } 11346185db85Sdougm 11356185db85Sdougm /* 11366185db85Sdougm * getlegacyconfig(path, root) 11376185db85Sdougm * 11386185db85Sdougm * Parse dfstab and build the legacy configuration. This only gets 11396185db85Sdougm * called when a change was detected. 11406185db85Sdougm */ 11416185db85Sdougm 11426185db85Sdougm void 1143*549ec3ffSdougm getlegacyconfig(sa_handle_t handle, char *path, xmlNodePtr *root) 11446185db85Sdougm { 11456185db85Sdougm sa_group_t defgroup; 11466185db85Sdougm 11476185db85Sdougm if (root != NULL) { 11486185db85Sdougm if (*root == NULL) 11496185db85Sdougm *root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 11506185db85Sdougm if (*root != NULL) { 11516185db85Sdougm if (strcmp(path, SA_LEGACY_DFSTAB) == 0) { 11526185db85Sdougm /* 11536185db85Sdougm * walk the default shares and find anything 11546185db85Sdougm * missing. we do this first to make sure it 11556185db85Sdougm * is cleaned up since there may be legacy 11566185db85Sdougm * code add/del via dfstab and we need to 11576185db85Sdougm * cleanup SMF. 11586185db85Sdougm */ 1159*549ec3ffSdougm defgroup = sa_get_group(handle, "default"); 11606185db85Sdougm if (defgroup != NULL) { 11616185db85Sdougm legacy_removes(defgroup, path); 11626185db85Sdougm } 11636185db85Sdougm /* parse the dfstab and add anything new */ 1164*549ec3ffSdougm parse_dfstab(handle, path, *root); 11656185db85Sdougm } 11666185db85Sdougm } 11676185db85Sdougm } 11686185db85Sdougm } 11696185db85Sdougm 11701cea05afSdougm /* 11711cea05afSdougm * get_share_list(&err) 11721cea05afSdougm * 11731cea05afSdougm * Get a linked list of all the shares on the system from 11741cea05afSdougm * /etc/dfs/sharetab. This is partially copied from libfsmgt which we 11751cea05afSdougm * can't use due to package dependencies. 11761cea05afSdougm */ 11771cea05afSdougm static xfs_sharelist_t * 11781cea05afSdougm get_share_list(int *errp) 11791cea05afSdougm { 11801cea05afSdougm xfs_sharelist_t *newp; 11811cea05afSdougm xfs_sharelist_t *headp; 11821cea05afSdougm xfs_sharelist_t *tailp; 11831cea05afSdougm FILE *fp; 11841cea05afSdougm 11851cea05afSdougm headp = NULL; 11861cea05afSdougm tailp = NULL; 11871cea05afSdougm 11881cea05afSdougm if ((fp = fopen(SHARETAB, "r")) != NULL) { 11891cea05afSdougm struct share *sharetab_entry; 1190a99982a7Sdougm (void) lockf(fileno(fp), F_LOCK, 0); 11911cea05afSdougm 11921cea05afSdougm while (getshare(fp, &sharetab_entry) > 0) { 11931cea05afSdougm newp = alloc_sharelist(); 11941cea05afSdougm if (newp == NULL) { 11951cea05afSdougm goto err; 11961cea05afSdougm } 11971cea05afSdougm 11981cea05afSdougm /* 11991cea05afSdougm * link into the list here so we don't leak 12001cea05afSdougm * memory on a failure from strdup(). 12011cea05afSdougm */ 12021cea05afSdougm if (headp == NULL) { 12031cea05afSdougm headp = newp; 12041cea05afSdougm tailp = newp; 12051cea05afSdougm } else { 12061cea05afSdougm tailp->next = newp; 12071cea05afSdougm tailp = newp; 12081cea05afSdougm } 12091cea05afSdougm 12101cea05afSdougm newp->path = strdup(sharetab_entry->sh_path); 12111cea05afSdougm if (newp->path == NULL) 12121cea05afSdougm goto err; 12131cea05afSdougm newp->resource = strdup(sharetab_entry->sh_res); 12141cea05afSdougm if (newp->resource == NULL) 12151cea05afSdougm goto err; 12161cea05afSdougm newp->fstype = strdup(sharetab_entry->sh_fstype); 12171cea05afSdougm if (newp->fstype == NULL) 12181cea05afSdougm goto err; 12191cea05afSdougm newp->options = strdup(sharetab_entry->sh_opts); 12201cea05afSdougm if (newp->options == NULL) 12211cea05afSdougm goto err; 12221cea05afSdougm newp->description = strdup(sharetab_entry->sh_descr); 12231cea05afSdougm if (newp->description == NULL) 12241cea05afSdougm goto err; 12251cea05afSdougm } 1226a99982a7Sdougm (void) lockf(fileno(fp), F_ULOCK, 0); 12271cea05afSdougm (void) fclose(fp); 12281cea05afSdougm } else { 12291cea05afSdougm *errp = errno; 12301cea05afSdougm } 12311cea05afSdougm 12321cea05afSdougm /* 12331cea05afSdougm * Caller must free the mount list 12341cea05afSdougm */ 12351cea05afSdougm return (headp); 12361cea05afSdougm err: 12371cea05afSdougm /* 12381cea05afSdougm * Out of memory so cleanup and leave. 12391cea05afSdougm */ 12401cea05afSdougm dfs_free_list(headp); 12411cea05afSdougm (void) fclose(fp); 12421cea05afSdougm return (NULL); 12431cea05afSdougm } 12441cea05afSdougm 12456185db85Sdougm /* 1246*549ec3ffSdougm * parse_sharetab(handle) 12476185db85Sdougm * 12481cea05afSdougm * Read the /etc/dfs/sharetab file and see which entries don't exist 12491cea05afSdougm * in the repository. These shares are marked transient. We also need 12501cea05afSdougm * to see if they are ZFS shares since ZFS bypasses the SMF 12511cea05afSdougm * repository. 12526185db85Sdougm */ 12536185db85Sdougm 12546185db85Sdougm int 1255*549ec3ffSdougm parse_sharetab(sa_handle_t handle) 12566185db85Sdougm { 12571cea05afSdougm xfs_sharelist_t *list, *tmplist; 12586185db85Sdougm int err = 0; 12596185db85Sdougm sa_share_t share; 12606185db85Sdougm sa_group_t group; 12616185db85Sdougm sa_group_t lgroup; 12626185db85Sdougm char *groupname; 12636185db85Sdougm int legacy = 0; 12646185db85Sdougm 12651cea05afSdougm list = get_share_list(&err); 12666185db85Sdougm if (list == NULL) 12676185db85Sdougm return (legacy); 12686185db85Sdougm 1269*549ec3ffSdougm lgroup = sa_get_group(handle, "default"); 12706185db85Sdougm 12716185db85Sdougm for (tmplist = list; tmplist != NULL; tmplist = tmplist->next) { 12726185db85Sdougm group = NULL; 1273*549ec3ffSdougm share = sa_find_share(handle, tmplist->path); 12746185db85Sdougm if (share == NULL) { 12756185db85Sdougm /* 12766185db85Sdougm * this share is transient so needs to be 12776185db85Sdougm * added. Initially, this will be under 12786185db85Sdougm * default(legacy) unless it is a ZFS 12796185db85Sdougm * share. If zfs, we need a zfs group. 12806185db85Sdougm */ 12816185db85Sdougm if (tmplist->resource != NULL && 12826185db85Sdougm (groupname = strchr(tmplist->resource, '@')) != NULL) { 12836185db85Sdougm /* there is a defined group */ 12846185db85Sdougm *groupname++ = '\0'; 1285*549ec3ffSdougm group = sa_get_group(handle, groupname); 12866185db85Sdougm if (group != NULL) { 12876185db85Sdougm share = _sa_add_share(group, tmplist->path, 12886185db85Sdougm SA_SHARE_TRANSIENT, &err); 12896185db85Sdougm } else { 129093a6f655Sdougm /* 129193a6f655Sdougm * While this case shouldn't occur very often, 129293a6f655Sdougm * it does occur out of a "zfs set 129393a6f655Sdougm * sharenfs=off" when the dataset is also set 129493a6f655Sdougm * to canmount=off. A warning will then cause 129593a6f655Sdougm * the zfs command to abort. Since we add it 129693a6f655Sdougm * to the default list, everything works 129793a6f655Sdougm * properly anyway and the library doesn't 129893a6f655Sdougm * need to give a warning. 129993a6f655Sdougm */ 13006185db85Sdougm share = _sa_add_share(lgroup, tmplist->path, 13016185db85Sdougm SA_SHARE_TRANSIENT, &err); 13026185db85Sdougm } 13036185db85Sdougm } else { 1304*549ec3ffSdougm if (sa_zfs_is_shared(handle, tmplist->path)) { 1305*549ec3ffSdougm group = sa_get_group(handle, "zfs"); 13066185db85Sdougm if (group == NULL) { 1307*549ec3ffSdougm group = sa_create_group(handle, "zfs", &err); 13086185db85Sdougm if (group == NULL && err == SA_NO_PERMISSION) { 1309*549ec3ffSdougm group = _sa_create_group( 1310*549ec3ffSdougm (sa_handle_impl_t)handle, 1311*549ec3ffSdougm "zfs"); 13126185db85Sdougm } 13136185db85Sdougm if (group != NULL) { 13146185db85Sdougm (void) sa_create_optionset(group, 13156185db85Sdougm tmplist->fstype); 13166185db85Sdougm (void) sa_set_group_attr(group, "zfs", "true"); 13176185db85Sdougm } 13186185db85Sdougm } 13196185db85Sdougm if (group != NULL) { 13206185db85Sdougm share = _sa_add_share(group, tmplist->path, 13216185db85Sdougm SA_SHARE_TRANSIENT, &err); 13226185db85Sdougm } 13236185db85Sdougm } else { 13246185db85Sdougm share = _sa_add_share(lgroup, tmplist->path, 13256185db85Sdougm SA_SHARE_TRANSIENT, &err); 13266185db85Sdougm } 13276185db85Sdougm } 13286185db85Sdougm if (share == NULL) 132924424a35Sdougm (void) printf(dgettext(TEXT_DOMAIN, 133024424a35Sdougm "Problem with transient: %s\n"), 13316185db85Sdougm sa_errorstr(err)); 13326185db85Sdougm if (share != NULL) 13336185db85Sdougm set_node_attr(share, "shared", "true"); 13346185db85Sdougm 13356185db85Sdougm if (err == SA_OK) { 13366185db85Sdougm if (tmplist->options != NULL && 13376185db85Sdougm strlen(tmplist->options) > 0) { 13386185db85Sdougm (void) sa_parse_legacy_options(share, 13396185db85Sdougm tmplist->options, 13406185db85Sdougm tmplist->fstype); 13416185db85Sdougm } 13426185db85Sdougm if (tmplist->resource != NULL && 13436185db85Sdougm strcmp(tmplist->resource, "-") != 0) 13446185db85Sdougm set_node_attr(share, "resource", tmplist->resource); 13456185db85Sdougm if (tmplist->description != NULL) { 13466185db85Sdougm xmlNodePtr node; 13476185db85Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, 13486185db85Sdougm (xmlChar *)"description", NULL); 13496185db85Sdougm xmlNodeSetContent(node, 13506185db85Sdougm (xmlChar *)tmplist->description); 13516185db85Sdougm } 13526185db85Sdougm legacy = 1; 13536185db85Sdougm } 13546185db85Sdougm } else { 13556185db85Sdougm /* 13566185db85Sdougm * if this is a legacy share, mark as shared so we 1357f345c0beSdougm * only update sharetab appropriately. We also keep 1358f345c0beSdougm * the sharetab options in order to display for legacy 1359f345c0beSdougm * share with no arguments. 13606185db85Sdougm */ 13616185db85Sdougm set_node_attr(share, "shared", "true"); 1362f345c0beSdougm set_node_attr(share, "shareopts", tmplist->options); 13636185db85Sdougm } 13646185db85Sdougm } 13651cea05afSdougm dfs_free_list(list); 13666185db85Sdougm return (legacy); 13676185db85Sdougm } 13686185db85Sdougm 13696185db85Sdougm /* 13706185db85Sdougm * get the transient shares from the sharetab (or other) file. since 13716185db85Sdougm * these are transient, they only appear in the working file and not 13726185db85Sdougm * in a repository. 13736185db85Sdougm */ 13746185db85Sdougm int 1375*549ec3ffSdougm gettransients(sa_handle_impl_t ihandle, xmlNodePtr *root) 13766185db85Sdougm { 13776185db85Sdougm int legacy = 0; 13786185db85Sdougm 13796185db85Sdougm if (root != NULL) { 13806185db85Sdougm if (*root == NULL) 13816185db85Sdougm *root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 13826185db85Sdougm if (*root != NULL) { 1383*549ec3ffSdougm legacy = parse_sharetab(ihandle); 13846185db85Sdougm } 13856185db85Sdougm } 13866185db85Sdougm return (legacy); 13876185db85Sdougm } 13886185db85Sdougm 13896185db85Sdougm /* 13906185db85Sdougm * sa_has_prop(optionset, prop) 13916185db85Sdougm * 13926185db85Sdougm * Is the specified property a member of the optionset? 13936185db85Sdougm */ 13946185db85Sdougm 13956185db85Sdougm int 13966185db85Sdougm sa_has_prop(sa_optionset_t optionset, sa_property_t prop) 13976185db85Sdougm { 13986185db85Sdougm char *name; 13996185db85Sdougm sa_property_t otherprop; 14006185db85Sdougm int result = 0; 14016185db85Sdougm 14026185db85Sdougm if (optionset != NULL) { 14036185db85Sdougm name = sa_get_property_attr(prop, "type"); 14046185db85Sdougm if (name != NULL) { 14056185db85Sdougm otherprop = sa_get_property(optionset, name); 14066185db85Sdougm if (otherprop != NULL) 14076185db85Sdougm result = 1; 14086185db85Sdougm sa_free_attr_string(name); 14096185db85Sdougm } 14106185db85Sdougm } 14116185db85Sdougm return (result); 14126185db85Sdougm } 14136185db85Sdougm 14146185db85Sdougm /* 14156185db85Sdougm * Update legacy files 14166185db85Sdougm * 14176185db85Sdougm * Provides functions to add/remove/modify individual entries 14186185db85Sdougm * in dfstab and sharetab 14196185db85Sdougm */ 14206185db85Sdougm 14216185db85Sdougm void 1422*549ec3ffSdougm update_legacy_config(sa_handle_t handle) 14236185db85Sdougm { 14246185db85Sdougm /* 14256185db85Sdougm * no longer used -- this is a placeholder in case we need to 14266185db85Sdougm * add it back later. 14276185db85Sdougm */ 1428*549ec3ffSdougm #ifdef lint 1429*549ec3ffSdougm handle = handle; 1430*549ec3ffSdougm #endif 14316185db85Sdougm } 14326185db85Sdougm 14336185db85Sdougm /* 14346185db85Sdougm * sa_valid_property(object, proto, property) 14356185db85Sdougm * 14366185db85Sdougm * check to see if the specified property is valid relative to the 14376185db85Sdougm * specified protocol. The protocol plugin is called to do the work. 14386185db85Sdougm */ 14396185db85Sdougm 14406185db85Sdougm int 14416185db85Sdougm sa_valid_property(void *object, char *proto, sa_property_t property) 14426185db85Sdougm { 14436185db85Sdougm int ret = SA_OK; 14446185db85Sdougm 14456185db85Sdougm if (proto != NULL && property != NULL) { 14466185db85Sdougm ret = sa_proto_valid_prop(proto, property, object); 14476185db85Sdougm } 14486185db85Sdougm 14496185db85Sdougm return (ret); 14506185db85Sdougm } 14516185db85Sdougm 14526185db85Sdougm /* 14536185db85Sdougm * sa_fstype(path) 14546185db85Sdougm * 14556185db85Sdougm * Given path, return the string representing the path's file system 14566185db85Sdougm * type. This is used to discover ZFS shares. 14576185db85Sdougm */ 14586185db85Sdougm 14596185db85Sdougm char * 14606185db85Sdougm sa_fstype(char *path) 14616185db85Sdougm { 14626185db85Sdougm int err; 14636185db85Sdougm struct stat st; 14646185db85Sdougm 14656185db85Sdougm err = stat(path, &st); 14666185db85Sdougm if (err < 0) { 14676185db85Sdougm err = SA_NO_SUCH_PATH; 14686185db85Sdougm } else { 14696185db85Sdougm err = SA_OK; 14706185db85Sdougm } 14716185db85Sdougm if (err == SA_OK) { 14726185db85Sdougm /* have a valid path at this point */ 14736185db85Sdougm return (strdup(st.st_fstype)); 14746185db85Sdougm } 14756185db85Sdougm return (NULL); 14766185db85Sdougm } 14776185db85Sdougm 14786185db85Sdougm void 14796185db85Sdougm sa_free_fstype(char *type) 14806185db85Sdougm { 14816185db85Sdougm free(type); 14826185db85Sdougm } 14836185db85Sdougm 14846185db85Sdougm /* 14856185db85Sdougm * sa_get_derived_optionset(object, proto, hier) 14866185db85Sdougm * 14876185db85Sdougm * Work backward to the top of the share object tree and start 14886185db85Sdougm * copying protocol specific optionsets into a newly created 14896185db85Sdougm * optionset that doesn't have a parent (it will be freed 14906185db85Sdougm * later). This provides for the property inheritence model. That 14916185db85Sdougm * is, properties closer to the share take precedence over group 14926185db85Sdougm * level. This also provides for groups of groups in the future. 14936185db85Sdougm */ 14946185db85Sdougm 14956185db85Sdougm sa_optionset_t 14966185db85Sdougm sa_get_derived_optionset(void *object, char *proto, int hier) 14976185db85Sdougm { 14986185db85Sdougm sa_optionset_t newoptionset; 14996185db85Sdougm sa_optionset_t optionset; 15006185db85Sdougm sa_group_t group; 15016185db85Sdougm 15026185db85Sdougm if (hier && 15036185db85Sdougm (group = sa_get_parent_group((sa_share_t)object)) != NULL) { 15046185db85Sdougm newoptionset = sa_get_derived_optionset((void *)group, proto, hier); 15056185db85Sdougm } else { 15066185db85Sdougm newoptionset = (sa_optionset_t)xmlNewNode(NULL, 15076185db85Sdougm (xmlChar *)"optionset"); 15086185db85Sdougm if (newoptionset != NULL) { 15096185db85Sdougm sa_set_optionset_attr(newoptionset, "type", proto); 15106185db85Sdougm } 15116185db85Sdougm } 15126185db85Sdougm /* dont' do anything if memory wasn't allocated */ 15136185db85Sdougm if (newoptionset == NULL) 15146185db85Sdougm return (NULL); 15156185db85Sdougm 15166185db85Sdougm /* found the top so working back down the stack */ 15176185db85Sdougm optionset = sa_get_optionset((sa_optionset_t)object, proto); 15186185db85Sdougm if (optionset != NULL) { 15196185db85Sdougm sa_property_t prop; 15206185db85Sdougm /* add optionset to the newoptionset */ 15216185db85Sdougm for (prop = sa_get_property(optionset, NULL); 15226185db85Sdougm prop != NULL; prop = sa_get_next_property(prop)) { 15236185db85Sdougm sa_property_t newprop; 15246185db85Sdougm char *name; 15256185db85Sdougm char *value; 15266185db85Sdougm name = sa_get_property_attr(prop, "type"); 15276185db85Sdougm value = sa_get_property_attr(prop, "value"); 15286185db85Sdougm if (name != NULL) { 15296185db85Sdougm newprop = sa_get_property(newoptionset, name); 15306185db85Sdougm /* replace the value with the new value */ 15316185db85Sdougm if (newprop != NULL) { 15326185db85Sdougm /* 15336185db85Sdougm * only set if value is non NULL, old value ok 15346185db85Sdougm * if it is NULL. 15356185db85Sdougm */ 15366185db85Sdougm if (value != NULL) 15376185db85Sdougm set_node_attr(newprop, "value", value); 15386185db85Sdougm } else { 15396185db85Sdougm /* an entirely new property */ 15406185db85Sdougm if (value != NULL) { 15416185db85Sdougm newprop = sa_create_property(name, value); 15426185db85Sdougm if (newprop != NULL) { 15436185db85Sdougm newprop = (sa_property_t) 15446185db85Sdougm xmlAddChild((xmlNodePtr)newoptionset, 15456185db85Sdougm (xmlNodePtr)newprop); 15466185db85Sdougm } 15476185db85Sdougm } 15486185db85Sdougm } 15496185db85Sdougm sa_free_attr_string(name); 15506185db85Sdougm } 15516185db85Sdougm if (value != NULL) 15526185db85Sdougm sa_free_attr_string(value); 15536185db85Sdougm } 15546185db85Sdougm } 15556185db85Sdougm return (newoptionset); 15566185db85Sdougm } 15576185db85Sdougm 15586185db85Sdougm void 15596185db85Sdougm sa_free_derived_optionset(sa_optionset_t optionset) 15606185db85Sdougm { 15616185db85Sdougm /* while it shouldn't be linked, it doesn't hurt */ 15626185db85Sdougm if (optionset != NULL) { 15636185db85Sdougm xmlUnlinkNode((xmlNodePtr) optionset); 15646185db85Sdougm xmlFreeNode((xmlNodePtr) optionset); 15656185db85Sdougm } 15666185db85Sdougm } 15676185db85Sdougm 15686185db85Sdougm /* 15696185db85Sdougm * sa_get_all_security_types(object, proto, hier) 15706185db85Sdougm * 15716185db85Sdougm * find all the security types set for this object. This is 15726185db85Sdougm * preliminary to getting a derived security set. The return value is an 15736185db85Sdougm * optionset containg properties which are the sectype values found by 15746185db85Sdougm * walking up the XML document struture. The returned optionset 15756185db85Sdougm * is a derived optionset. 15766185db85Sdougm * 15776185db85Sdougm * If hier is 0, only look at object. If non-zero, walk up the tree. 15786185db85Sdougm */ 15796185db85Sdougm sa_optionset_t 15806185db85Sdougm sa_get_all_security_types(void *object, char *proto, int hier) 15816185db85Sdougm { 15826185db85Sdougm sa_optionset_t options; 15836185db85Sdougm sa_security_t security; 15846185db85Sdougm sa_group_t group; 15856185db85Sdougm sa_property_t prop; 15866185db85Sdougm 15876185db85Sdougm options = NULL; 15886185db85Sdougm 15896185db85Sdougm if (hier && 15906185db85Sdougm (group = sa_get_parent_group((sa_share_t)object)) != NULL) { 15916185db85Sdougm options = sa_get_all_security_types((void *)group, proto, hier); 15926185db85Sdougm } else { 15936185db85Sdougm options = (sa_optionset_t)xmlNewNode(NULL, 15946185db85Sdougm (xmlChar *)"optionset"); 15956185db85Sdougm } 15966185db85Sdougm /* hit the top so collect the security types working back */ 15976185db85Sdougm if (options != NULL) { 15986185db85Sdougm for (security = sa_get_security((sa_group_t)object, NULL, NULL); 15996185db85Sdougm security != NULL; security = sa_get_next_security(security)) { 16006185db85Sdougm char *type; 16016185db85Sdougm char *sectype; 16026185db85Sdougm 16036185db85Sdougm type = sa_get_security_attr(security, "type"); 16046185db85Sdougm if (type != NULL) { 16056185db85Sdougm if (strcmp(type, proto) != 0) { 16066185db85Sdougm sa_free_attr_string(type); 16076185db85Sdougm continue; 16086185db85Sdougm } 16096185db85Sdougm sectype = sa_get_security_attr(security, "sectype"); 16106185db85Sdougm if (sectype != NULL) { 16116185db85Sdougm /* 16126185db85Sdougm * have a security type, check to see if 16136185db85Sdougm * already present in optionset and add if it 16146185db85Sdougm * isn't. 16156185db85Sdougm */ 16166185db85Sdougm if (sa_get_property(options, sectype) == NULL) { 16176185db85Sdougm prop = sa_create_property(sectype, "true"); 16186185db85Sdougm if (prop != NULL) 16196185db85Sdougm prop = (sa_property_t) 16206185db85Sdougm xmlAddChild((xmlNodePtr)options, 16216185db85Sdougm (xmlNodePtr)prop); 16226185db85Sdougm } 16236185db85Sdougm sa_free_attr_string(sectype); 16246185db85Sdougm } 16256185db85Sdougm sa_free_attr_string(type); 16266185db85Sdougm } 16276185db85Sdougm } 16286185db85Sdougm } 16296185db85Sdougm return (options); 16306185db85Sdougm } 16316185db85Sdougm 16326185db85Sdougm /* 16336185db85Sdougm * sa_get_derived_security(object, sectype, proto, hier) 16346185db85Sdougm * 16356185db85Sdougm * Get the derived security(named optionset) for the object given the 16366185db85Sdougm * sectype and proto. If hier is non-zero, walk up the tree to get all 16376185db85Sdougm * properties defined for this object, otherwise just those on the 16386185db85Sdougm * object. 16396185db85Sdougm */ 16406185db85Sdougm 16416185db85Sdougm sa_security_t 16426185db85Sdougm sa_get_derived_security(void *object, char *sectype, char *proto, int hier) 16436185db85Sdougm { 16446185db85Sdougm sa_security_t newsecurity; 16456185db85Sdougm sa_security_t security; 16466185db85Sdougm sa_group_t group; 16476185db85Sdougm 16486185db85Sdougm if (hier && 16496185db85Sdougm (group = sa_get_parent_group((sa_share_t)object)) != NULL) { 16506185db85Sdougm newsecurity = sa_get_derived_security((void *)group, 16516185db85Sdougm sectype, proto, hier); 16526185db85Sdougm } else { 16536185db85Sdougm newsecurity = (sa_security_t)xmlNewNode(NULL, 16546185db85Sdougm (xmlChar *)"security"); 16556185db85Sdougm if (newsecurity != NULL) { 16566185db85Sdougm sa_set_security_attr(newsecurity, "type", proto); 16576185db85Sdougm sa_set_security_attr(newsecurity, "sectype", sectype); 16586185db85Sdougm } 16596185db85Sdougm } 16606185db85Sdougm /* dont' do anything if memory wasn't allocated */ 16616185db85Sdougm if (newsecurity == NULL) 16626185db85Sdougm return (NULL); 16636185db85Sdougm 16646185db85Sdougm /* found the top so working back down the stack */ 16656185db85Sdougm security = sa_get_security((sa_security_t)object, sectype, proto); 16666185db85Sdougm if (security != NULL) { 16676185db85Sdougm sa_property_t prop; 16686185db85Sdougm /* add security to the newsecurity */ 16696185db85Sdougm for (prop = sa_get_property(security, NULL); 16706185db85Sdougm prop != NULL; prop = sa_get_next_property(prop)) { 16716185db85Sdougm sa_property_t newprop; 16726185db85Sdougm char *name; 16736185db85Sdougm char *value; 16746185db85Sdougm name = sa_get_property_attr(prop, "type"); 16756185db85Sdougm value = sa_get_property_attr(prop, "value"); 16766185db85Sdougm if (name != NULL) { 16776185db85Sdougm newprop = sa_get_property(newsecurity, name); 16786185db85Sdougm /* replace the value with the new value */ 16796185db85Sdougm if (newprop != NULL) { 16806185db85Sdougm /* 16816185db85Sdougm * only set if value is non NULL, old value ok 16826185db85Sdougm * if it is NULL. 16836185db85Sdougm */ 16846185db85Sdougm if (value != NULL) 16856185db85Sdougm set_node_attr(newprop, name, value); 16866185db85Sdougm } else { 16876185db85Sdougm /* an entirely new property */ 16886185db85Sdougm if (value != NULL) { 16896185db85Sdougm newprop = sa_create_property(name, value); 16906185db85Sdougm newprop = (sa_property_t) 16916185db85Sdougm xmlAddChild((xmlNodePtr)newsecurity, 16926185db85Sdougm (xmlNodePtr)newprop); 16936185db85Sdougm } 16946185db85Sdougm } 16956185db85Sdougm sa_free_attr_string(name); 16966185db85Sdougm } 16976185db85Sdougm if (value != NULL) 16986185db85Sdougm sa_free_attr_string(value); 16996185db85Sdougm } 17006185db85Sdougm } 17016185db85Sdougm return (newsecurity); 17026185db85Sdougm } 17036185db85Sdougm 17046185db85Sdougm void 17056185db85Sdougm sa_free_derived_security(sa_security_t security) 17066185db85Sdougm { 17076185db85Sdougm /* while it shouldn't be linked, it doesn't hurt */ 17086185db85Sdougm if (security != NULL) { 17096185db85Sdougm xmlUnlinkNode((xmlNodePtr)security); 17106185db85Sdougm xmlFreeNode((xmlNodePtr)security); 17116185db85Sdougm } 17126185db85Sdougm } 17136185db85Sdougm 17146185db85Sdougm /* 17156185db85Sdougm * sharetab utility functions 17166185db85Sdougm * 17176185db85Sdougm * makes use of the original sharetab.c from fs.d/nfs/lib 17186185db85Sdougm */ 17196185db85Sdougm 17206185db85Sdougm /* 17216185db85Sdougm * fillshare(share, proto, sh) 17226185db85Sdougm * 17236185db85Sdougm * Fill the struct share with values obtained from the share object. 17246185db85Sdougm */ 17256185db85Sdougm static void 17266185db85Sdougm fillshare(sa_share_t share, char *proto, struct share *sh) 17276185db85Sdougm { 17286185db85Sdougm char *groupname = NULL; 17296185db85Sdougm char *value; 17306185db85Sdougm sa_group_t group; 17316185db85Sdougm char *buff; 17326185db85Sdougm char *zfs; 17336185db85Sdougm 17346185db85Sdougm group = sa_get_parent_group(share); 17356185db85Sdougm if (group != NULL) { 17366185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 17376185db85Sdougm groupname = sa_get_group_attr(group, "name"); 17386185db85Sdougm 17396185db85Sdougm if (groupname != NULL && 17406185db85Sdougm (strcmp(groupname, "default") == 0 || zfs != NULL)) { 17416185db85Sdougm /* 17426185db85Sdougm * since the groupname is either "default" or the 17436185db85Sdougm * group is a ZFS group, we don't want to keep 17446185db85Sdougm * groupname. We do want it if it is any other type of 17456185db85Sdougm * group. 17466185db85Sdougm */ 17476185db85Sdougm sa_free_attr_string(groupname); 17486185db85Sdougm groupname = NULL; 17496185db85Sdougm } 17506185db85Sdougm if (zfs != NULL) 17516185db85Sdougm sa_free_attr_string(zfs); 17526185db85Sdougm } 17536185db85Sdougm 17546185db85Sdougm value = sa_get_share_attr(share, "path"); 17556185db85Sdougm if (value != NULL) { 17566185db85Sdougm sh->sh_path = strdup(value); 17576185db85Sdougm sa_free_attr_string(value); 17586185db85Sdougm } 17596185db85Sdougm 17606185db85Sdougm value = sa_get_share_attr(share, "resource"); 17616185db85Sdougm if (value != NULL || groupname != NULL) { 17626185db85Sdougm int len = 0; 17636185db85Sdougm 17646185db85Sdougm if (value != NULL) 17656185db85Sdougm len += strlen(value); 17666185db85Sdougm if (groupname != NULL) 17676185db85Sdougm len += strlen(groupname); 17686185db85Sdougm len += 3; /* worst case */ 17696185db85Sdougm buff = malloc(len); 17706185db85Sdougm (void) snprintf(buff, len, "%s%s%s", 17716185db85Sdougm (value != NULL && strlen(value) > 0) ? value : "-", 17726185db85Sdougm groupname != NULL ? "@" : "", 17736185db85Sdougm groupname != NULL ? groupname : ""); 17746185db85Sdougm sh->sh_res = buff; 17756185db85Sdougm if (value != NULL) 17766185db85Sdougm sa_free_attr_string(value); 17776185db85Sdougm if (groupname != NULL) { 17786185db85Sdougm sa_free_attr_string(groupname); 17796185db85Sdougm groupname = NULL; 17806185db85Sdougm } 17816185db85Sdougm } else { 17826185db85Sdougm sh->sh_res = strdup("-"); 17836185db85Sdougm } 17846185db85Sdougm 17856185db85Sdougm sh->sh_fstype = strdup(proto); 17866185db85Sdougm value = sa_proto_legacy_format(proto, share, 1); 17876185db85Sdougm if (value != NULL) { 17886185db85Sdougm if (strlen(value) > 0) 17896185db85Sdougm sh->sh_opts = strdup(value); 17906185db85Sdougm else 17916185db85Sdougm sh->sh_opts = strdup("rw"); 17926185db85Sdougm free(value); 17936185db85Sdougm } else 17946185db85Sdougm sh->sh_opts = strdup("rw"); 17956185db85Sdougm 17966185db85Sdougm value = sa_get_share_description(share); 17976185db85Sdougm if (value != NULL) { 17986185db85Sdougm sh->sh_descr = strdup(value); 17996185db85Sdougm sa_free_share_description(value); 18006185db85Sdougm } else 18016185db85Sdougm sh->sh_descr = strdup(""); 18026185db85Sdougm } 18036185db85Sdougm 18046185db85Sdougm /* 18056185db85Sdougm * emptyshare(sh) 18066185db85Sdougm * 18076185db85Sdougm * Free the strings in the non-NULL members of sh. 18086185db85Sdougm */ 18096185db85Sdougm 18106185db85Sdougm static void 18116185db85Sdougm emptyshare(struct share *sh) 18126185db85Sdougm { 18136185db85Sdougm if (sh->sh_path != NULL) 18146185db85Sdougm free(sh->sh_path); 18156185db85Sdougm sh->sh_path = NULL; 18166185db85Sdougm if (sh->sh_res != NULL) 18176185db85Sdougm free(sh->sh_res); 18186185db85Sdougm sh->sh_res = NULL; 18196185db85Sdougm if (sh->sh_fstype != NULL) 18206185db85Sdougm free(sh->sh_fstype); 18216185db85Sdougm sh->sh_fstype = NULL; 18226185db85Sdougm if (sh->sh_opts != NULL) 18236185db85Sdougm free(sh->sh_opts); 18246185db85Sdougm sh->sh_opts = NULL; 18256185db85Sdougm if (sh->sh_descr != NULL) 18266185db85Sdougm free(sh->sh_descr); 18276185db85Sdougm sh->sh_descr = NULL; 18286185db85Sdougm } 18296185db85Sdougm 1830a99982a7Sdougm /* 1831a99982a7Sdougm * checkshare(struct share *) 1832a99982a7Sdougm * 1833a99982a7Sdougm * If the share to write to sharetab is not present, need to add. If 1834a99982a7Sdougm * the share is present, replace if options are different else we want 1835a99982a7Sdougm * to keep it. 1836a99982a7Sdougm * Return values: 1837a99982a7Sdougm * 1 - keep 1838a99982a7Sdougm * 2 - replace 1839a99982a7Sdougm * The CHK_NEW value isn't currently returned. 1840a99982a7Sdougm */ 1841a99982a7Sdougm #define CHK_NEW 0 1842a99982a7Sdougm #define CHK_KEEP 1 1843a99982a7Sdougm #define CHK_REPLACE 2 1844a99982a7Sdougm static int 1845a99982a7Sdougm checkshare(struct share *sh) 1846a99982a7Sdougm { 1847a99982a7Sdougm xfs_sharelist_t *list, *head; 1848a99982a7Sdougm int err; 1849a99982a7Sdougm int ret = CHK_NEW; 1850a99982a7Sdougm 1851a99982a7Sdougm head = list = get_share_list(&err); 1852a99982a7Sdougm while (list != NULL && ret == CHK_NEW) { 1853a99982a7Sdougm if (strcmp(sh->sh_path, list->path) == 0) { 1854a99982a7Sdougm /* Have the same path so check if replace or keep */ 1855a99982a7Sdougm if (strcmp(sh->sh_opts, list->options) == 0) 1856a99982a7Sdougm ret = CHK_KEEP; 1857a99982a7Sdougm else 1858a99982a7Sdougm ret = CHK_REPLACE; 1859a99982a7Sdougm } 1860a99982a7Sdougm list = list->next; 1861a99982a7Sdougm } 1862a99982a7Sdougm if (head != NULL) { 1863a99982a7Sdougm dfs_free_list(head); 1864a99982a7Sdougm } 1865a99982a7Sdougm /* 1866a99982a7Sdougm * Just in case it was added by another process after our 1867a99982a7Sdougm * scan, we always replace even if we think it is new. 1868a99982a7Sdougm */ 1869a99982a7Sdougm if (ret == CHK_NEW) 1870a99982a7Sdougm ret = CHK_REPLACE; 1871a99982a7Sdougm return (ret); 1872a99982a7Sdougm } 1873a99982a7Sdougm 18746185db85Sdougm /* 18756185db85Sdougm * sa_update_sharetab(share, proto) 18766185db85Sdougm * 18776185db85Sdougm * Update the sharetab file with info from the specified share. 18786185db85Sdougm * This could be an update or add. 18796185db85Sdougm */ 18806185db85Sdougm 18816185db85Sdougm int 18826185db85Sdougm sa_update_sharetab(sa_share_t share, char *proto) 18836185db85Sdougm { 18846185db85Sdougm int ret = SA_OK; 18856185db85Sdougm struct share shtab; 18866185db85Sdougm char *path; 18876185db85Sdougm int logging = 0; 18886185db85Sdougm FILE *sharetab; 1889a99982a7Sdougm sigset_t old; 1890a99982a7Sdougm int action; 18916185db85Sdougm 18926185db85Sdougm path = sa_get_share_attr(share, "path"); 18936185db85Sdougm if (path != NULL) { 18946185db85Sdougm (void) memset(&shtab, '\0', sizeof (shtab)); 18956185db85Sdougm sharetab = fopen(SA_LEGACY_SHARETAB, "r+"); 18966185db85Sdougm if (sharetab == NULL) { 18976185db85Sdougm sharetab = fopen(SA_LEGACY_SHARETAB, "w+"); 18986185db85Sdougm } 18996185db85Sdougm if (sharetab != NULL) { 19006185db85Sdougm (void) setvbuf(sharetab, NULL, _IOLBF, BUFSIZ * 8); 1901a99982a7Sdougm sablocksigs(&old); 1902a99982a7Sdougm /* 1903a99982a7Sdougm * Fill in share structure and write it out if the 1904a99982a7Sdougm * share isn't already shared with the same options. 1905a99982a7Sdougm */ 19066185db85Sdougm (void) fillshare(share, proto, &shtab); 1907a99982a7Sdougm /* 1908a99982a7Sdougm * If share is new or changed, remove the old, 1909a99982a7Sdougm * otherwise keep it in place since it hasn't changed. 1910a99982a7Sdougm */ 1911a99982a7Sdougm action = checkshare(&shtab); 1912a99982a7Sdougm (void) lockf(fileno(sharetab), F_LOCK, 0); 1913a99982a7Sdougm switch (action) { 1914a99982a7Sdougm case CHK_REPLACE: 1915a99982a7Sdougm (void) remshare(sharetab, path, &logging); 1916a99982a7Sdougm (void) putshare(sharetab, &shtab); 1917a99982a7Sdougm break; 1918a99982a7Sdougm case CHK_KEEP: 1919a99982a7Sdougm /* Don't do anything */ 1920a99982a7Sdougm break; 1921a99982a7Sdougm } 19226185db85Sdougm emptyshare(&shtab); 19236185db85Sdougm (void) fflush(sharetab); 19246185db85Sdougm (void) lockf(fileno(sharetab), F_ULOCK, 0); 19256185db85Sdougm (void) fsync(fileno(sharetab)); 1926a99982a7Sdougm saunblocksigs(&old); 19276185db85Sdougm (void) fclose(sharetab); 19286185db85Sdougm } else { 19296185db85Sdougm if (errno == EACCES || errno == EPERM) { 19306185db85Sdougm ret = SA_NO_PERMISSION; 19316185db85Sdougm } else { 19326185db85Sdougm ret = SA_CONFIG_ERR; 19336185db85Sdougm } 19346185db85Sdougm } 19356185db85Sdougm sa_free_attr_string(path); 19366185db85Sdougm } 19376185db85Sdougm return (ret); 19386185db85Sdougm } 19396185db85Sdougm 19406185db85Sdougm /* 19416185db85Sdougm * sa_delete_sharetab(path, proto) 19426185db85Sdougm * 19436185db85Sdougm * remove the specified share from sharetab. 19446185db85Sdougm */ 19456185db85Sdougm 19466185db85Sdougm int 19476185db85Sdougm sa_delete_sharetab(char *path, char *proto) 19486185db85Sdougm { 19496185db85Sdougm int ret = SA_OK; 19506185db85Sdougm int logging = 0; 19516185db85Sdougm FILE *sharetab; 1952a99982a7Sdougm sigset_t old; 19536185db85Sdougm #ifdef lint 19546185db85Sdougm proto = proto; 19556185db85Sdougm #endif 19566185db85Sdougm 19576185db85Sdougm if (path != NULL) { 19586185db85Sdougm sharetab = fopen(SA_LEGACY_SHARETAB, "r+"); 19596185db85Sdougm if (sharetab == NULL) { 19606185db85Sdougm sharetab = fopen(SA_LEGACY_SHARETAB, "w+"); 19616185db85Sdougm } 19626185db85Sdougm if (sharetab != NULL) { 19636185db85Sdougm /* should block keyboard level signals around the lock */ 1964a99982a7Sdougm sablocksigs(&old); 19656185db85Sdougm (void) lockf(fileno(sharetab), F_LOCK, 0); 19666185db85Sdougm ret = remshare(sharetab, path, &logging); 19676185db85Sdougm (void) fflush(sharetab); 19686185db85Sdougm (void) lockf(fileno(sharetab), F_ULOCK, 0); 19696185db85Sdougm (void) fsync(fileno(sharetab)); 1970a99982a7Sdougm saunblocksigs(&old); 19716185db85Sdougm (void) fclose(sharetab); 19726185db85Sdougm } else { 19736185db85Sdougm if (errno == EACCES || errno == EPERM) { 19746185db85Sdougm ret = SA_NO_PERMISSION; 19756185db85Sdougm } else { 19766185db85Sdougm ret = SA_CONFIG_ERR; 19776185db85Sdougm } 19786185db85Sdougm } 19796185db85Sdougm } 19806185db85Sdougm return (ret); 19816185db85Sdougm } 1982