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 /* 23*f345c0beSdougm * 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; 856185db85Sdougm static void parse_dfstab(char *, xmlNodePtr); 866185db85Sdougm extern char *get_token(char *); 876185db85Sdougm static void dfs_free_list(xfs_sharelist_t *); 886185db85Sdougm /* prototypes */ 896185db85Sdougm void getlegacyconfig(char *, xmlNodePtr *); 906185db85Sdougm extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *); 916185db85Sdougm extern xmlNodePtr _sa_get_next_error(xmlNodePtr); 926185db85Sdougm extern sa_group_t _sa_create_group(char *); 936185db85Sdougm static void outdfstab(FILE *, xfs_sharelist_t *); 946185db85Sdougm extern int _sa_remove_optionset(sa_optionset_t); 956185db85Sdougm extern int set_node_share(void *, char *, char *); 966185db85Sdougm extern void set_node_attr(void *, char *, char *); 976185db85Sdougm 986185db85Sdougm /* 996185db85Sdougm * alloc_sharelist() 1006185db85Sdougm * 1016185db85Sdougm * allocator function to return an zfs_sharelist_t 1026185db85Sdougm */ 1036185db85Sdougm 1046185db85Sdougm static xfs_sharelist_t * 1056185db85Sdougm alloc_sharelist() 1066185db85Sdougm { 1076185db85Sdougm xfs_sharelist_t *item; 1086185db85Sdougm 1096185db85Sdougm item = (xfs_sharelist_t *)malloc(sizeof (xfs_sharelist_t)); 1106185db85Sdougm if (item != NULL) 1116185db85Sdougm (void) memset(item, '\0', sizeof (xfs_sharelist_t)); 1126185db85Sdougm return (item); 1136185db85Sdougm } 1146185db85Sdougm 1156185db85Sdougm /* 1166185db85Sdougm * fix_notice(list) 1176185db85Sdougm * 1186185db85Sdougm * Look at the beginning of the current /etc/dfs/dfstab file and add 1196185db85Sdougm * the do not modify notice if it doesn't exist. 1206185db85Sdougm */ 1216185db85Sdougm 1226185db85Sdougm static xfs_sharelist_t * 1236185db85Sdougm fix_notice(xfs_sharelist_t *list) 1246185db85Sdougm { 1256185db85Sdougm xfs_sharelist_t *item, *prev; 1266185db85Sdougm int i; 1276185db85Sdougm 1287d968cb8Sdougm if (list == NULL) { 1297d968cb8Sdougm /* zero length dfstab */ 1307d968cb8Sdougm list = alloc_sharelist(); 1317d968cb8Sdougm if (list == NULL) 1327d968cb8Sdougm return (NULL); 1337d968cb8Sdougm list->description = strdup("#\n"); 1347d968cb8Sdougm } 1356185db85Sdougm if (list->path == NULL && list->description != NULL && 1366185db85Sdougm strcmp(list->description, notice[0]) != 0) { 1376185db85Sdougm for (prev = NULL, i = 0; i < DFSTAB_NOTICE_LINES; i++) { 1386185db85Sdougm item = alloc_sharelist(); 1396185db85Sdougm if (item != NULL) { 1406185db85Sdougm item->description = strdup(notice[i]); 1416185db85Sdougm if (prev == NULL) { 1426185db85Sdougm item->next = list; 1436185db85Sdougm prev = item; 1446185db85Sdougm list = item; 1456185db85Sdougm } else { 1466185db85Sdougm item->next = prev->next; 1476185db85Sdougm prev->next = item; 1486185db85Sdougm prev = item; 1496185db85Sdougm } 1506185db85Sdougm } 1516185db85Sdougm } 1526185db85Sdougm } 1536185db85Sdougm return (list); 1546185db85Sdougm } 1556185db85Sdougm 1566185db85Sdougm /* 1576185db85Sdougm * getdfstab(dfs) 1586185db85Sdougm * 1596185db85Sdougm * Returns an zfs_sharelist_t list of lines from the dfstab file 1606185db85Sdougm * pointed to by the FILE pointer dfs. Each entry is parsed and the 1616185db85Sdougm * original line is also preserved. Used in parsing and updating the 1626185db85Sdougm * dfstab file. 1636185db85Sdougm */ 1646185db85Sdougm 1656185db85Sdougm static xfs_sharelist_t * 1666185db85Sdougm getdfstab(FILE *dfs) 1676185db85Sdougm { 1686185db85Sdougm char buff[_POSIX_ARG_MAX]; /* reasonable size given syntax of share */ 1696185db85Sdougm char *bp; 1706185db85Sdougm char *token; 1716185db85Sdougm char *args[MAXARGSFORSHARE]; 1726185db85Sdougm int argc; 1736185db85Sdougm int c; 1746185db85Sdougm static int line = 0; 1757d968cb8Sdougm xfs_sharelist_t *item = NULL, *first = NULL, *last; 1766185db85Sdougm 1776185db85Sdougm if (dfs != NULL) { 1786185db85Sdougm first = NULL; 1796185db85Sdougm line = 0; 1806185db85Sdougm while (fgets(buff, sizeof (buff), dfs) != NULL) { 1816185db85Sdougm line++; 1826185db85Sdougm bp = buff; 1836185db85Sdougm if (buff[0] == '#') { 1846185db85Sdougm item = alloc_sharelist(); 1856185db85Sdougm if (item != NULL) { 1866185db85Sdougm /* if no path, then comment */ 1876185db85Sdougm item->lineno = line; 1886185db85Sdougm item->description = strdup(buff); 1896185db85Sdougm if (first == NULL) { 1906185db85Sdougm first = item; 1916185db85Sdougm last = item; 1926185db85Sdougm } else { 1936185db85Sdougm last->next = item; 1946185db85Sdougm last = item; 1956185db85Sdougm } 1966185db85Sdougm } else { 1976185db85Sdougm break; 1986185db85Sdougm } 1996185db85Sdougm continue; 2006185db85Sdougm } else if (buff[0] == '\n') { 2016185db85Sdougm continue; 2026185db85Sdougm } 2036185db85Sdougm optind = 1; 2046185db85Sdougm item = alloc_sharelist(); 2056185db85Sdougm if (item == NULL) { 2066185db85Sdougm break; 2076185db85Sdougm } else if (first == NULL) { 2086185db85Sdougm first = item; 2096185db85Sdougm last = item; 2106185db85Sdougm } else { 2116185db85Sdougm last->next = item; 2126185db85Sdougm last = item; 2136185db85Sdougm } 2146185db85Sdougm item->lineno = line; 2156185db85Sdougm item->origline = strdup(buff); 2166185db85Sdougm (void) get_token(NULL); /* reset to new pointers */ 2176185db85Sdougm argc = 0; 2186185db85Sdougm while ((token = get_token(bp)) != NULL) { 2196185db85Sdougm if (argc < MAXARGSFORSHARE) { 2206185db85Sdougm args[argc++] = token; 2216185db85Sdougm } 2226185db85Sdougm } 2236185db85Sdougm while ((c = getopt(argc, args, "F:o:d:pg:")) != -1) { 2246185db85Sdougm switch (c) { 2256185db85Sdougm case 'p': 2266185db85Sdougm item->persist = 1; 2276185db85Sdougm break; 2286185db85Sdougm case 'F': 2296185db85Sdougm item->fstype = strdup(optarg); 2306185db85Sdougm break; 2316185db85Sdougm case 'o': 2326185db85Sdougm item->options = strdup(optarg); 2336185db85Sdougm break; 2346185db85Sdougm case 'd': 2356185db85Sdougm item->description = strdup(optarg); 2366185db85Sdougm break; 2376185db85Sdougm case 'g': 2386185db85Sdougm item->group = strdup(optarg); 2396185db85Sdougm break; 2406185db85Sdougm default: 2416185db85Sdougm break; 2426185db85Sdougm } 2436185db85Sdougm } 2446185db85Sdougm if (optind < argc) { 2456185db85Sdougm item->path = strdup(args[optind]); 2466185db85Sdougm optind++; 2476185db85Sdougm if (optind < argc) { 2486185db85Sdougm char *resource; 2496185db85Sdougm char *optgroup; 2506185db85Sdougm /* resource and/or groupname */ 2516185db85Sdougm resource = args[optind]; 2526185db85Sdougm optgroup = strchr(resource, '@'); 2536185db85Sdougm if (optgroup != NULL) { 2546185db85Sdougm *optgroup++ = '\0'; 2556185db85Sdougm } 2566185db85Sdougm if (optgroup != NULL) 2576185db85Sdougm item->group = strdup(optgroup); 2586185db85Sdougm if (resource != NULL && strlen(resource) > 0) 2596185db85Sdougm item->resource = strdup(resource); 2606185db85Sdougm } 2616185db85Sdougm } 2626185db85Sdougm } 2637d968cb8Sdougm if (item != NULL && item->fstype == NULL) 2646185db85Sdougm item->fstype = strdup("nfs"); /* this is the default */ 2656185db85Sdougm } 2666185db85Sdougm first = fix_notice(first); 2676185db85Sdougm return (first); 2686185db85Sdougm } 2696185db85Sdougm 2706185db85Sdougm /* 2716185db85Sdougm * finddfsentry(list, path) 2726185db85Sdougm * 2737d968cb8Sdougm * Look for path in the zfs_sharelist_t list and return the entry if it 2746185db85Sdougm * exists. 2756185db85Sdougm */ 2766185db85Sdougm 2776185db85Sdougm static xfs_sharelist_t * 2786185db85Sdougm finddfsentry(xfs_sharelist_t *list, char *path) 2796185db85Sdougm { 2806185db85Sdougm xfs_sharelist_t *item; 2816185db85Sdougm 2826185db85Sdougm for (item = list; item != NULL; item = item->next) { 2836185db85Sdougm if (item->path != NULL && strcmp(item->path, path) == 0) 2846185db85Sdougm return (item); 2856185db85Sdougm } 2866185db85Sdougm return (NULL); 2876185db85Sdougm } 2886185db85Sdougm 2896185db85Sdougm /* 2906185db85Sdougm * remdfsentry(list, path, proto) 2916185db85Sdougm * 2926185db85Sdougm * Remove the specified path (with protocol) from the list. This will 2936185db85Sdougm * remove it from dfstab when the file is rewritten. 2946185db85Sdougm */ 2956185db85Sdougm 2966185db85Sdougm static xfs_sharelist_t * 2976185db85Sdougm remdfsentry(xfs_sharelist_t *list, char *path, char *proto) 2986185db85Sdougm { 2996185db85Sdougm xfs_sharelist_t *item, *prev = NULL; 3006185db85Sdougm 3016185db85Sdougm 3026185db85Sdougm for (item = prev = list; item != NULL; item = item->next) { 3036185db85Sdougm /* skip comment entry but don't lose it */ 3046185db85Sdougm if (item->path == NULL) { 3056185db85Sdougm prev = item; 3066185db85Sdougm continue; 3076185db85Sdougm } 3086185db85Sdougm /* if proto is NULL, remove all protocols */ 3096185db85Sdougm if (proto == NULL || (strcmp(item->path, path) == 0 && 3106185db85Sdougm (item->fstype != NULL && strcmp(item->fstype, proto) == 0))) 3116185db85Sdougm break; 3126185db85Sdougm if (item->fstype == NULL && 3136185db85Sdougm (proto == NULL || strcmp(proto, "nfs") == 0)) 3146185db85Sdougm break; 3156185db85Sdougm prev = item; 3166185db85Sdougm } 3176185db85Sdougm if (item != NULL) { 3186185db85Sdougm if (item == prev) { 3196185db85Sdougm list = item->next; /* this must be the first one */ 3206185db85Sdougm } else { 3216185db85Sdougm prev->next = item->next; 3226185db85Sdougm } 3236185db85Sdougm item->next = NULL; 3246185db85Sdougm dfs_free_list(item); 3256185db85Sdougm } 3266185db85Sdougm return (list); 3276185db85Sdougm } 3286185db85Sdougm 3296185db85Sdougm /* 3306185db85Sdougm * remdfsline(list, line) 3316185db85Sdougm * 3326185db85Sdougm * Remove the line specified from the list. 3336185db85Sdougm */ 3346185db85Sdougm 3356185db85Sdougm static xfs_sharelist_t * 3366185db85Sdougm remdfsline(xfs_sharelist_t *list, char *line) 3376185db85Sdougm { 3386185db85Sdougm xfs_sharelist_t *item, *prev = NULL; 3396185db85Sdougm 3406185db85Sdougm for (item = prev = list; item != NULL; item = item->next) { 3416185db85Sdougm /* skip comment entry but don't lose it */ 3426185db85Sdougm if (item->path == NULL) { 3436185db85Sdougm prev = item; 3446185db85Sdougm continue; 3456185db85Sdougm } 3466185db85Sdougm if (strcmp(item->origline, line) == 0) { 3476185db85Sdougm break; 3486185db85Sdougm } 3496185db85Sdougm prev = item; 3506185db85Sdougm } 3516185db85Sdougm if (item != NULL) { 3526185db85Sdougm if (item == prev) { 3536185db85Sdougm list = item->next; /* this must be the first one */ 3546185db85Sdougm } else { 3556185db85Sdougm prev->next = item->next; 3566185db85Sdougm } 3576185db85Sdougm item->next = NULL; 3586185db85Sdougm dfs_free_list(item); 3596185db85Sdougm } 3606185db85Sdougm return (list); 3616185db85Sdougm } 3626185db85Sdougm 3636185db85Sdougm /* 3646185db85Sdougm * adddfsentry(list, share, proto) 3656185db85Sdougm * 3666185db85Sdougm * Add an entry to the dfstab list for share (relative to proto). This 3676185db85Sdougm * is used to update dfstab for legacy purposes. 3686185db85Sdougm */ 3696185db85Sdougm 3706185db85Sdougm static xfs_sharelist_t * 3716185db85Sdougm adddfsentry(xfs_sharelist_t *list, sa_share_t share, char *proto) 3726185db85Sdougm { 3736185db85Sdougm xfs_sharelist_t *item, *tmp; 3746185db85Sdougm sa_group_t parent; 3756185db85Sdougm char *groupname; 3766185db85Sdougm 3776185db85Sdougm item = alloc_sharelist(); 3786185db85Sdougm if (item != NULL) { 3796185db85Sdougm parent = sa_get_parent_group(share); 3806185db85Sdougm groupname = sa_get_group_attr(parent, "name"); 3816185db85Sdougm if (strcmp(groupname, "default") == 0) { 3826185db85Sdougm sa_free_attr_string(groupname); 3836185db85Sdougm groupname = NULL; 3846185db85Sdougm } 3856185db85Sdougm item->path = sa_get_share_attr(share, "path"); 3866185db85Sdougm item->resource = sa_get_share_attr(share, "resource"); 3876185db85Sdougm item->group = groupname; 3886185db85Sdougm item->fstype = strdup(proto); 3896185db85Sdougm item->options = sa_proto_legacy_format(proto, share, 1); 3906185db85Sdougm if (item->options != NULL && strlen(item->options) == 0) { 3916185db85Sdougm free(item->options); 3926185db85Sdougm item->options = NULL; 3936185db85Sdougm } 3946185db85Sdougm item->description = sa_get_share_description(share); 3956185db85Sdougm if (item->description != NULL && strlen(item->description) == 0) { 3966185db85Sdougm sa_free_share_description(item->description); 3976185db85Sdougm item->description = NULL; 3986185db85Sdougm } 3996185db85Sdougm if (list == NULL) { 4006185db85Sdougm list = item; 4016185db85Sdougm } else { 4026185db85Sdougm for (tmp = list; tmp->next != NULL; tmp = tmp->next) 4036185db85Sdougm /* do nothing */; 4046185db85Sdougm tmp->next = item; 4056185db85Sdougm } 4066185db85Sdougm } 4076185db85Sdougm return (list); 4086185db85Sdougm } 4096185db85Sdougm 4106185db85Sdougm /* 4116185db85Sdougm * outdfstab(dfstab, list) 4126185db85Sdougm * 4136185db85Sdougm * Output the list to dfstab making sure the file is truncated. 4146185db85Sdougm * Comments and errors are preserved. 4156185db85Sdougm */ 4166185db85Sdougm 4176185db85Sdougm static void 4186185db85Sdougm outdfstab(FILE *dfstab, xfs_sharelist_t *list) 4196185db85Sdougm { 4206185db85Sdougm xfs_sharelist_t *item; 4216185db85Sdougm 4226185db85Sdougm (void) ftruncate(fileno(dfstab), 0); 4236185db85Sdougm 4246185db85Sdougm for (item = list; item != NULL; item = item->next) { 4256185db85Sdougm if (item->path != NULL) { 4266185db85Sdougm if (*item->path == '/') 4276185db85Sdougm (void) fprintf(dfstab, "share %s%s%s%s%s%s%s %s%s%s%s%s\n", 4286185db85Sdougm (item->fstype != NULL) ? "-F " : "", 4296185db85Sdougm (item->fstype != NULL) ? item->fstype : "", 4306185db85Sdougm (item->options != NULL) ? " -o " : "", 4316185db85Sdougm (item->options != NULL) ? item->options : "", 4326185db85Sdougm (item->description != NULL) ? " -d \"" : "", 4336185db85Sdougm (item->description != NULL) ? 4346185db85Sdougm item->description : "", 4356185db85Sdougm (item->description != NULL) ? "\"" : "", 4366185db85Sdougm item->path, 4376185db85Sdougm ((item->resource != NULL) || 4386185db85Sdougm (item->group != NULL)) ? " " : "", 4396185db85Sdougm (item->resource != NULL) ? item->resource : "", 4406185db85Sdougm item->group != NULL ? "@" : "", 4416185db85Sdougm item->group != NULL ? item->group : ""); 4426185db85Sdougm else 4436185db85Sdougm (void) fprintf(dfstab, "%s", item->origline); 4446185db85Sdougm } else { 4456185db85Sdougm if (item->description != NULL) { 4466185db85Sdougm (void) fprintf(dfstab, "%s", item->description); 4476185db85Sdougm } else { 4486185db85Sdougm (void) fprintf(dfstab, "%s", item->origline); 4496185db85Sdougm } 4506185db85Sdougm } 4516185db85Sdougm } 4526185db85Sdougm } 4536185db85Sdougm 4546185db85Sdougm /* 4556185db85Sdougm * open_dfstab(file) 4566185db85Sdougm * 4576185db85Sdougm * Open the specified dfstab file. If the owner/group/perms are wrong, 4586185db85Sdougm * fix them. 4596185db85Sdougm */ 4606185db85Sdougm 4616185db85Sdougm static FILE * 4626185db85Sdougm open_dfstab(char *file) 4636185db85Sdougm { 4646185db85Sdougm struct group *grp; 4656185db85Sdougm struct group group; 4666185db85Sdougm char *buff; 4676185db85Sdougm int grsize; 4686185db85Sdougm FILE *dfstab; 4696185db85Sdougm 4706185db85Sdougm dfstab = fopen(file, "r+"); 4716185db85Sdougm if (dfstab == NULL) { 4726185db85Sdougm dfstab = fopen(file, "w+"); 4736185db85Sdougm } 4746185db85Sdougm if (dfstab != NULL) { 4756185db85Sdougm grsize = sysconf(_SC_GETGR_R_SIZE_MAX); 4766185db85Sdougm buff = malloc(grsize); 4776185db85Sdougm if (buff != NULL) 4786185db85Sdougm grp = getgrnam_r(SA_DEFAULT_FILE_GRP, &group, buff, grsize); 4796185db85Sdougm else 4806185db85Sdougm grp = getgrnam(SA_DEFAULT_FILE_GRP); /* take the risk */ 4816185db85Sdougm (void) fchmod(fileno(dfstab), 0644); 4826185db85Sdougm (void) fchown(fileno(dfstab), 0, 4836185db85Sdougm grp != NULL ? grp->gr_gid : 3); 4846185db85Sdougm if (buff != NULL) 4856185db85Sdougm free(buff); 4866185db85Sdougm rewind(dfstab); 4876185db85Sdougm } 4886185db85Sdougm return (dfstab); 4896185db85Sdougm } 4906185db85Sdougm 4916185db85Sdougm /* 4926185db85Sdougm * sa_comment_line(line, err) 4936185db85Sdougm * 4946185db85Sdougm * Add a comment to the dfstab file with err as a prefix to the 4956185db85Sdougm * original line. 4966185db85Sdougm */ 4976185db85Sdougm 4986185db85Sdougm static void 4996185db85Sdougm sa_comment_line(char *line, char *err) 5006185db85Sdougm { 5016185db85Sdougm FILE *dfstab; 5026185db85Sdougm xfs_sharelist_t *list; 5036185db85Sdougm sigset_t old, new; 5046185db85Sdougm 5056185db85Sdougm dfstab = open_dfstab(SA_LEGACY_DFSTAB); 5066185db85Sdougm if (dfstab != NULL) { 5076185db85Sdougm (void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8); 5086185db85Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 5096185db85Sdougm (void) sigaddset(&new, SIGHUP); 5106185db85Sdougm (void) sigaddset(&new, SIGINT); 5116185db85Sdougm (void) sigaddset(&new, SIGQUIT); 5126185db85Sdougm (void) sigaddset(&new, SIGTSTP); 5136185db85Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 5146185db85Sdougm (void) lockf(fileno(dfstab), F_LOCK, 0); 5156185db85Sdougm list = getdfstab(dfstab); 5166185db85Sdougm rewind(dfstab); 517*f345c0beSdougm /* 518*f345c0beSdougm * don't ignore the return since the list could have 519*f345c0beSdougm * gone to NULL if the file only had one line in it. 520*f345c0beSdougm */ 521*f345c0beSdougm list = remdfsline(list, line); 5226185db85Sdougm outdfstab(dfstab, list); 5236185db85Sdougm (void) fprintf(dfstab, "# Error: %s: %s", err, line); 5246185db85Sdougm (void) fsync(fileno(dfstab)); 5256185db85Sdougm (void) lockf(fileno(dfstab), F_ULOCK, 0); 5266185db85Sdougm (void) fclose(dfstab); 5276185db85Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 5286185db85Sdougm if (list != NULL) 5296185db85Sdougm dfs_free_list(list); 5306185db85Sdougm } 5316185db85Sdougm } 5326185db85Sdougm 5336185db85Sdougm /* 5346185db85Sdougm * sa_delete_legacy(share) 5356185db85Sdougm * 5366185db85Sdougm * Delete the specified share from the legacy config file. 5376185db85Sdougm */ 5386185db85Sdougm 5396185db85Sdougm int 5406185db85Sdougm sa_delete_legacy(sa_share_t share) 5416185db85Sdougm { 5426185db85Sdougm FILE *dfstab; 5436185db85Sdougm int err; 5446185db85Sdougm int ret = SA_OK; 5456185db85Sdougm xfs_sharelist_t *list; 5466185db85Sdougm char *path; 5476185db85Sdougm sa_optionset_t optionset; 5486185db85Sdougm sa_group_t parent; 5496185db85Sdougm sigset_t old, new; 5506185db85Sdougm 5516185db85Sdougm dfstab = open_dfstab(SA_LEGACY_DFSTAB); 5526185db85Sdougm if (dfstab != NULL) { 5536185db85Sdougm (void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8); 5546185db85Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 5556185db85Sdougm (void) sigaddset(&new, SIGHUP); 5566185db85Sdougm (void) sigaddset(&new, SIGINT); 5576185db85Sdougm (void) sigaddset(&new, SIGQUIT); 5586185db85Sdougm (void) sigaddset(&new, SIGTSTP); 5596185db85Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 5606185db85Sdougm path = sa_get_share_attr(share, "path"); 5616185db85Sdougm parent = sa_get_parent_group(share); 5626185db85Sdougm if (parent != NULL) { 5636185db85Sdougm (void) lockf(fileno(dfstab), F_LOCK, 0); 5646185db85Sdougm list = getdfstab(dfstab); 5656185db85Sdougm rewind(dfstab); 5666185db85Sdougm for (optionset = sa_get_optionset(parent, NULL); 5676185db85Sdougm optionset != NULL; 5686185db85Sdougm optionset = sa_get_next_optionset(optionset)) { 5696185db85Sdougm char *proto = sa_get_optionset_attr(optionset, "type"); 5706185db85Sdougm if (list != NULL && proto != NULL) 5717d968cb8Sdougm list = remdfsentry(list, path, proto); 5726185db85Sdougm if (proto == NULL) 5736185db85Sdougm ret = SA_NO_MEMORY; 5746185db85Sdougm /* 5756185db85Sdougm * may want to only do the dfstab if this call 5766185db85Sdougm * returns NOT IMPLEMENTED but it shouldn't 5776185db85Sdougm * hurt. 5786185db85Sdougm */ 5796185db85Sdougm if (ret == SA_OK) { 5806185db85Sdougm err = sa_proto_delete_legacy(proto, share); 5816185db85Sdougm if (err != SA_NOT_IMPLEMENTED) 5826185db85Sdougm ret = err; 5836185db85Sdougm } 5846185db85Sdougm if (proto != NULL) 5856185db85Sdougm sa_free_attr_string(proto); 5866185db85Sdougm } 5876185db85Sdougm outdfstab(dfstab, list); 5886185db85Sdougm if (list != NULL) 5896185db85Sdougm dfs_free_list(list); 5906185db85Sdougm (void) fflush(dfstab); 5916185db85Sdougm (void) lockf(fileno(dfstab), F_ULOCK, 0); 5926185db85Sdougm } 5936185db85Sdougm (void) fsync(fileno(dfstab)); 5946185db85Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 5956185db85Sdougm (void) fclose(dfstab); 5966185db85Sdougm sa_free_attr_string(path); 5976185db85Sdougm } else { 5986185db85Sdougm if (errno == EACCES || errno == EPERM) { 5996185db85Sdougm ret = SA_NO_PERMISSION; 6006185db85Sdougm } else { 6016185db85Sdougm ret = SA_CONFIG_ERR; 6026185db85Sdougm } 6036185db85Sdougm } 6046185db85Sdougm return (ret); 6056185db85Sdougm } 6066185db85Sdougm 6076185db85Sdougm /* 6086185db85Sdougm * sa_update_legacy(share, proto) 6096185db85Sdougm * 6106185db85Sdougm * There is an assumption that dfstab will be the most common form of 6116185db85Sdougm * legacy configuration file for shares, but not the only one. Because 6126185db85Sdougm * of that, dfstab handling is done in the main code with calls to 6136185db85Sdougm * this function and protocol specific calls to deal with formating 6146185db85Sdougm * options into dfstab/share compatible syntax. Since not everything 6156185db85Sdougm * will be dfstab, there is a provision for calling a protocol 6166185db85Sdougm * specific plugin interface that allows the protocol plugin to do its 6176185db85Sdougm * own legacy files and skip the dfstab update. 6186185db85Sdougm */ 6196185db85Sdougm 6206185db85Sdougm int 6216185db85Sdougm sa_update_legacy(sa_share_t share, char *proto) 6226185db85Sdougm { 6236185db85Sdougm FILE *dfstab; 6246185db85Sdougm int ret = SA_OK; 6256185db85Sdougm xfs_sharelist_t *list; 6266185db85Sdougm char *path; 6276185db85Sdougm sigset_t old, new; 6286185db85Sdougm char *persist; 6296185db85Sdougm 6306185db85Sdougm ret = sa_proto_update_legacy(proto, share); 6316185db85Sdougm if (ret != SA_NOT_IMPLEMENTED) 6326185db85Sdougm return (ret); 6336185db85Sdougm /* do the dfstab format */ 6346185db85Sdougm persist = sa_get_share_attr(share, "type"); 6356185db85Sdougm /* 6366185db85Sdougm * only update if the share is not transient -- no share type 6376185db85Sdougm * set or the type is not "transient". 6386185db85Sdougm */ 6396185db85Sdougm if (persist == NULL || strcmp(persist, "transient") != 0) { 6406185db85Sdougm dfstab = open_dfstab(SA_LEGACY_DFSTAB); 6416185db85Sdougm if (dfstab != NULL) { 6426185db85Sdougm (void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8); 6436185db85Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 6446185db85Sdougm (void) sigaddset(&new, SIGHUP); 6456185db85Sdougm (void) sigaddset(&new, SIGINT); 6466185db85Sdougm (void) sigaddset(&new, SIGQUIT); 6476185db85Sdougm (void) sigaddset(&new, SIGTSTP); 6486185db85Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 6496185db85Sdougm path = sa_get_share_attr(share, "path"); 6506185db85Sdougm (void) lockf(fileno(dfstab), F_LOCK, 0); 6516185db85Sdougm list = getdfstab(dfstab); 6526185db85Sdougm rewind(dfstab); 6536185db85Sdougm if (list != NULL) 6546185db85Sdougm list = remdfsentry(list, path, proto); 6556185db85Sdougm list = adddfsentry(list, share, proto); 6566185db85Sdougm outdfstab(dfstab, list); 6576185db85Sdougm (void) fflush(dfstab); 6586185db85Sdougm (void) lockf(fileno(dfstab), F_ULOCK, 0); 6596185db85Sdougm (void) fsync(fileno(dfstab)); 6606185db85Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 6616185db85Sdougm (void) fclose(dfstab); 6626185db85Sdougm sa_free_attr_string(path); 6636185db85Sdougm if (list != NULL) 6646185db85Sdougm dfs_free_list(list); 6656185db85Sdougm } else { 6666185db85Sdougm if (errno == EACCES || errno == EPERM) { 6676185db85Sdougm ret = SA_NO_PERMISSION; 6686185db85Sdougm } else { 6696185db85Sdougm ret = SA_CONFIG_ERR; 6706185db85Sdougm } 6716185db85Sdougm } 6726185db85Sdougm } 6736185db85Sdougm if (persist != NULL) 6746185db85Sdougm sa_free_attr_string(persist); 6756185db85Sdougm return (ret); 6766185db85Sdougm } 6776185db85Sdougm 6786185db85Sdougm /* 6796185db85Sdougm * sa_is_security(optname, proto) 6806185db85Sdougm * 6816185db85Sdougm * Check to see if optname is a security (named optionset) specific 6826185db85Sdougm * property for the specified protocol. 6836185db85Sdougm */ 6846185db85Sdougm 6856185db85Sdougm int 6866185db85Sdougm sa_is_security(char *optname, char *proto) 6876185db85Sdougm { 6886185db85Sdougm int ret = 0; 6896185db85Sdougm if (proto != NULL) 6906185db85Sdougm ret = sa_proto_security_prop(proto, optname); 6916185db85Sdougm return (ret); 6926185db85Sdougm } 6936185db85Sdougm 6946185db85Sdougm /* 6956185db85Sdougm * add_syntax_comment(root, line, err, todfstab) 6966185db85Sdougm * 6976185db85Sdougm * add a comment to the document indicating a syntax error. If 6986185db85Sdougm * todfstab is set, write it back to the dfstab file as well. 6996185db85Sdougm */ 7006185db85Sdougm 7016185db85Sdougm static void 7026185db85Sdougm add_syntax_comment(xmlNodePtr root, char *line, char *err, int todfstab) 7036185db85Sdougm { 7046185db85Sdougm xmlNodePtr node; 7056185db85Sdougm 7066185db85Sdougm node = xmlNewChild(root, NULL, (xmlChar *)"error", (xmlChar *)line); 7076185db85Sdougm if (node != NULL) { 7086185db85Sdougm xmlSetProp(node, (xmlChar *)"type", (xmlChar *)err); 7096185db85Sdougm } 7106185db85Sdougm if (todfstab) 7116185db85Sdougm sa_comment_line(line, err); 7126185db85Sdougm } 7136185db85Sdougm 7146185db85Sdougm /* 7156185db85Sdougm * sa_is_share(object) 7166185db85Sdougm * 7176185db85Sdougm * returns true of the object is of type "share". 7186185db85Sdougm */ 7196185db85Sdougm 7206185db85Sdougm int 7216185db85Sdougm sa_is_share(void *object) 7226185db85Sdougm { 7236185db85Sdougm if (object != NULL) { 7246185db85Sdougm if (strcmp((char *)((xmlNodePtr)object)->name, "share") == 0) 7256185db85Sdougm return (1); 7266185db85Sdougm } 7276185db85Sdougm return (0); 7286185db85Sdougm } 7296185db85Sdougm 7306185db85Sdougm /* 7316185db85Sdougm * _sa_remove_property(property) 7326185db85Sdougm * 7336185db85Sdougm * remove a property only from the document. 7346185db85Sdougm */ 7356185db85Sdougm 7366185db85Sdougm static void 7376185db85Sdougm _sa_remove_property(sa_property_t property) 7386185db85Sdougm { 7396185db85Sdougm xmlUnlinkNode((xmlNodePtr)property); 7406185db85Sdougm xmlFreeNode((xmlNodePtr)property); 7416185db85Sdougm } 7426185db85Sdougm 7436185db85Sdougm /* 7446185db85Sdougm * sa_parse_legacy_options(group, options, proto) 7456185db85Sdougm * 7466185db85Sdougm * In order to support legacy configurations, we allow the protocol 7476185db85Sdougm * specific plugin to parse legacy syntax options (like those in 7486185db85Sdougm * /etc/dfs/dfstab). This adds a new optionset to the group (or 7496185db85Sdougm * share). 7506185db85Sdougm * 7516185db85Sdougm * Once the optionset has been created, we then get the derived 7526185db85Sdougm * optionset of the parent (options from the optionset of the parent 7536185db85Sdougm * and any parent it might have) and remove those from the created 7546185db85Sdougm * optionset. This avoids duplication of options. 7556185db85Sdougm */ 7566185db85Sdougm 7576185db85Sdougm int 7586185db85Sdougm sa_parse_legacy_options(sa_group_t group, char *options, char *proto) 7596185db85Sdougm { 7606185db85Sdougm int ret = SA_INVALID_PROTOCOL; 7616185db85Sdougm sa_group_t parent; 7626185db85Sdougm parent = sa_get_parent_group(group); 7636185db85Sdougm 7646185db85Sdougm if (proto != NULL) 7656185db85Sdougm ret = sa_proto_legacy_opts(proto, group, options); 7666185db85Sdougm /* 7676185db85Sdougm * if in a group, remove the inherited options and security 7686185db85Sdougm */ 7696185db85Sdougm if (ret == SA_OK) { 7706185db85Sdougm if (parent != NULL) { 7716185db85Sdougm sa_optionset_t optionset; 7726185db85Sdougm sa_property_t popt, prop; 7736185db85Sdougm sa_optionset_t localoptions; 7746185db85Sdougm /* find parent options to remove from child */ 7756185db85Sdougm optionset = sa_get_derived_optionset(parent, proto, 1); 7766185db85Sdougm localoptions = sa_get_optionset(group, proto); 7776185db85Sdougm if (optionset != NULL) { 7786185db85Sdougm for (popt = sa_get_property(optionset, NULL); 7796185db85Sdougm popt != NULL; 7806185db85Sdougm popt = sa_get_next_property(popt)) { 7816185db85Sdougm char *tag; 7826185db85Sdougm char *value1; 7836185db85Sdougm char *value2; 7846185db85Sdougm 7856185db85Sdougm tag = sa_get_property_attr(popt, "type"); 7866185db85Sdougm if (tag != NULL) { 7876185db85Sdougm prop = sa_get_property(localoptions, tag); 7886185db85Sdougm if (prop != NULL) { 7896185db85Sdougm value1 = sa_get_property_attr(popt, "value"); 7906185db85Sdougm value2 = sa_get_property_attr(prop, "value"); 7916185db85Sdougm if (value1 != NULL && value2 != NULL && 7926185db85Sdougm strcmp(value1, value2) == 0) { 7936185db85Sdougm /* remove the property from the child */ 7946185db85Sdougm (void) _sa_remove_property(prop); 7956185db85Sdougm } 7966185db85Sdougm if (value1 != NULL) 7976185db85Sdougm sa_free_attr_string(value1); 7986185db85Sdougm if (value2 != NULL) 7996185db85Sdougm sa_free_attr_string(value2); 8006185db85Sdougm } 8016185db85Sdougm sa_free_attr_string(tag); 8026185db85Sdougm } 8036185db85Sdougm } 8046185db85Sdougm prop = sa_get_property(localoptions, NULL); 8056185db85Sdougm if (prop == NULL && sa_is_share(group)) { 8066185db85Sdougm /* 8076185db85Sdougm * all properties removed so remove the 8086185db85Sdougm * optionset if it is on a share 8096185db85Sdougm */ 8106185db85Sdougm (void) _sa_remove_optionset(localoptions); 8116185db85Sdougm } 8126185db85Sdougm sa_free_derived_optionset(optionset); 8136185db85Sdougm } 8146185db85Sdougm /* 8156185db85Sdougm * need to remove security here. If there are no 8166185db85Sdougm * security options on the local group/share, don't 8176185db85Sdougm * bother since those are the only ones that would be 8186185db85Sdougm * affected. 8196185db85Sdougm */ 8206185db85Sdougm localoptions = sa_get_all_security_types(group, proto, 0); 8216185db85Sdougm if (localoptions != NULL) { 8226185db85Sdougm for (prop = sa_get_property(localoptions, NULL); 8236185db85Sdougm prop != NULL; prop = sa_get_next_property(prop)) { 8246185db85Sdougm char *tag; 8256185db85Sdougm sa_security_t security; 8266185db85Sdougm tag = sa_get_property_attr(prop, "type"); 8276185db85Sdougm if (tag != NULL) { 8286185db85Sdougm security = sa_get_security(group, tag, proto); 8296185db85Sdougm sa_free_attr_string(tag); 8306185db85Sdougm for (popt = sa_get_property(security, NULL); 8316185db85Sdougm popt != NULL; 8326185db85Sdougm popt = sa_get_next_property(popt)) { 8336185db85Sdougm char *value1; 8346185db85Sdougm char *value2; 8356185db85Sdougm 8366185db85Sdougm /* remove duplicates from this level */ 8376185db85Sdougm value1 = sa_get_property_attr(popt, "value"); 8386185db85Sdougm value2 = sa_get_property_attr(prop, "value"); 8396185db85Sdougm if (value1 != NULL && value2 != NULL && 8406185db85Sdougm strcmp(value1, value2) == 0) { 8416185db85Sdougm /* remove the property from the child */ 8426185db85Sdougm (void) _sa_remove_property(prop); 8436185db85Sdougm } 8446185db85Sdougm if (value1 != NULL) 8456185db85Sdougm sa_free_attr_string(value1); 8466185db85Sdougm if (value2 != NULL) 8476185db85Sdougm sa_free_attr_string(value2); 8486185db85Sdougm } 8496185db85Sdougm } 8506185db85Sdougm } 8516185db85Sdougm (void) sa_destroy_optionset(localoptions); 8526185db85Sdougm } 8536185db85Sdougm } 8546185db85Sdougm } 8556185db85Sdougm return (ret); 8566185db85Sdougm } 8576185db85Sdougm 8586185db85Sdougm /* 8596185db85Sdougm * dfs_free_list(list) 8606185db85Sdougm * 8616185db85Sdougm * Free the data in each list entry of the list as well as freeing the 8626185db85Sdougm * entries themselves. We need to avoid memory leaks and don't want to 8636185db85Sdougm * dereference any NULL members. 8646185db85Sdougm */ 8656185db85Sdougm 8666185db85Sdougm static void 8676185db85Sdougm dfs_free_list(xfs_sharelist_t *list) 8686185db85Sdougm { 8696185db85Sdougm xfs_sharelist_t *entry; 8706185db85Sdougm for (entry = list; entry != NULL; entry = list) { 8716185db85Sdougm if (entry->path != NULL) 8726185db85Sdougm free(entry->path); 8736185db85Sdougm if (entry->resource != NULL) 8746185db85Sdougm free(entry->resource); 8756185db85Sdougm if (entry->fstype != NULL) 8766185db85Sdougm free(entry->fstype); 8776185db85Sdougm if (entry->options != NULL) 8786185db85Sdougm free(entry->options); 8796185db85Sdougm if (entry->description != NULL) 8806185db85Sdougm free(entry->description); 8816185db85Sdougm if (entry->origline != NULL) 8826185db85Sdougm free(entry->origline); 8836185db85Sdougm if (entry->group != NULL) 8846185db85Sdougm free(entry->group); 8856185db85Sdougm list = list->next; 8866185db85Sdougm free(entry); 8876185db85Sdougm } 8886185db85Sdougm } 8896185db85Sdougm 8906185db85Sdougm /* 8916185db85Sdougm * parse_dfstab(dfstab, root) 8926185db85Sdougm * 8936185db85Sdougm * Open and read the existing dfstab, parsing each line and adding it 8946185db85Sdougm * to the internal configuration. Make sure syntax errors, etc are 8956185db85Sdougm * preserved as comments. 8966185db85Sdougm */ 8976185db85Sdougm 8986185db85Sdougm static void 8996185db85Sdougm parse_dfstab(char *dfstab, xmlNodePtr root) 9006185db85Sdougm { 9016185db85Sdougm sa_share_t share; 9026185db85Sdougm sa_group_t group; 9036185db85Sdougm sa_group_t sgroup = NULL; 9046185db85Sdougm sa_group_t defgroup; 9056185db85Sdougm xfs_sharelist_t *head, *list; 9066185db85Sdougm int err; 9076185db85Sdougm int defined_group; 9086185db85Sdougm FILE *dfs; 9096185db85Sdougm char *oldprops; 9106185db85Sdougm 9116185db85Sdougm /* read the dfstab format file and fill in the doc tree */ 9126185db85Sdougm 9136185db85Sdougm dfs = fopen(dfstab, "r"); 9146185db85Sdougm if (dfs == NULL) { 9156185db85Sdougm return; 9166185db85Sdougm } 9176185db85Sdougm 9186185db85Sdougm defgroup = sa_get_group("default"); 9196185db85Sdougm 9206185db85Sdougm for (head = list = getdfstab(dfs); 9216185db85Sdougm list != NULL; 9226185db85Sdougm list = list->next) { 9236185db85Sdougm share = NULL; 9246185db85Sdougm group = NULL; 9256185db85Sdougm defined_group = 0; 9266185db85Sdougm err = 0; 9276185db85Sdougm 9286185db85Sdougm if (list->origline == NULL) { 9296185db85Sdougm /* 9306185db85Sdougm * Comment line that we will likely skip. 9316185db85Sdougm * If the line has the syntax: 9326185db85Sdougm * # error: string: string 9336185db85Sdougm * It should be preserved until manually deleted. 9346185db85Sdougm */ 9356185db85Sdougm if (list->description != NULL && 9366185db85Sdougm strncmp(list->description, "# Error: ", 9) == 0) { 9376185db85Sdougm char *line; 9386185db85Sdougm char *error; 9396185db85Sdougm char *cmd; 9406185db85Sdougm line = strdup(list->description); 9416185db85Sdougm if (line != NULL) { 9426185db85Sdougm error = line + 9; 9436185db85Sdougm cmd = strchr(error, ':'); 9446185db85Sdougm if (cmd != NULL) { 9456185db85Sdougm int len; 9466185db85Sdougm *cmd = '\0'; 9476185db85Sdougm cmd += 2; 9486185db85Sdougm len = strlen(cmd); 9496185db85Sdougm cmd[len - 1] = '\0'; 9506185db85Sdougm add_syntax_comment(root, cmd, error, 0); 9516185db85Sdougm } 9526185db85Sdougm free(line); 9536185db85Sdougm } 9546185db85Sdougm } 9556185db85Sdougm continue; 9566185db85Sdougm } 9576185db85Sdougm if (list->path != NULL && strlen(list->path) > 0 && 9586185db85Sdougm *list->path == '/') { 9596185db85Sdougm share = sa_find_share(list->path); 9606185db85Sdougm if (share != NULL) 9616185db85Sdougm sgroup = sa_get_parent_group(share); 9626185db85Sdougm else 9636185db85Sdougm sgroup = NULL; 9646185db85Sdougm } else { 9656185db85Sdougm (void) printf(gettext("No share specified in dfstab: " 9666185db85Sdougm "line %d: %s\n"), 9676185db85Sdougm list->lineno, list->origline); 9686185db85Sdougm add_syntax_comment(root, list->origline, 9696185db85Sdougm gettext("No share specified"), 9706185db85Sdougm 1); 9716185db85Sdougm continue; 9726185db85Sdougm } 9736185db85Sdougm if (list->group != NULL && strlen(list->group) > 0) { 9746185db85Sdougm group = sa_get_group(list->group); 9756185db85Sdougm defined_group = 1; 9766185db85Sdougm } else { 9776185db85Sdougm group = defgroup; 9786185db85Sdougm } 9796185db85Sdougm if (defined_group && group == NULL) { 9806185db85Sdougm (void) printf(gettext("Unknown group used in dfstab: " 9816185db85Sdougm "line %d: %s\n"), 9826185db85Sdougm list->lineno, list->origline); 9836185db85Sdougm add_syntax_comment(root, list->origline, 9846185db85Sdougm gettext("Unknown group specified"), 1); 9856185db85Sdougm continue; 9866185db85Sdougm } 9876185db85Sdougm if (group != NULL) { 9886185db85Sdougm if (share == NULL) { 9896185db85Sdougm if (!defined_group && group == defgroup) { 9906185db85Sdougm /* this is an OK add for legacy */ 9916185db85Sdougm share = sa_add_share(defgroup, list->path, 9926185db85Sdougm SA_SHARE_PERMANENT | SA_SHARE_PARSER, 9936185db85Sdougm &err); 9946185db85Sdougm if (share != NULL) { 9956185db85Sdougm if (list->description != NULL && 9966185db85Sdougm strlen(list->description) > 0) 9976185db85Sdougm (void) sa_set_share_description(share, 9986185db85Sdougm list->description); 9996185db85Sdougm if (list->options != NULL && 10006185db85Sdougm strlen(list->options) > 0) { 10016185db85Sdougm (void) sa_parse_legacy_options(share, 10026185db85Sdougm list->options, 10036185db85Sdougm list->fstype); 10046185db85Sdougm } 10056185db85Sdougm if (list->resource != NULL) 10066185db85Sdougm (void) sa_set_share_attr(share, "resource", 10076185db85Sdougm list->resource); 10086185db85Sdougm } else { 10096185db85Sdougm (void) printf(gettext("Error in dfstab: " 10106185db85Sdougm "line %d: %s\n"), 10116185db85Sdougm list->lineno, list->origline); 10126185db85Sdougm if (err != SA_BAD_PATH) 10136185db85Sdougm add_syntax_comment(root, list->origline, 10146185db85Sdougm gettext("Syntax"), 1); 10156185db85Sdougm else 10166185db85Sdougm add_syntax_comment(root, list->origline, 10176185db85Sdougm gettext("Path"), 1); 10186185db85Sdougm continue; 10196185db85Sdougm } 10206185db85Sdougm } 10216185db85Sdougm } else { 10226185db85Sdougm if (group != sgroup) { 10236185db85Sdougm (void) printf(gettext("Attempt to change" 10246185db85Sdougm "configuration in" 10256185db85Sdougm "dfstab: line %d: %s\n"), 10266185db85Sdougm list->lineno, list->origline); 10276185db85Sdougm add_syntax_comment(root, list->origline, 10286185db85Sdougm gettext("Attempt to change configuration"), 1); 10296185db85Sdougm continue; 10306185db85Sdougm } 10316185db85Sdougm /* its the same group but could have changed options */ 10326185db85Sdougm oldprops = sa_proto_legacy_format(list->fstype, share, 0); 10336185db85Sdougm if (oldprops != NULL) { 10346185db85Sdougm if (list->options != NULL && 10356185db85Sdougm strcmp(oldprops, list->options) != 0) { 10366185db85Sdougm sa_optionset_t opts; 10376185db85Sdougm sa_security_t secs; 10386185db85Sdougm /* possibly different values */ 10396185db85Sdougm opts = sa_get_optionset((sa_group_t)share, 10406185db85Sdougm list->fstype); 10416185db85Sdougm (void) sa_destroy_optionset(opts); 10426185db85Sdougm for (secs = sa_get_security((sa_group_t)share, 10436185db85Sdougm NULL, list->fstype); 10446185db85Sdougm secs != NULL; 10456185db85Sdougm secs = sa_get_security((sa_group_t)share, 10466185db85Sdougm NULL, list->fstype)) { 10476185db85Sdougm (void) sa_destroy_security(secs); 10486185db85Sdougm } 10496185db85Sdougm (void) sa_parse_legacy_options(share, 10506185db85Sdougm list->options, 10516185db85Sdougm list->fstype); 10526185db85Sdougm } 10536185db85Sdougm } 10546185db85Sdougm } 10556185db85Sdougm } else { 10566185db85Sdougm /* shouldn't happen */ 10576185db85Sdougm err = SA_CONFIG_ERR; 10586185db85Sdougm } 10596185db85Sdougm 10606185db85Sdougm } 10616185db85Sdougm dfs_free_list(head); 10626185db85Sdougm } 10636185db85Sdougm 10646185db85Sdougm /* 10656185db85Sdougm * legacy_removes(group, file) 10666185db85Sdougm * 10676185db85Sdougm * Find any shares that are "missing" from the legacy file. These 10686185db85Sdougm * should be removed from the configuration since they are likely from 10696185db85Sdougm * a legacy app or the admin modified the dfstab file directly. We 10706185db85Sdougm * have to support this even if it is not the recommended way to do 10716185db85Sdougm * things. 10726185db85Sdougm */ 10736185db85Sdougm 10746185db85Sdougm static void 10756185db85Sdougm legacy_removes(sa_group_t group, char *file) 10766185db85Sdougm { 10776185db85Sdougm sa_share_t share; 10786185db85Sdougm char *path; 10796185db85Sdougm xfs_sharelist_t *list, *item; 10806185db85Sdougm FILE *dfstab; 10816185db85Sdougm 10826185db85Sdougm dfstab = fopen(file, "r"); 10836185db85Sdougm if (dfstab != NULL) { 10846185db85Sdougm list = getdfstab(dfstab); 10856185db85Sdougm (void) fclose(dfstab); 1086*f345c0beSdougm retry: 10876185db85Sdougm for (share = sa_get_share(group, NULL); share != NULL; 10886185db85Sdougm share = sa_get_next_share(share)) { 10896185db85Sdougm /* now see if the share is in the dfstab file */ 10906185db85Sdougm path = sa_get_share_attr(share, "path"); 10916185db85Sdougm if (path != NULL) { 10926185db85Sdougm item = finddfsentry(list, path); 1093*f345c0beSdougm sa_free_attr_string(path); 10946185db85Sdougm if (item == NULL) { 10956185db85Sdougm /* the share was removed this way */ 10966185db85Sdougm (void) sa_remove_share(share); 1097*f345c0beSdougm 10986185db85Sdougm /* start over since the list was broken */ 1099*f345c0beSdougm goto retry; 11006185db85Sdougm } 11016185db85Sdougm } 11026185db85Sdougm } 11036185db85Sdougm if (list != NULL) 11046185db85Sdougm dfs_free_list(list); 11056185db85Sdougm } 11066185db85Sdougm } 11076185db85Sdougm 11086185db85Sdougm /* 11096185db85Sdougm * getlegacyconfig(path, root) 11106185db85Sdougm * 11116185db85Sdougm * Parse dfstab and build the legacy configuration. This only gets 11126185db85Sdougm * called when a change was detected. 11136185db85Sdougm */ 11146185db85Sdougm 11156185db85Sdougm void 11166185db85Sdougm getlegacyconfig(char *path, xmlNodePtr *root) 11176185db85Sdougm { 11186185db85Sdougm sa_group_t defgroup; 11196185db85Sdougm 11206185db85Sdougm if (root != NULL) { 11216185db85Sdougm if (*root == NULL) 11226185db85Sdougm *root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 11236185db85Sdougm if (*root != NULL) { 11246185db85Sdougm if (strcmp(path, SA_LEGACY_DFSTAB) == 0) { 11256185db85Sdougm /* 11266185db85Sdougm * walk the default shares and find anything 11276185db85Sdougm * missing. we do this first to make sure it 11286185db85Sdougm * is cleaned up since there may be legacy 11296185db85Sdougm * code add/del via dfstab and we need to 11306185db85Sdougm * cleanup SMF. 11316185db85Sdougm */ 11326185db85Sdougm defgroup = sa_get_group("default"); 11336185db85Sdougm if (defgroup != NULL) { 11346185db85Sdougm legacy_removes(defgroup, path); 11356185db85Sdougm } 11366185db85Sdougm /* parse the dfstab and add anything new */ 11376185db85Sdougm parse_dfstab(path, *root); 11386185db85Sdougm } 11396185db85Sdougm } 11406185db85Sdougm } 11416185db85Sdougm } 11426185db85Sdougm 11431cea05afSdougm /* 11441cea05afSdougm * get_share_list(&err) 11451cea05afSdougm * 11461cea05afSdougm * Get a linked list of all the shares on the system from 11471cea05afSdougm * /etc/dfs/sharetab. This is partially copied from libfsmgt which we 11481cea05afSdougm * can't use due to package dependencies. 11491cea05afSdougm */ 11501cea05afSdougm static xfs_sharelist_t * 11511cea05afSdougm get_share_list(int *errp) 11521cea05afSdougm { 11531cea05afSdougm xfs_sharelist_t *newp; 11541cea05afSdougm xfs_sharelist_t *headp; 11551cea05afSdougm xfs_sharelist_t *tailp; 11561cea05afSdougm FILE *fp; 11571cea05afSdougm 11581cea05afSdougm headp = NULL; 11591cea05afSdougm tailp = NULL; 11601cea05afSdougm 11611cea05afSdougm if ((fp = fopen(SHARETAB, "r")) != NULL) { 11621cea05afSdougm struct share *sharetab_entry; 11631cea05afSdougm 11641cea05afSdougm while (getshare(fp, &sharetab_entry) > 0) { 11651cea05afSdougm newp = alloc_sharelist(); 11661cea05afSdougm if (newp == NULL) { 11671cea05afSdougm goto err; 11681cea05afSdougm } 11691cea05afSdougm 11701cea05afSdougm /* 11711cea05afSdougm * link into the list here so we don't leak 11721cea05afSdougm * memory on a failure from strdup(). 11731cea05afSdougm */ 11741cea05afSdougm if (headp == NULL) { 11751cea05afSdougm headp = newp; 11761cea05afSdougm tailp = newp; 11771cea05afSdougm } else { 11781cea05afSdougm tailp->next = newp; 11791cea05afSdougm tailp = newp; 11801cea05afSdougm } 11811cea05afSdougm 11821cea05afSdougm newp->path = strdup(sharetab_entry->sh_path); 11831cea05afSdougm if (newp->path == NULL) 11841cea05afSdougm goto err; 11851cea05afSdougm newp->resource = strdup(sharetab_entry->sh_res); 11861cea05afSdougm if (newp->resource == NULL) 11871cea05afSdougm goto err; 11881cea05afSdougm newp->fstype = strdup(sharetab_entry->sh_fstype); 11891cea05afSdougm if (newp->fstype == NULL) 11901cea05afSdougm goto err; 11911cea05afSdougm newp->options = strdup(sharetab_entry->sh_opts); 11921cea05afSdougm if (newp->options == NULL) 11931cea05afSdougm goto err; 11941cea05afSdougm newp->description = strdup(sharetab_entry->sh_descr); 11951cea05afSdougm if (newp->description == NULL) 11961cea05afSdougm goto err; 11971cea05afSdougm } 11981cea05afSdougm (void) fclose(fp); 11991cea05afSdougm } else { 12001cea05afSdougm *errp = errno; 12011cea05afSdougm } 12021cea05afSdougm 12031cea05afSdougm /* 12041cea05afSdougm * Caller must free the mount list 12051cea05afSdougm */ 12061cea05afSdougm return (headp); 12071cea05afSdougm err: 12081cea05afSdougm /* 12091cea05afSdougm * Out of memory so cleanup and leave. 12101cea05afSdougm */ 12111cea05afSdougm dfs_free_list(headp); 12121cea05afSdougm (void) fclose(fp); 12131cea05afSdougm return (NULL); 12141cea05afSdougm } 12151cea05afSdougm 12166185db85Sdougm /* 12176185db85Sdougm * parse_sharetab(void) 12186185db85Sdougm * 12191cea05afSdougm * Read the /etc/dfs/sharetab file and see which entries don't exist 12201cea05afSdougm * in the repository. These shares are marked transient. We also need 12211cea05afSdougm * to see if they are ZFS shares since ZFS bypasses the SMF 12221cea05afSdougm * repository. 12236185db85Sdougm */ 12246185db85Sdougm 12256185db85Sdougm int 12266185db85Sdougm parse_sharetab(void) 12276185db85Sdougm { 12281cea05afSdougm xfs_sharelist_t *list, *tmplist; 12296185db85Sdougm int err = 0; 12306185db85Sdougm sa_share_t share; 12316185db85Sdougm sa_group_t group; 12326185db85Sdougm sa_group_t lgroup; 12336185db85Sdougm char *groupname; 12346185db85Sdougm int legacy = 0; 12356185db85Sdougm 12361cea05afSdougm list = get_share_list(&err); 12376185db85Sdougm if (list == NULL) 12386185db85Sdougm return (legacy); 12396185db85Sdougm 12406185db85Sdougm lgroup = sa_get_group("default"); 12416185db85Sdougm 12426185db85Sdougm for (tmplist = list; tmplist != NULL; tmplist = tmplist->next) { 12436185db85Sdougm group = NULL; 12446185db85Sdougm share = sa_find_share(tmplist->path); 12456185db85Sdougm if (share == NULL) { 12466185db85Sdougm /* 12476185db85Sdougm * this share is transient so needs to be 12486185db85Sdougm * added. Initially, this will be under 12496185db85Sdougm * default(legacy) unless it is a ZFS 12506185db85Sdougm * share. If zfs, we need a zfs group. 12516185db85Sdougm */ 12526185db85Sdougm if (tmplist->resource != NULL && 12536185db85Sdougm (groupname = strchr(tmplist->resource, '@')) != NULL) { 12546185db85Sdougm /* there is a defined group */ 12556185db85Sdougm *groupname++ = '\0'; 12566185db85Sdougm group = sa_get_group(groupname); 12576185db85Sdougm if (group != NULL) { 12586185db85Sdougm share = _sa_add_share(group, tmplist->path, 12596185db85Sdougm SA_SHARE_TRANSIENT, &err); 12606185db85Sdougm } else { 126193a6f655Sdougm /* 126293a6f655Sdougm * While this case shouldn't occur very often, 126393a6f655Sdougm * it does occur out of a "zfs set 126493a6f655Sdougm * sharenfs=off" when the dataset is also set 126593a6f655Sdougm * to canmount=off. A warning will then cause 126693a6f655Sdougm * the zfs command to abort. Since we add it 126793a6f655Sdougm * to the default list, everything works 126893a6f655Sdougm * properly anyway and the library doesn't 126993a6f655Sdougm * need to give a warning. 127093a6f655Sdougm */ 12716185db85Sdougm share = _sa_add_share(lgroup, tmplist->path, 12726185db85Sdougm SA_SHARE_TRANSIENT, &err); 12736185db85Sdougm } 12746185db85Sdougm } else { 12756185db85Sdougm if (sa_zfs_is_shared(tmplist->path)) { 12766185db85Sdougm group = sa_get_group("zfs"); 12776185db85Sdougm if (group == NULL) { 12786185db85Sdougm group = sa_create_group("zfs", &err); 12796185db85Sdougm if (group == NULL && err == SA_NO_PERMISSION) { 12806185db85Sdougm group = _sa_create_group("zfs"); 12816185db85Sdougm } 12826185db85Sdougm if (group != NULL) { 12836185db85Sdougm (void) sa_create_optionset(group, 12846185db85Sdougm tmplist->fstype); 12856185db85Sdougm (void) sa_set_group_attr(group, "zfs", "true"); 12866185db85Sdougm } 12876185db85Sdougm } 12886185db85Sdougm if (group != NULL) { 12896185db85Sdougm share = _sa_add_share(group, tmplist->path, 12906185db85Sdougm SA_SHARE_TRANSIENT, &err); 12916185db85Sdougm } 12926185db85Sdougm } else { 12936185db85Sdougm share = _sa_add_share(lgroup, tmplist->path, 12946185db85Sdougm SA_SHARE_TRANSIENT, &err); 12956185db85Sdougm } 12966185db85Sdougm } 12976185db85Sdougm if (share == NULL) 12986185db85Sdougm (void) printf(gettext("Problem with transient: %s\n"), 12996185db85Sdougm sa_errorstr(err)); 13006185db85Sdougm if (share != NULL) 13016185db85Sdougm set_node_attr(share, "shared", "true"); 13026185db85Sdougm 13036185db85Sdougm if (err == SA_OK) { 13046185db85Sdougm if (tmplist->options != NULL && 13056185db85Sdougm strlen(tmplist->options) > 0) { 13066185db85Sdougm (void) sa_parse_legacy_options(share, 13076185db85Sdougm tmplist->options, 13086185db85Sdougm tmplist->fstype); 13096185db85Sdougm } 13106185db85Sdougm if (tmplist->resource != NULL && 13116185db85Sdougm strcmp(tmplist->resource, "-") != 0) 13126185db85Sdougm set_node_attr(share, "resource", tmplist->resource); 13136185db85Sdougm if (tmplist->description != NULL) { 13146185db85Sdougm xmlNodePtr node; 13156185db85Sdougm node = xmlNewChild((xmlNodePtr)share, NULL, 13166185db85Sdougm (xmlChar *)"description", NULL); 13176185db85Sdougm xmlNodeSetContent(node, 13186185db85Sdougm (xmlChar *)tmplist->description); 13196185db85Sdougm } 13206185db85Sdougm legacy = 1; 13216185db85Sdougm } 13226185db85Sdougm } else { 13236185db85Sdougm /* 13246185db85Sdougm * if this is a legacy share, mark as shared so we 1325*f345c0beSdougm * only update sharetab appropriately. We also keep 1326*f345c0beSdougm * the sharetab options in order to display for legacy 1327*f345c0beSdougm * share with no arguments. 13286185db85Sdougm */ 13296185db85Sdougm set_node_attr(share, "shared", "true"); 1330*f345c0beSdougm set_node_attr(share, "shareopts", tmplist->options); 13316185db85Sdougm } 13326185db85Sdougm } 13331cea05afSdougm dfs_free_list(list); 13346185db85Sdougm return (legacy); 13356185db85Sdougm } 13366185db85Sdougm 13376185db85Sdougm /* 13386185db85Sdougm * get the transient shares from the sharetab (or other) file. since 13396185db85Sdougm * these are transient, they only appear in the working file and not 13406185db85Sdougm * in a repository. 13416185db85Sdougm */ 13426185db85Sdougm int 13436185db85Sdougm gettransients(xmlNodePtr *root) 13446185db85Sdougm { 13456185db85Sdougm int legacy = 0; 13466185db85Sdougm 13476185db85Sdougm if (root != NULL) { 13486185db85Sdougm if (*root == NULL) 13496185db85Sdougm *root = xmlNewNode(NULL, (xmlChar *)"sharecfg"); 13506185db85Sdougm if (*root != NULL) { 13516185db85Sdougm legacy = parse_sharetab(); 13526185db85Sdougm } 13536185db85Sdougm } 13546185db85Sdougm return (legacy); 13556185db85Sdougm } 13566185db85Sdougm 13576185db85Sdougm /* 13586185db85Sdougm * sa_has_prop(optionset, prop) 13596185db85Sdougm * 13606185db85Sdougm * Is the specified property a member of the optionset? 13616185db85Sdougm */ 13626185db85Sdougm 13636185db85Sdougm int 13646185db85Sdougm sa_has_prop(sa_optionset_t optionset, sa_property_t prop) 13656185db85Sdougm { 13666185db85Sdougm char *name; 13676185db85Sdougm sa_property_t otherprop; 13686185db85Sdougm int result = 0; 13696185db85Sdougm 13706185db85Sdougm if (optionset != NULL) { 13716185db85Sdougm name = sa_get_property_attr(prop, "type"); 13726185db85Sdougm if (name != NULL) { 13736185db85Sdougm otherprop = sa_get_property(optionset, name); 13746185db85Sdougm if (otherprop != NULL) 13756185db85Sdougm result = 1; 13766185db85Sdougm sa_free_attr_string(name); 13776185db85Sdougm } 13786185db85Sdougm } 13796185db85Sdougm return (result); 13806185db85Sdougm } 13816185db85Sdougm 13826185db85Sdougm /* 13836185db85Sdougm * Update legacy files 13846185db85Sdougm * 13856185db85Sdougm * Provides functions to add/remove/modify individual entries 13866185db85Sdougm * in dfstab and sharetab 13876185db85Sdougm */ 13886185db85Sdougm 13896185db85Sdougm void 13906185db85Sdougm update_legacy_config(void) 13916185db85Sdougm { 13926185db85Sdougm /* 13936185db85Sdougm * no longer used -- this is a placeholder in case we need to 13946185db85Sdougm * add it back later. 13956185db85Sdougm */ 13966185db85Sdougm } 13976185db85Sdougm 13986185db85Sdougm /* 13996185db85Sdougm * sa_valid_property(object, proto, property) 14006185db85Sdougm * 14016185db85Sdougm * check to see if the specified property is valid relative to the 14026185db85Sdougm * specified protocol. The protocol plugin is called to do the work. 14036185db85Sdougm */ 14046185db85Sdougm 14056185db85Sdougm int 14066185db85Sdougm sa_valid_property(void *object, char *proto, sa_property_t property) 14076185db85Sdougm { 14086185db85Sdougm int ret = SA_OK; 14096185db85Sdougm 14106185db85Sdougm if (proto != NULL && property != NULL) { 14116185db85Sdougm ret = sa_proto_valid_prop(proto, property, object); 14126185db85Sdougm } 14136185db85Sdougm 14146185db85Sdougm return (ret); 14156185db85Sdougm } 14166185db85Sdougm 14176185db85Sdougm /* 14186185db85Sdougm * sa_fstype(path) 14196185db85Sdougm * 14206185db85Sdougm * Given path, return the string representing the path's file system 14216185db85Sdougm * type. This is used to discover ZFS shares. 14226185db85Sdougm */ 14236185db85Sdougm 14246185db85Sdougm char * 14256185db85Sdougm sa_fstype(char *path) 14266185db85Sdougm { 14276185db85Sdougm int err; 14286185db85Sdougm struct stat st; 14296185db85Sdougm 14306185db85Sdougm err = stat(path, &st); 14316185db85Sdougm if (err < 0) { 14326185db85Sdougm err = SA_NO_SUCH_PATH; 14336185db85Sdougm } else { 14346185db85Sdougm err = SA_OK; 14356185db85Sdougm } 14366185db85Sdougm if (err == SA_OK) { 14376185db85Sdougm /* have a valid path at this point */ 14386185db85Sdougm return (strdup(st.st_fstype)); 14396185db85Sdougm } 14406185db85Sdougm return (NULL); 14416185db85Sdougm } 14426185db85Sdougm 14436185db85Sdougm void 14446185db85Sdougm sa_free_fstype(char *type) 14456185db85Sdougm { 14466185db85Sdougm free(type); 14476185db85Sdougm } 14486185db85Sdougm 14496185db85Sdougm /* 14506185db85Sdougm * sa_get_derived_optionset(object, proto, hier) 14516185db85Sdougm * 14526185db85Sdougm * Work backward to the top of the share object tree and start 14536185db85Sdougm * copying protocol specific optionsets into a newly created 14546185db85Sdougm * optionset that doesn't have a parent (it will be freed 14556185db85Sdougm * later). This provides for the property inheritence model. That 14566185db85Sdougm * is, properties closer to the share take precedence over group 14576185db85Sdougm * level. This also provides for groups of groups in the future. 14586185db85Sdougm */ 14596185db85Sdougm 14606185db85Sdougm sa_optionset_t 14616185db85Sdougm sa_get_derived_optionset(void *object, char *proto, int hier) 14626185db85Sdougm { 14636185db85Sdougm sa_optionset_t newoptionset; 14646185db85Sdougm sa_optionset_t optionset; 14656185db85Sdougm sa_group_t group; 14666185db85Sdougm 14676185db85Sdougm if (hier && 14686185db85Sdougm (group = sa_get_parent_group((sa_share_t)object)) != NULL) { 14696185db85Sdougm newoptionset = sa_get_derived_optionset((void *)group, proto, hier); 14706185db85Sdougm } else { 14716185db85Sdougm newoptionset = (sa_optionset_t)xmlNewNode(NULL, 14726185db85Sdougm (xmlChar *)"optionset"); 14736185db85Sdougm if (newoptionset != NULL) { 14746185db85Sdougm sa_set_optionset_attr(newoptionset, "type", proto); 14756185db85Sdougm } 14766185db85Sdougm } 14776185db85Sdougm /* dont' do anything if memory wasn't allocated */ 14786185db85Sdougm if (newoptionset == NULL) 14796185db85Sdougm return (NULL); 14806185db85Sdougm 14816185db85Sdougm /* found the top so working back down the stack */ 14826185db85Sdougm optionset = sa_get_optionset((sa_optionset_t)object, proto); 14836185db85Sdougm if (optionset != NULL) { 14846185db85Sdougm sa_property_t prop; 14856185db85Sdougm /* add optionset to the newoptionset */ 14866185db85Sdougm for (prop = sa_get_property(optionset, NULL); 14876185db85Sdougm prop != NULL; prop = sa_get_next_property(prop)) { 14886185db85Sdougm sa_property_t newprop; 14896185db85Sdougm char *name; 14906185db85Sdougm char *value; 14916185db85Sdougm name = sa_get_property_attr(prop, "type"); 14926185db85Sdougm value = sa_get_property_attr(prop, "value"); 14936185db85Sdougm if (name != NULL) { 14946185db85Sdougm newprop = sa_get_property(newoptionset, name); 14956185db85Sdougm /* replace the value with the new value */ 14966185db85Sdougm if (newprop != NULL) { 14976185db85Sdougm /* 14986185db85Sdougm * only set if value is non NULL, old value ok 14996185db85Sdougm * if it is NULL. 15006185db85Sdougm */ 15016185db85Sdougm if (value != NULL) 15026185db85Sdougm set_node_attr(newprop, "value", value); 15036185db85Sdougm } else { 15046185db85Sdougm /* an entirely new property */ 15056185db85Sdougm if (value != NULL) { 15066185db85Sdougm newprop = sa_create_property(name, value); 15076185db85Sdougm if (newprop != NULL) { 15086185db85Sdougm newprop = (sa_property_t) 15096185db85Sdougm xmlAddChild((xmlNodePtr)newoptionset, 15106185db85Sdougm (xmlNodePtr)newprop); 15116185db85Sdougm } 15126185db85Sdougm } 15136185db85Sdougm } 15146185db85Sdougm sa_free_attr_string(name); 15156185db85Sdougm } 15166185db85Sdougm if (value != NULL) 15176185db85Sdougm sa_free_attr_string(value); 15186185db85Sdougm } 15196185db85Sdougm } 15206185db85Sdougm return (newoptionset); 15216185db85Sdougm } 15226185db85Sdougm 15236185db85Sdougm void 15246185db85Sdougm sa_free_derived_optionset(sa_optionset_t optionset) 15256185db85Sdougm { 15266185db85Sdougm /* while it shouldn't be linked, it doesn't hurt */ 15276185db85Sdougm if (optionset != NULL) { 15286185db85Sdougm xmlUnlinkNode((xmlNodePtr) optionset); 15296185db85Sdougm xmlFreeNode((xmlNodePtr) optionset); 15306185db85Sdougm } 15316185db85Sdougm } 15326185db85Sdougm 15336185db85Sdougm /* 15346185db85Sdougm * sa_get_all_security_types(object, proto, hier) 15356185db85Sdougm * 15366185db85Sdougm * find all the security types set for this object. This is 15376185db85Sdougm * preliminary to getting a derived security set. The return value is an 15386185db85Sdougm * optionset containg properties which are the sectype values found by 15396185db85Sdougm * walking up the XML document struture. The returned optionset 15406185db85Sdougm * is a derived optionset. 15416185db85Sdougm * 15426185db85Sdougm * If hier is 0, only look at object. If non-zero, walk up the tree. 15436185db85Sdougm */ 15446185db85Sdougm sa_optionset_t 15456185db85Sdougm sa_get_all_security_types(void *object, char *proto, int hier) 15466185db85Sdougm { 15476185db85Sdougm sa_optionset_t options; 15486185db85Sdougm sa_security_t security; 15496185db85Sdougm sa_group_t group; 15506185db85Sdougm sa_property_t prop; 15516185db85Sdougm 15526185db85Sdougm options = NULL; 15536185db85Sdougm 15546185db85Sdougm if (hier && 15556185db85Sdougm (group = sa_get_parent_group((sa_share_t)object)) != NULL) { 15566185db85Sdougm options = sa_get_all_security_types((void *)group, proto, hier); 15576185db85Sdougm } else { 15586185db85Sdougm options = (sa_optionset_t)xmlNewNode(NULL, 15596185db85Sdougm (xmlChar *)"optionset"); 15606185db85Sdougm } 15616185db85Sdougm /* hit the top so collect the security types working back */ 15626185db85Sdougm if (options != NULL) { 15636185db85Sdougm for (security = sa_get_security((sa_group_t)object, NULL, NULL); 15646185db85Sdougm security != NULL; security = sa_get_next_security(security)) { 15656185db85Sdougm char *type; 15666185db85Sdougm char *sectype; 15676185db85Sdougm 15686185db85Sdougm type = sa_get_security_attr(security, "type"); 15696185db85Sdougm if (type != NULL) { 15706185db85Sdougm if (strcmp(type, proto) != 0) { 15716185db85Sdougm sa_free_attr_string(type); 15726185db85Sdougm continue; 15736185db85Sdougm } 15746185db85Sdougm sectype = sa_get_security_attr(security, "sectype"); 15756185db85Sdougm if (sectype != NULL) { 15766185db85Sdougm /* 15776185db85Sdougm * have a security type, check to see if 15786185db85Sdougm * already present in optionset and add if it 15796185db85Sdougm * isn't. 15806185db85Sdougm */ 15816185db85Sdougm if (sa_get_property(options, sectype) == NULL) { 15826185db85Sdougm prop = sa_create_property(sectype, "true"); 15836185db85Sdougm if (prop != NULL) 15846185db85Sdougm prop = (sa_property_t) 15856185db85Sdougm xmlAddChild((xmlNodePtr)options, 15866185db85Sdougm (xmlNodePtr)prop); 15876185db85Sdougm } 15886185db85Sdougm sa_free_attr_string(sectype); 15896185db85Sdougm } 15906185db85Sdougm sa_free_attr_string(type); 15916185db85Sdougm } 15926185db85Sdougm } 15936185db85Sdougm } 15946185db85Sdougm return (options); 15956185db85Sdougm } 15966185db85Sdougm 15976185db85Sdougm /* 15986185db85Sdougm * sa_get_derived_security(object, sectype, proto, hier) 15996185db85Sdougm * 16006185db85Sdougm * Get the derived security(named optionset) for the object given the 16016185db85Sdougm * sectype and proto. If hier is non-zero, walk up the tree to get all 16026185db85Sdougm * properties defined for this object, otherwise just those on the 16036185db85Sdougm * object. 16046185db85Sdougm */ 16056185db85Sdougm 16066185db85Sdougm sa_security_t 16076185db85Sdougm sa_get_derived_security(void *object, char *sectype, char *proto, int hier) 16086185db85Sdougm { 16096185db85Sdougm sa_security_t newsecurity; 16106185db85Sdougm sa_security_t security; 16116185db85Sdougm sa_group_t group; 16126185db85Sdougm 16136185db85Sdougm if (hier && 16146185db85Sdougm (group = sa_get_parent_group((sa_share_t)object)) != NULL) { 16156185db85Sdougm newsecurity = sa_get_derived_security((void *)group, 16166185db85Sdougm sectype, proto, hier); 16176185db85Sdougm } else { 16186185db85Sdougm newsecurity = (sa_security_t)xmlNewNode(NULL, 16196185db85Sdougm (xmlChar *)"security"); 16206185db85Sdougm if (newsecurity != NULL) { 16216185db85Sdougm sa_set_security_attr(newsecurity, "type", proto); 16226185db85Sdougm sa_set_security_attr(newsecurity, "sectype", sectype); 16236185db85Sdougm } 16246185db85Sdougm } 16256185db85Sdougm /* dont' do anything if memory wasn't allocated */ 16266185db85Sdougm if (newsecurity == NULL) 16276185db85Sdougm return (NULL); 16286185db85Sdougm 16296185db85Sdougm /* found the top so working back down the stack */ 16306185db85Sdougm security = sa_get_security((sa_security_t)object, sectype, proto); 16316185db85Sdougm if (security != NULL) { 16326185db85Sdougm sa_property_t prop; 16336185db85Sdougm /* add security to the newsecurity */ 16346185db85Sdougm for (prop = sa_get_property(security, NULL); 16356185db85Sdougm prop != NULL; prop = sa_get_next_property(prop)) { 16366185db85Sdougm sa_property_t newprop; 16376185db85Sdougm char *name; 16386185db85Sdougm char *value; 16396185db85Sdougm name = sa_get_property_attr(prop, "type"); 16406185db85Sdougm value = sa_get_property_attr(prop, "value"); 16416185db85Sdougm if (name != NULL) { 16426185db85Sdougm newprop = sa_get_property(newsecurity, name); 16436185db85Sdougm /* replace the value with the new value */ 16446185db85Sdougm if (newprop != NULL) { 16456185db85Sdougm /* 16466185db85Sdougm * only set if value is non NULL, old value ok 16476185db85Sdougm * if it is NULL. 16486185db85Sdougm */ 16496185db85Sdougm if (value != NULL) 16506185db85Sdougm set_node_attr(newprop, name, value); 16516185db85Sdougm } else { 16526185db85Sdougm /* an entirely new property */ 16536185db85Sdougm if (value != NULL) { 16546185db85Sdougm newprop = sa_create_property(name, value); 16556185db85Sdougm newprop = (sa_property_t) 16566185db85Sdougm xmlAddChild((xmlNodePtr)newsecurity, 16576185db85Sdougm (xmlNodePtr)newprop); 16586185db85Sdougm } 16596185db85Sdougm } 16606185db85Sdougm sa_free_attr_string(name); 16616185db85Sdougm } 16626185db85Sdougm if (value != NULL) 16636185db85Sdougm sa_free_attr_string(value); 16646185db85Sdougm } 16656185db85Sdougm } 16666185db85Sdougm return (newsecurity); 16676185db85Sdougm } 16686185db85Sdougm 16696185db85Sdougm void 16706185db85Sdougm sa_free_derived_security(sa_security_t security) 16716185db85Sdougm { 16726185db85Sdougm /* while it shouldn't be linked, it doesn't hurt */ 16736185db85Sdougm if (security != NULL) { 16746185db85Sdougm xmlUnlinkNode((xmlNodePtr)security); 16756185db85Sdougm xmlFreeNode((xmlNodePtr)security); 16766185db85Sdougm } 16776185db85Sdougm } 16786185db85Sdougm 16796185db85Sdougm /* 16806185db85Sdougm * sharetab utility functions 16816185db85Sdougm * 16826185db85Sdougm * makes use of the original sharetab.c from fs.d/nfs/lib 16836185db85Sdougm */ 16846185db85Sdougm 16856185db85Sdougm /* 16866185db85Sdougm * fillshare(share, proto, sh) 16876185db85Sdougm * 16886185db85Sdougm * Fill the struct share with values obtained from the share object. 16896185db85Sdougm */ 16906185db85Sdougm static void 16916185db85Sdougm fillshare(sa_share_t share, char *proto, struct share *sh) 16926185db85Sdougm { 16936185db85Sdougm char *groupname = NULL; 16946185db85Sdougm char *value; 16956185db85Sdougm sa_group_t group; 16966185db85Sdougm char *buff; 16976185db85Sdougm char *zfs; 16986185db85Sdougm 16996185db85Sdougm group = sa_get_parent_group(share); 17006185db85Sdougm if (group != NULL) { 17016185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 17026185db85Sdougm groupname = sa_get_group_attr(group, "name"); 17036185db85Sdougm 17046185db85Sdougm if (groupname != NULL && 17056185db85Sdougm (strcmp(groupname, "default") == 0 || zfs != NULL)) { 17066185db85Sdougm /* 17076185db85Sdougm * since the groupname is either "default" or the 17086185db85Sdougm * group is a ZFS group, we don't want to keep 17096185db85Sdougm * groupname. We do want it if it is any other type of 17106185db85Sdougm * group. 17116185db85Sdougm */ 17126185db85Sdougm sa_free_attr_string(groupname); 17136185db85Sdougm groupname = NULL; 17146185db85Sdougm } 17156185db85Sdougm if (zfs != NULL) 17166185db85Sdougm sa_free_attr_string(zfs); 17176185db85Sdougm } 17186185db85Sdougm 17196185db85Sdougm value = sa_get_share_attr(share, "path"); 17206185db85Sdougm if (value != NULL) { 17216185db85Sdougm sh->sh_path = strdup(value); 17226185db85Sdougm sa_free_attr_string(value); 17236185db85Sdougm } 17246185db85Sdougm 17256185db85Sdougm value = sa_get_share_attr(share, "resource"); 17266185db85Sdougm if (value != NULL || groupname != NULL) { 17276185db85Sdougm int len = 0; 17286185db85Sdougm 17296185db85Sdougm if (value != NULL) 17306185db85Sdougm len += strlen(value); 17316185db85Sdougm if (groupname != NULL) 17326185db85Sdougm len += strlen(groupname); 17336185db85Sdougm len += 3; /* worst case */ 17346185db85Sdougm buff = malloc(len); 17356185db85Sdougm (void) snprintf(buff, len, "%s%s%s", 17366185db85Sdougm (value != NULL && strlen(value) > 0) ? value : "-", 17376185db85Sdougm groupname != NULL ? "@" : "", 17386185db85Sdougm groupname != NULL ? groupname : ""); 17396185db85Sdougm sh->sh_res = buff; 17406185db85Sdougm if (value != NULL) 17416185db85Sdougm sa_free_attr_string(value); 17426185db85Sdougm if (groupname != NULL) { 17436185db85Sdougm sa_free_attr_string(groupname); 17446185db85Sdougm groupname = NULL; 17456185db85Sdougm } 17466185db85Sdougm } else { 17476185db85Sdougm sh->sh_res = strdup("-"); 17486185db85Sdougm } 17496185db85Sdougm 17506185db85Sdougm sh->sh_fstype = strdup(proto); 17516185db85Sdougm value = sa_proto_legacy_format(proto, share, 1); 17526185db85Sdougm if (value != NULL) { 17536185db85Sdougm if (strlen(value) > 0) 17546185db85Sdougm sh->sh_opts = strdup(value); 17556185db85Sdougm else 17566185db85Sdougm sh->sh_opts = strdup("rw"); 17576185db85Sdougm free(value); 17586185db85Sdougm } else 17596185db85Sdougm sh->sh_opts = strdup("rw"); 17606185db85Sdougm 17616185db85Sdougm value = sa_get_share_description(share); 17626185db85Sdougm if (value != NULL) { 17636185db85Sdougm sh->sh_descr = strdup(value); 17646185db85Sdougm sa_free_share_description(value); 17656185db85Sdougm } else 17666185db85Sdougm sh->sh_descr = strdup(""); 17676185db85Sdougm } 17686185db85Sdougm 17696185db85Sdougm /* 17706185db85Sdougm * emptyshare(sh) 17716185db85Sdougm * 17726185db85Sdougm * Free the strings in the non-NULL members of sh. 17736185db85Sdougm */ 17746185db85Sdougm 17756185db85Sdougm static void 17766185db85Sdougm emptyshare(struct share *sh) 17776185db85Sdougm { 17786185db85Sdougm if (sh->sh_path != NULL) 17796185db85Sdougm free(sh->sh_path); 17806185db85Sdougm sh->sh_path = NULL; 17816185db85Sdougm if (sh->sh_res != NULL) 17826185db85Sdougm free(sh->sh_res); 17836185db85Sdougm sh->sh_res = NULL; 17846185db85Sdougm if (sh->sh_fstype != NULL) 17856185db85Sdougm free(sh->sh_fstype); 17866185db85Sdougm sh->sh_fstype = NULL; 17876185db85Sdougm if (sh->sh_opts != NULL) 17886185db85Sdougm free(sh->sh_opts); 17896185db85Sdougm sh->sh_opts = NULL; 17906185db85Sdougm if (sh->sh_descr != NULL) 17916185db85Sdougm free(sh->sh_descr); 17926185db85Sdougm sh->sh_descr = NULL; 17936185db85Sdougm } 17946185db85Sdougm 17956185db85Sdougm /* 17966185db85Sdougm * sa_update_sharetab(share, proto) 17976185db85Sdougm * 17986185db85Sdougm * Update the sharetab file with info from the specified share. 17996185db85Sdougm * This could be an update or add. 18006185db85Sdougm */ 18016185db85Sdougm 18026185db85Sdougm int 18036185db85Sdougm sa_update_sharetab(sa_share_t share, char *proto) 18046185db85Sdougm { 18056185db85Sdougm int ret = SA_OK; 18066185db85Sdougm struct share shtab; 18076185db85Sdougm char *path; 18086185db85Sdougm int logging = 0; 18096185db85Sdougm FILE *sharetab; 18106185db85Sdougm sigset_t old, new; 18116185db85Sdougm 18126185db85Sdougm path = sa_get_share_attr(share, "path"); 18136185db85Sdougm if (path != NULL) { 18146185db85Sdougm (void) memset(&shtab, '\0', sizeof (shtab)); 18156185db85Sdougm sharetab = fopen(SA_LEGACY_SHARETAB, "r+"); 18166185db85Sdougm if (sharetab == NULL) { 18176185db85Sdougm sharetab = fopen(SA_LEGACY_SHARETAB, "w+"); 18186185db85Sdougm } 18196185db85Sdougm if (sharetab != NULL) { 18206185db85Sdougm (void) setvbuf(sharetab, NULL, _IOLBF, BUFSIZ * 8); 18216185db85Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 18226185db85Sdougm (void) sigaddset(&new, SIGHUP); 18236185db85Sdougm (void) sigaddset(&new, SIGINT); 18246185db85Sdougm (void) sigaddset(&new, SIGQUIT); 18256185db85Sdougm (void) sigaddset(&new, SIGTSTP); 18266185db85Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 18276185db85Sdougm (void) lockf(fileno(sharetab), F_LOCK, 0); 18286185db85Sdougm (void) remshare(sharetab, path, &logging); 18296185db85Sdougm /* fill in share structure and write it out */ 18306185db85Sdougm (void) fillshare(share, proto, &shtab); 18316185db85Sdougm (void) putshare(sharetab, &shtab); 18326185db85Sdougm emptyshare(&shtab); 18336185db85Sdougm (void) fflush(sharetab); 18346185db85Sdougm (void) lockf(fileno(sharetab), F_ULOCK, 0); 18356185db85Sdougm (void) fsync(fileno(sharetab)); 18366185db85Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 18376185db85Sdougm (void) fclose(sharetab); 18386185db85Sdougm } else { 18396185db85Sdougm if (errno == EACCES || errno == EPERM) { 18406185db85Sdougm ret = SA_NO_PERMISSION; 18416185db85Sdougm } else { 18426185db85Sdougm ret = SA_CONFIG_ERR; 18436185db85Sdougm } 18446185db85Sdougm } 18456185db85Sdougm sa_free_attr_string(path); 18466185db85Sdougm } 18476185db85Sdougm return (ret); 18486185db85Sdougm } 18496185db85Sdougm 18506185db85Sdougm /* 18516185db85Sdougm * sa_delete_sharetab(path, proto) 18526185db85Sdougm * 18536185db85Sdougm * remove the specified share from sharetab. 18546185db85Sdougm */ 18556185db85Sdougm 18566185db85Sdougm int 18576185db85Sdougm sa_delete_sharetab(char *path, char *proto) 18586185db85Sdougm { 18596185db85Sdougm int ret = SA_OK; 18606185db85Sdougm int logging = 0; 18616185db85Sdougm FILE *sharetab; 18626185db85Sdougm sigset_t old, new; 18636185db85Sdougm #ifdef lint 18646185db85Sdougm proto = proto; 18656185db85Sdougm #endif 18666185db85Sdougm 18676185db85Sdougm if (path != NULL) { 18686185db85Sdougm sharetab = fopen(SA_LEGACY_SHARETAB, "r+"); 18696185db85Sdougm if (sharetab == NULL) { 18706185db85Sdougm sharetab = fopen(SA_LEGACY_SHARETAB, "w+"); 18716185db85Sdougm } 18726185db85Sdougm if (sharetab != NULL) { 18736185db85Sdougm /* should block keyboard level signals around the lock */ 18746185db85Sdougm (void) sigprocmask(SIG_BLOCK, NULL, &new); 18756185db85Sdougm (void) sigaddset(&new, SIGHUP); 18766185db85Sdougm (void) sigaddset(&new, SIGINT); 18776185db85Sdougm (void) sigaddset(&new, SIGQUIT); 18786185db85Sdougm (void) sigaddset(&new, SIGTSTP); 18796185db85Sdougm (void) sigprocmask(SIG_SETMASK, &new, &old); 18806185db85Sdougm (void) lockf(fileno(sharetab), F_LOCK, 0); 18816185db85Sdougm ret = remshare(sharetab, path, &logging); 18826185db85Sdougm (void) fflush(sharetab); 18836185db85Sdougm (void) lockf(fileno(sharetab), F_ULOCK, 0); 18846185db85Sdougm (void) fsync(fileno(sharetab)); 18856185db85Sdougm (void) sigprocmask(SIG_SETMASK, &old, NULL); 18866185db85Sdougm (void) fclose(sharetab); 18876185db85Sdougm } else { 18886185db85Sdougm if (errno == EACCES || errno == EPERM) { 18896185db85Sdougm ret = SA_NO_PERMISSION; 18906185db85Sdougm } else { 18916185db85Sdougm ret = SA_CONFIG_ERR; 18926185db85Sdougm } 18936185db85Sdougm } 18946185db85Sdougm } 18956185db85Sdougm return (ret); 18966185db85Sdougm } 1897