xref: /onnv-gate/usr/src/lib/libshare/common/libsharecore.c (revision 12508:edb7861a1533)
13034Sdougm /*
23034Sdougm  * CDDL HEADER START
33034Sdougm  *
43034Sdougm  * The contents of this file are subject to the terms of the
53034Sdougm  * Common Development and Distribution License (the "License").
63034Sdougm  * You may not use this file except in compliance with the License.
73034Sdougm  *
83034Sdougm  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93034Sdougm  * or http://www.opensolaris.org/os/licensing.
103034Sdougm  * See the License for the specific language governing permissions
113034Sdougm  * and limitations under the License.
123034Sdougm  *
133034Sdougm  * When distributing Covered Code, include this CDDL HEADER in each
143034Sdougm  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153034Sdougm  * If applicable, add the following below this CDDL HEADER, with the
163034Sdougm  * fields enclosed by brackets "[]" replaced with your own identifying
173034Sdougm  * information: Portions Copyright [yyyy] [name of copyright owner]
183034Sdougm  *
193034Sdougm  * CDDL HEADER END
203034Sdougm  */
213034Sdougm 
223034Sdougm /*
23*12508Samw@Sun.COM  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
243034Sdougm  */
253034Sdougm 
263034Sdougm /*
273034Sdougm  * core library for common functions across all config store types
283034Sdougm  * and file systems to be exported. This includes legacy dfstab/sharetab
293034Sdougm  * parsing. Need to eliminate XML where possible.
303034Sdougm  */
313034Sdougm 
323034Sdougm #include <stdio.h>
333034Sdougm #include <string.h>
343034Sdougm #include <ctype.h>
353034Sdougm #include <unistd.h>
363034Sdougm #include <limits.h>
373034Sdougm #include <errno.h>
383034Sdougm #include <sys/types.h>
393034Sdougm #include <sys/stat.h>
403034Sdougm #include <libxml/parser.h>
413034Sdougm #include <libxml/tree.h>
423034Sdougm #include "libshare.h"
433034Sdougm #include "libshare_impl.h"
443034Sdougm #include <fcntl.h>
458334SJose.Borrego@Sun.COM #include <thread.h>
463034Sdougm #include <grp.h>
473034Sdougm #include <limits.h>
483034Sdougm #include <sys/param.h>
493034Sdougm #include <signal.h>
503034Sdougm #include <libintl.h>
515331Samw #include <dirent.h>
523034Sdougm 
533957Sth199096 #include <sharefs/share.h>
543034Sdougm #include "sharetab.h"
553034Sdougm 
563034Sdougm #define	DFSTAB_NOTICE_LINES	5
573034Sdougm static char *notice[DFSTAB_NOTICE_LINES] =	{
583034Sdougm 	"# Do not modify this file directly.\n",
593034Sdougm 	"# Use the sharemgr(1m) command for all share management\n",
603034Sdougm 	"# This file is reconstructed and only maintained for backward\n",
613034Sdougm 	"# compatibility. Configuration lines could be lost.\n",
623034Sdougm 	"#\n"
633034Sdougm };
643034Sdougm 
653034Sdougm #define	STRNCAT(x, y, z)	(xmlChar *)strncat((char *)x, (char *)y, z)
663034Sdougm 
673034Sdougm /* will be much smaller, but this handles bad syntax in the file */
683034Sdougm #define	MAXARGSFORSHARE	256
693034Sdougm 
708334SJose.Borrego@Sun.COM static mutex_t sharetab_lock = DEFAULTMUTEX;
71*12508Samw@Sun.COM extern mutex_t sa_dfstab_lock;
728334SJose.Borrego@Sun.COM 
733034Sdougm /* used internally only */
743034Sdougm typedef
753034Sdougm struct sharelist {
763034Sdougm     struct sharelist *next;
773034Sdougm     int   persist;
783034Sdougm     char *path;
793034Sdougm     char *resource;
803034Sdougm     char *fstype;
813034Sdougm     char *options;
823034Sdougm     char *description;
833034Sdougm     char *group;
843034Sdougm     char *origline;
853034Sdougm     int lineno;
863034Sdougm } xfs_sharelist_t;
873910Sdougm static void parse_dfstab(sa_handle_t, char *, xmlNodePtr);
888334SJose.Borrego@Sun.COM extern char *_sa_get_token(char *);
893034Sdougm static void dfs_free_list(xfs_sharelist_t *);
903034Sdougm /* prototypes */
913910Sdougm void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *);
925331Samw extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
933910Sdougm extern sa_group_t _sa_create_group(sa_handle_impl_t, char *);
943034Sdougm static void outdfstab(FILE *, xfs_sharelist_t *);
953034Sdougm extern int _sa_remove_optionset(sa_optionset_t);
963034Sdougm extern int set_node_share(void *, char *, char *);
973034Sdougm extern void set_node_attr(void *, char *, char *);
983034Sdougm 
993034Sdougm /*
1003663Sdougm  * sablocksigs(*sigs)
1013663Sdougm  *
1023663Sdougm  * block important signals for a critical region. Arg is a pointer to
1033663Sdougm  * a sigset_t that is used later for the unblock.
1043663Sdougm  */
1053663Sdougm void
sablocksigs(sigset_t * sigs)1063663Sdougm sablocksigs(sigset_t *sigs)
1073663Sdougm {
1083663Sdougm 	sigset_t new;
1093663Sdougm 
1103663Sdougm 	if (sigs != NULL) {
1114653Sdougm 		(void) sigprocmask(SIG_BLOCK, NULL, &new);
1124653Sdougm 		(void) sigaddset(&new, SIGHUP);
1134653Sdougm 		(void) sigaddset(&new, SIGINT);
1144653Sdougm 		(void) sigaddset(&new, SIGQUIT);
1154653Sdougm 		(void) sigaddset(&new, SIGTSTP);
1164653Sdougm 		(void) sigprocmask(SIG_SETMASK, &new, sigs);
1173663Sdougm 	}
1183663Sdougm }
1193663Sdougm 
1203663Sdougm /*
1213663Sdougm  * saunblocksigs(*sigs)
1223663Sdougm  *
1233663Sdougm  * unblock previously blocked signals from the sigs arg.
1243663Sdougm  */
1253663Sdougm void
saunblocksigs(sigset_t * sigs)1263663Sdougm saunblocksigs(sigset_t *sigs)
1273663Sdougm {
1283663Sdougm 	if (sigs != NULL)
1294653Sdougm 		(void) sigprocmask(SIG_SETMASK, sigs, NULL);
1303663Sdougm }
1313663Sdougm 
1323663Sdougm /*
1333034Sdougm  * alloc_sharelist()
1343034Sdougm  *
1353034Sdougm  * allocator function to return an zfs_sharelist_t
1363034Sdougm  */
1373034Sdougm 
1383034Sdougm static xfs_sharelist_t *
alloc_sharelist()1393034Sdougm alloc_sharelist()
1403034Sdougm {
1413034Sdougm 	xfs_sharelist_t *item;
1423034Sdougm 
1433034Sdougm 	item = (xfs_sharelist_t *)malloc(sizeof (xfs_sharelist_t));
1443034Sdougm 	if (item != NULL)
1454653Sdougm 		(void) memset(item, '\0', sizeof (xfs_sharelist_t));
1463034Sdougm 	return (item);
1473034Sdougm }
1483034Sdougm 
1493034Sdougm /*
1503034Sdougm  * fix_notice(list)
1513034Sdougm  *
1523034Sdougm  * Look at the beginning of the current /etc/dfs/dfstab file and add
1533034Sdougm  * the do not modify notice if it doesn't exist.
1543034Sdougm  */
1553034Sdougm 
1563034Sdougm static xfs_sharelist_t *
fix_notice(xfs_sharelist_t * list)1573034Sdougm fix_notice(xfs_sharelist_t *list)
1583034Sdougm {
1593034Sdougm 	xfs_sharelist_t *item, *prev;
1603034Sdougm 	int i;
1613034Sdougm 
1623082Sdougm 	if (list == NULL) {
1634653Sdougm 		/* zero length dfstab */
1644653Sdougm 		list = alloc_sharelist();
1654653Sdougm 		if (list == NULL)
1664653Sdougm 			return (NULL);
1674653Sdougm 		list->description = strdup("#\n");
1683082Sdougm 	}
1693034Sdougm 	if (list->path == NULL && list->description != NULL &&
1703034Sdougm 	    strcmp(list->description, notice[0]) != 0) {
1714653Sdougm 		for (prev = NULL, i = 0; i < DFSTAB_NOTICE_LINES; i++) {
1724653Sdougm 			item = alloc_sharelist();
1734653Sdougm 			if (item != NULL) {
1744653Sdougm 				item->description = strdup(notice[i]);
1754653Sdougm 				if (prev == NULL) {
1764653Sdougm 					item->next = list;
1774653Sdougm 					prev = item;
1784653Sdougm 					list = item;
1794653Sdougm 				} else {
1804653Sdougm 					item->next = prev->next;
1814653Sdougm 					prev->next = item;
1824653Sdougm 					prev = item;
1834653Sdougm 				}
1844653Sdougm 			}
1853034Sdougm 		}
1863034Sdougm 	}
1873034Sdougm 	return (list);
1883034Sdougm }
1893034Sdougm 
1903034Sdougm /*
1913034Sdougm  * getdfstab(dfs)
1923034Sdougm  *
1933034Sdougm  * Returns an zfs_sharelist_t list of lines from the dfstab file
1943034Sdougm  * pointed to by the FILE pointer dfs. Each entry is parsed and the
1953034Sdougm  * original line is also preserved. Used in parsing and updating the
1963034Sdougm  * dfstab file.
1973034Sdougm  */
1983034Sdougm 
1993034Sdougm static xfs_sharelist_t *
getdfstab(FILE * dfs)2003034Sdougm getdfstab(FILE *dfs)
2013034Sdougm {
2023034Sdougm 	char buff[_POSIX_ARG_MAX]; /* reasonable size given syntax of share */
2033034Sdougm 	char *bp;
2043034Sdougm 	char *token;
2053034Sdougm 	char *args[MAXARGSFORSHARE];
2063034Sdougm 	int argc;
2073034Sdougm 	int c;
2083034Sdougm 	static int line = 0;
2093082Sdougm 	xfs_sharelist_t *item = NULL, *first = NULL, *last;
2103034Sdougm 
2113034Sdougm 	if (dfs != NULL) {
2124653Sdougm 		first = NULL;
2134653Sdougm 		line = 0;
2144653Sdougm 		while (fgets(buff, sizeof (buff), dfs) != NULL) {
2154653Sdougm 			line++;
2164653Sdougm 			bp = buff;
2174653Sdougm 			if (buff[0] == '#') {
2184653Sdougm 				item = alloc_sharelist();
2194653Sdougm 				if (item != NULL) {
2204653Sdougm 					/* if no path, then comment */
2214653Sdougm 					item->lineno = line;
2224653Sdougm 					item->description = strdup(buff);
2234653Sdougm 					if (first == NULL) {
2244653Sdougm 						first = item;
2254653Sdougm 						last = item;
2264653Sdougm 					} else {
2274653Sdougm 						last->next = item;
2284653Sdougm 						last = item;
2294653Sdougm 					}
2304653Sdougm 				} else {
2314653Sdougm 					break;
2324653Sdougm 				}
2334653Sdougm 				continue;
2344653Sdougm 			} else if (buff[0] == '\n') {
2354653Sdougm 				continue;
2364653Sdougm 			}
2374653Sdougm 			optind = 1;
2384653Sdougm 			item = alloc_sharelist();
2394653Sdougm 			if (item == NULL) {
2404653Sdougm 				break;
2414653Sdougm 			} else if (first == NULL) {
2424653Sdougm 				first = item;
2434653Sdougm 				last = item;
2444653Sdougm 			} else {
2454653Sdougm 				last->next = item;
2464653Sdougm 				last = item;
2474653Sdougm 			}
2483034Sdougm 			item->lineno = line;
2494653Sdougm 			item->origline = strdup(buff);
2508334SJose.Borrego@Sun.COM 			(void) _sa_get_token(NULL); /* reset to new pointers */
2514653Sdougm 			argc = 0;
2528334SJose.Borrego@Sun.COM 			while ((token = _sa_get_token(bp)) != NULL) {
2534653Sdougm 				if (argc < MAXARGSFORSHARE)
2544653Sdougm 					args[argc++] = token;
2553034Sdougm 			}
2564653Sdougm 			while ((c = getopt(argc, args, "F:o:d:pg:")) != -1) {
2574653Sdougm 				switch (c) {
2584653Sdougm 				case 'p':
2594653Sdougm 					item->persist = 1;
2604653Sdougm 					break;
2614653Sdougm 				case 'F':
2624653Sdougm 					item->fstype = strdup(optarg);
2634653Sdougm 					break;
2644653Sdougm 				case 'o':
2654653Sdougm 					item->options = strdup(optarg);
2664653Sdougm 					break;
2674653Sdougm 				case 'd':
2684653Sdougm 					item->description = strdup(optarg);
2694653Sdougm 					break;
2704653Sdougm 				case 'g':
2714653Sdougm 					item->group = strdup(optarg);
2724653Sdougm 					break;
2734653Sdougm 				default:
2744653Sdougm 					break;
2754653Sdougm 				}
2764653Sdougm 			}
2774653Sdougm 			if (optind < argc) {
2784653Sdougm 				item->path = strdup(args[optind]);
2794653Sdougm 				optind++;
2804653Sdougm 				if (optind < argc) {
2814653Sdougm 					char *resource;
2824653Sdougm 					char *optgroup;
2834653Sdougm 					/* resource and/or groupname */
2844653Sdougm 					resource = args[optind];
2854653Sdougm 					optgroup = strchr(resource, '@');
2864653Sdougm 					if (optgroup != NULL)
2874653Sdougm 						*optgroup++ = '\0';
2884653Sdougm 					if (optgroup != NULL)
2894653Sdougm 						item->group = strdup(optgroup);
2904653Sdougm 					if (resource != NULL &&
2914653Sdougm 					    strlen(resource) > 0)
2924653Sdougm 						item->resource =
2934653Sdougm 						    strdup(resource);
2944653Sdougm 				}
2954653Sdougm 			}
2964653Sdougm 			/* NFS is the default if none defined */
2974653Sdougm 			if (item != NULL && item->fstype == NULL)
2984653Sdougm 				item->fstype = strdup("nfs");
2993034Sdougm 		}
3003034Sdougm 	}
3013034Sdougm 	first = fix_notice(first);
3023034Sdougm 	return (first);
3033034Sdougm }
3043034Sdougm 
3053034Sdougm /*
3063034Sdougm  * finddfsentry(list, path)
3073034Sdougm  *
3083082Sdougm  * Look for path in the zfs_sharelist_t list and return the entry if it
3093034Sdougm  * exists.
3103034Sdougm  */
3113034Sdougm 
3123034Sdougm static xfs_sharelist_t *
finddfsentry(xfs_sharelist_t * list,char * path)3133034Sdougm finddfsentry(xfs_sharelist_t *list, char *path)
3143034Sdougm {
3153034Sdougm 	xfs_sharelist_t *item;
3163034Sdougm 
3173034Sdougm 	for (item = list; item != NULL; item = item->next) {
3184653Sdougm 		if (item->path != NULL && strcmp(item->path, path) == 0)
3193034Sdougm 		return (item);
3203034Sdougm 	}
3213034Sdougm 	return (NULL);
3223034Sdougm }
3233034Sdougm 
3243034Sdougm /*
3253034Sdougm  * remdfsentry(list, path, proto)
3263034Sdougm  *
3273034Sdougm  * Remove the specified path (with protocol) from the list. This will
3283034Sdougm  * remove it from dfstab when the file is rewritten.
3293034Sdougm  */
3303034Sdougm 
3313034Sdougm static xfs_sharelist_t *
remdfsentry(xfs_sharelist_t * list,char * path,char * proto)3323034Sdougm remdfsentry(xfs_sharelist_t *list, char *path, char *proto)
3333034Sdougm {
3343034Sdougm 	xfs_sharelist_t *item, *prev = NULL;
3353034Sdougm 
3363034Sdougm 
3373034Sdougm 	for (item = prev = list; item != NULL; item = item->next) {
3383034Sdougm 	    /* skip comment entry but don't lose it */
3394653Sdougm 		if (item->path == NULL) {
3404653Sdougm 			prev = item;
3414653Sdougm 			continue;
3424653Sdougm 		}
3434653Sdougm 		/* if proto is NULL, remove all protocols */
3444653Sdougm 		if (proto == NULL || (strcmp(item->path, path) == 0 &&
3454653Sdougm 		    (item->fstype != NULL && strcmp(item->fstype, proto) == 0)))
3464653Sdougm 			break;
3474653Sdougm 		if (item->fstype == NULL &&
3484653Sdougm 		    (proto == NULL || strcmp(proto, "nfs") == 0))
3494653Sdougm 			break;
3503034Sdougm 		prev = item;
3513034Sdougm 	}
3523034Sdougm 	if (item != NULL) {
3534653Sdougm 		if (item == prev)
3544653Sdougm 			list = item->next; /* this must be the first one */
3554653Sdougm 		else
3564653Sdougm 			prev->next = item->next;
3574653Sdougm 		item->next = NULL;
3584653Sdougm 		dfs_free_list(item);
3593034Sdougm 	}
3603034Sdougm 	return (list);
3613034Sdougm }
3623034Sdougm 
3633034Sdougm /*
3643034Sdougm  * remdfsline(list, line)
3653034Sdougm  *
3663034Sdougm  * Remove the line specified from the list.
3673034Sdougm  */
3683034Sdougm 
3693034Sdougm static xfs_sharelist_t *
remdfsline(xfs_sharelist_t * list,char * line)3703034Sdougm remdfsline(xfs_sharelist_t *list, char *line)
3713034Sdougm {
3723034Sdougm 	xfs_sharelist_t *item, *prev = NULL;
3733034Sdougm 
3743034Sdougm 	for (item = prev = list; item != NULL; item = item->next) {
3754653Sdougm 		/* skip comment entry but don't lose it */
3764653Sdougm 		if (item->path == NULL) {
3773034Sdougm 		prev = item;
3783034Sdougm 		continue;
3794653Sdougm 		}
3804653Sdougm 		if (strcmp(item->origline, line) == 0)
3814653Sdougm 			break;
3824653Sdougm 		prev = item;
3833034Sdougm 	}
3843034Sdougm 	if (item != NULL) {
3854653Sdougm 		if (item == prev)
3864653Sdougm 			list = item->next; /* this must be the first one */
3874653Sdougm 		else
3884653Sdougm 			prev->next = item->next;
3894653Sdougm 		item->next = NULL;
3904653Sdougm 		dfs_free_list(item);
3913034Sdougm 	}
3923034Sdougm 	return (list);
3933034Sdougm }
3943034Sdougm 
3953034Sdougm /*
3963034Sdougm  * adddfsentry(list, share, proto)
3973034Sdougm  *
3983034Sdougm  * Add an entry to the dfstab list for share (relative to proto). This
3993034Sdougm  * is used to update dfstab for legacy purposes.
4003034Sdougm  */
4013034Sdougm 
4023034Sdougm static xfs_sharelist_t *
adddfsentry(xfs_sharelist_t * list,sa_share_t share,char * proto)4033034Sdougm adddfsentry(xfs_sharelist_t *list, sa_share_t share, char *proto)
4043034Sdougm {
4053034Sdougm 	xfs_sharelist_t *item, *tmp;
4063034Sdougm 	sa_group_t parent;
4073034Sdougm 	char *groupname;
4083034Sdougm 
4093034Sdougm 	item = alloc_sharelist();
4103034Sdougm 	if (item != NULL) {
4114653Sdougm 		parent = sa_get_parent_group(share);
4124653Sdougm 		groupname = sa_get_group_attr(parent, "name");
41311337SWilliam.Krier@Sun.COM 		if (groupname != NULL && strcmp(groupname, "default") == 0) {
4144653Sdougm 			sa_free_attr_string(groupname);
4154653Sdougm 			groupname = NULL;
4164653Sdougm 		}
4174653Sdougm 		item->path = sa_get_share_attr(share, "path");
4184653Sdougm 		item->resource = sa_get_share_attr(share, "resource");
4194653Sdougm 		item->group = groupname;
4204653Sdougm 		item->fstype = strdup(proto);
4214653Sdougm 		item->options = sa_proto_legacy_format(proto, share, 1);
4224653Sdougm 		if (item->options != NULL && strlen(item->options) == 0) {
4234653Sdougm 			free(item->options);
4244653Sdougm 			item->options = NULL;
4254653Sdougm 		}
4264653Sdougm 		item->description = sa_get_share_description(share);
4274653Sdougm 		if (item->description != NULL &&
4284653Sdougm 		    strlen(item->description) == 0) {
4294653Sdougm 			sa_free_share_description(item->description);
4304653Sdougm 			item->description = NULL;
4314653Sdougm 		}
4324653Sdougm 		if (list == NULL) {
4334653Sdougm 			list = item;
4344653Sdougm 		} else {
4354653Sdougm 			for (tmp = list; tmp->next != NULL; tmp = tmp->next)
4364653Sdougm 				/* do nothing */;
4374653Sdougm 				tmp->next = item;
4384653Sdougm 		}
4393034Sdougm 	}
4403034Sdougm 	return (list);
4413034Sdougm }
4423034Sdougm 
4433034Sdougm /*
4443034Sdougm  * outdfstab(dfstab, list)
4453034Sdougm  *
4463034Sdougm  * Output the list to dfstab making sure the file is truncated.
4473034Sdougm  * Comments and errors are preserved.
4483034Sdougm  */
4493034Sdougm 
4503034Sdougm static void
outdfstab(FILE * dfstab,xfs_sharelist_t * list)4513034Sdougm outdfstab(FILE *dfstab, xfs_sharelist_t *list)
4523034Sdougm {
4533034Sdougm 	xfs_sharelist_t *item;
4543034Sdougm 
4553034Sdougm 	(void) ftruncate(fileno(dfstab), 0);
4563034Sdougm 
4573034Sdougm 	for (item = list; item != NULL; item = item->next) {
4584653Sdougm 		if (item->path != NULL) {
4594653Sdougm 			if (*item->path == '/') {
4604653Sdougm 				(void) fprintf(dfstab,
4614653Sdougm 				    "share %s%s%s%s%s%s%s %s%s%s%s%s\n",
4624653Sdougm 				    (item->fstype != NULL) ? "-F " : "",
4634653Sdougm 				    (item->fstype != NULL) ? item->fstype : "",
4644653Sdougm 				    (item->options != NULL) ? " -o " : "",
4654653Sdougm 				    (item->options != NULL) ?
4664653Sdougm 				    item->options : "",
4674653Sdougm 				    (item->description != NULL) ?
4684653Sdougm 				    " -d \"" : "",
4694653Sdougm 				    (item->description != NULL) ?
4704653Sdougm 				    item->description : "",
4714653Sdougm 				    (item->description != NULL) ? "\"" : "",
4724653Sdougm 				    item->path,
4734653Sdougm 				    ((item->resource != NULL) ||
4744653Sdougm 				    (item->group != NULL)) ? " " : "",
4754653Sdougm 				    (item->resource != NULL) ?
4764653Sdougm 				    item->resource : "",
4774653Sdougm 				    item->group != NULL ? "@" : "",
4784653Sdougm 				    item->group != NULL ? item->group : "");
4794653Sdougm 			} else {
4804653Sdougm 				(void) fprintf(dfstab, "%s", item->origline);
4814653Sdougm 			}
4823034Sdougm 		} else {
4834653Sdougm 			if (item->description != NULL)
4844653Sdougm 				(void) fprintf(dfstab, "%s", item->description);
4854653Sdougm 			else
4864653Sdougm 				(void) fprintf(dfstab, "%s", item->origline);
4873034Sdougm 		}
4883034Sdougm 	}
4893034Sdougm }
4903034Sdougm 
4913034Sdougm /*
4923034Sdougm  * open_dfstab(file)
4933034Sdougm  *
4943034Sdougm  * Open the specified dfstab file. If the owner/group/perms are wrong,
4953034Sdougm  * fix them.
4963034Sdougm  */
4973034Sdougm 
4983034Sdougm static FILE *
open_dfstab(char * file)4993034Sdougm open_dfstab(char *file)
5003034Sdougm {
5013034Sdougm 	struct group *grp;
5023034Sdougm 	struct group group;
5033034Sdougm 	char *buff;
5043034Sdougm 	int grsize;
5053034Sdougm 	FILE *dfstab;
5063034Sdougm 
5073034Sdougm 	dfstab = fopen(file, "r+");
5083034Sdougm 	if (dfstab == NULL) {
5094653Sdougm 		dfstab = fopen(file, "w+");
5103034Sdougm 	}
5113034Sdougm 	if (dfstab != NULL) {
5123034Sdougm 		grsize = sysconf(_SC_GETGR_R_SIZE_MAX);
5133034Sdougm 		buff = malloc(grsize);
5143034Sdougm 		if (buff != NULL)
5154653Sdougm 			grp = getgrnam_r(SA_DEFAULT_FILE_GRP, &group, buff,
5164653Sdougm 			    grsize);
5173034Sdougm 		else
5184653Sdougm 			grp = getgrnam(SA_DEFAULT_FILE_GRP);
5193034Sdougm 		(void) fchmod(fileno(dfstab), 0644);
5203034Sdougm 		(void) fchown(fileno(dfstab), 0,
5214653Sdougm 		    grp != NULL ? grp->gr_gid : 3);
5223034Sdougm 		if (buff != NULL)
5234653Sdougm 			free(buff);
5243034Sdougm 		rewind(dfstab);
5253034Sdougm 	}
5263034Sdougm 	return (dfstab);
5273034Sdougm }
5283034Sdougm 
5293034Sdougm /*
5303034Sdougm  * sa_comment_line(line, err)
5313034Sdougm  *
5323034Sdougm  * Add a comment to the dfstab file with err as a prefix to the
5333034Sdougm  * original line.
5343034Sdougm  */
5353034Sdougm 
5363034Sdougm static void
sa_comment_line(char * line,char * err)5373034Sdougm sa_comment_line(char *line, char *err)
5383034Sdougm {
5393034Sdougm 	FILE *dfstab;
5403034Sdougm 	xfs_sharelist_t *list;
5413663Sdougm 	sigset_t old;
5423034Sdougm 
5433034Sdougm 	dfstab = open_dfstab(SA_LEGACY_DFSTAB);
5443034Sdougm 	if (dfstab != NULL) {
5453034Sdougm 		(void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8);
5463663Sdougm 		sablocksigs(&old);
5473034Sdougm 		(void) lockf(fileno(dfstab), F_LOCK, 0);
548*12508Samw@Sun.COM 		(void) mutex_lock(&sa_dfstab_lock);
5493034Sdougm 		list = getdfstab(dfstab);
5503034Sdougm 		rewind(dfstab);
5513348Sdougm 		/*
5523348Sdougm 		 * don't ignore the return since the list could have
5533348Sdougm 		 * gone to NULL if the file only had one line in it.
5543348Sdougm 		 */
5553348Sdougm 		list = remdfsline(list, line);
5563034Sdougm 		outdfstab(dfstab, list);
5573034Sdougm 		(void) fprintf(dfstab, "# Error: %s: %s", err, line);
5583034Sdougm 		(void) fsync(fileno(dfstab));
559*12508Samw@Sun.COM 		(void) mutex_unlock(&sa_dfstab_lock);
5603034Sdougm 		(void) lockf(fileno(dfstab), F_ULOCK, 0);
5613034Sdougm 		(void) fclose(dfstab);
5623663Sdougm 		saunblocksigs(&old);
5633034Sdougm 		if (list != NULL)
5644653Sdougm 			dfs_free_list(list);
5653034Sdougm 	}
5663034Sdougm }
5673034Sdougm 
5683034Sdougm /*
5695331Samw  * sa_delete_legacy(share, protocol)
5703034Sdougm  *
5713034Sdougm  * Delete the specified share from the legacy config file.
5723034Sdougm  */
5733034Sdougm 
5743034Sdougm int
sa_delete_legacy(sa_share_t share,char * protocol)5755331Samw sa_delete_legacy(sa_share_t share, char *protocol)
5763034Sdougm {
5773034Sdougm 	FILE *dfstab;
5783034Sdougm 	int err;
5793034Sdougm 	int ret = SA_OK;
5803034Sdougm 	xfs_sharelist_t *list;
5813034Sdougm 	char *path;
5823034Sdougm 	sa_optionset_t optionset;
5833034Sdougm 	sa_group_t parent;
5843663Sdougm 	sigset_t old;
5853034Sdougm 
5865331Samw 	/*
5875331Samw 	 * Protect against shares that don't have paths. This is not
5885331Samw 	 * really an error at this point.
5895331Samw 	 */
5905331Samw 	path = sa_get_share_attr(share, "path");
5915331Samw 	if (path == NULL)
5925331Samw 		return (ret);
5935331Samw 
5943034Sdougm 	dfstab = open_dfstab(SA_LEGACY_DFSTAB);
5953034Sdougm 	if (dfstab != NULL) {
5963034Sdougm 		(void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8);
5973663Sdougm 		sablocksigs(&old);
5983034Sdougm 		parent = sa_get_parent_group(share);
5993034Sdougm 		if (parent != NULL) {
6004653Sdougm 			(void) lockf(fileno(dfstab), F_LOCK, 0);
601*12508Samw@Sun.COM 			(void) mutex_lock(&sa_dfstab_lock);
6024653Sdougm 			list = getdfstab(dfstab);
6034653Sdougm 			rewind(dfstab);
6045331Samw 			if (protocol != NULL) {
6055331Samw 				if (list != NULL)
6064653Sdougm 					list = remdfsentry(list, path,
6075331Samw 					    protocol);
6085331Samw 			} else {
6095331Samw 				for (optionset = sa_get_optionset(parent, NULL);
6105331Samw 				    optionset != NULL;
6115331Samw 				    optionset =
6125331Samw 				    sa_get_next_optionset(optionset)) {
6135331Samw 					char *proto = sa_get_optionset_attr(
6145331Samw 					    optionset, "type");
6155331Samw 
6165331Samw 					if (list != NULL && proto != NULL)
6175331Samw 						list = remdfsentry(list, path,
6185331Samw 						    proto);
6195331Samw 					if (proto == NULL)
6205331Samw 						ret = SA_NO_MEMORY;
6215331Samw 					/*
6225331Samw 					 * may want to only do the dfstab if
6235331Samw 					 * this call returns NOT IMPLEMENTED
6245331Samw 					 * but it shouldn't hurt.
6255331Samw 					 */
6265331Samw 					if (ret == SA_OK) {
6275331Samw 						err = sa_proto_delete_legacy(
6285331Samw 						    proto, share);
6295331Samw 						if (err != SA_NOT_IMPLEMENTED)
6305331Samw 							ret = err;
6315331Samw 					}
6325331Samw 					if (proto != NULL)
6335331Samw 						sa_free_attr_string(proto);
6344653Sdougm 				}
6353034Sdougm 			}
6364653Sdougm 			outdfstab(dfstab, list);
6374653Sdougm 			if (list != NULL)
6384653Sdougm 				dfs_free_list(list);
6394653Sdougm 			(void) fflush(dfstab);
640*12508Samw@Sun.COM 			(void) mutex_unlock(&sa_dfstab_lock);
6414653Sdougm 			(void) lockf(fileno(dfstab), F_ULOCK, 0);
6423034Sdougm 		}
6433034Sdougm 		(void) fsync(fileno(dfstab));
6443663Sdougm 		saunblocksigs(&old);
6453034Sdougm 		(void) fclose(dfstab);
6463034Sdougm 	} else {
6474653Sdougm 		if (errno == EACCES || errno == EPERM)
6484653Sdougm 			ret = SA_NO_PERMISSION;
6494653Sdougm 		else
6504653Sdougm 			ret = SA_CONFIG_ERR;
6513034Sdougm 	}
6525331Samw 
6535331Samw 	if (path != NULL)
6545331Samw 		sa_free_attr_string(path);
6555331Samw 
6563034Sdougm 	return (ret);
6573034Sdougm }
6583034Sdougm 
6593034Sdougm /*
6603034Sdougm  * sa_update_legacy(share, proto)
6613034Sdougm  *
6623034Sdougm  * There is an assumption that dfstab will be the most common form of
6633034Sdougm  * legacy configuration file for shares, but not the only one. Because
6643034Sdougm  * of that, dfstab handling is done in the main code with calls to
6655331Samw  * this function and protocol specific calls to deal with formatting
6663034Sdougm  * options into dfstab/share compatible syntax. Since not everything
6673034Sdougm  * will be dfstab, there is a provision for calling a protocol
6683034Sdougm  * specific plugin interface that allows the protocol plugin to do its
6693034Sdougm  * own legacy files and skip the dfstab update.
6703034Sdougm  */
6713034Sdougm 
6723034Sdougm int
sa_update_legacy(sa_share_t share,char * proto)6733034Sdougm sa_update_legacy(sa_share_t share, char *proto)
6743034Sdougm {
6753034Sdougm 	FILE *dfstab;
6763034Sdougm 	int ret = SA_OK;
6773034Sdougm 	xfs_sharelist_t *list;
6783034Sdougm 	char *path;
6793663Sdougm 	sigset_t old;
6803034Sdougm 	char *persist;
6815331Samw 	uint64_t features;
6823034Sdougm 
6833034Sdougm 	ret = sa_proto_update_legacy(proto, share);
6843034Sdougm 	if (ret != SA_NOT_IMPLEMENTED)
6854653Sdougm 		return (ret);
6865331Samw 
6875331Samw 	features = sa_proto_get_featureset(proto);
6885331Samw 	if (!(features & SA_FEATURE_DFSTAB))
6895331Samw 		return (ret);
6905331Samw 
6913034Sdougm 	/* do the dfstab format */
6923034Sdougm 	persist = sa_get_share_attr(share, "type");
6933034Sdougm 	/*
6943034Sdougm 	 * only update if the share is not transient -- no share type
6953034Sdougm 	 * set or the type is not "transient".
6963034Sdougm 	 */
6973034Sdougm 	if (persist == NULL || strcmp(persist, "transient") != 0) {
69811337SWilliam.Krier@Sun.COM 		path = sa_get_share_attr(share, "path");
69911337SWilliam.Krier@Sun.COM 		if (path == NULL) {
70011337SWilliam.Krier@Sun.COM 			ret = SA_NO_MEMORY;
70111337SWilliam.Krier@Sun.COM 			goto out;
70211337SWilliam.Krier@Sun.COM 		}
7034653Sdougm 		dfstab = open_dfstab(SA_LEGACY_DFSTAB);
7044653Sdougm 		if (dfstab != NULL) {
7054653Sdougm 			(void) setvbuf(dfstab, NULL, _IOLBF, BUFSIZ * 8);
7064653Sdougm 			sablocksigs(&old);
7074653Sdougm 			(void) lockf(fileno(dfstab), F_LOCK, 0);
708*12508Samw@Sun.COM 			(void) mutex_lock(&sa_dfstab_lock);
7094653Sdougm 			list = getdfstab(dfstab);
7104653Sdougm 			rewind(dfstab);
7114653Sdougm 			if (list != NULL)
7124653Sdougm 				list = remdfsentry(list, path, proto);
7134653Sdougm 			list = adddfsentry(list, share, proto);
7144653Sdougm 			outdfstab(dfstab, list);
7154653Sdougm 			(void) fflush(dfstab);
716*12508Samw@Sun.COM 			(void) mutex_unlock(&sa_dfstab_lock);
7174653Sdougm 			(void) lockf(fileno(dfstab), F_ULOCK, 0);
7184653Sdougm 			(void) fsync(fileno(dfstab));
7194653Sdougm 			saunblocksigs(&old);
7204653Sdougm 			(void) fclose(dfstab);
7214653Sdougm 			if (list != NULL)
7224653Sdougm 				dfs_free_list(list);
7233034Sdougm 		} else {
7244653Sdougm 			if (errno == EACCES || errno == EPERM)
7254653Sdougm 				ret = SA_NO_PERMISSION;
7264653Sdougm 			else
7274653Sdougm 				ret = SA_CONFIG_ERR;
7283034Sdougm 		}
72911337SWilliam.Krier@Sun.COM 		sa_free_attr_string(path);
7303034Sdougm 	}
73111337SWilliam.Krier@Sun.COM out:
7323034Sdougm 	if (persist != NULL)
7334653Sdougm 		sa_free_attr_string(persist);
7343034Sdougm 	return (ret);
7353034Sdougm }
7363034Sdougm 
7373034Sdougm /*
7383034Sdougm  * sa_is_security(optname, proto)
7393034Sdougm  *
7403034Sdougm  * Check to see if optname is a security (named optionset) specific
7413034Sdougm  * property for the specified protocol.
7423034Sdougm  */
7433034Sdougm 
7443034Sdougm int
sa_is_security(char * optname,char * proto)7453034Sdougm sa_is_security(char *optname, char *proto)
7463034Sdougm {
7473034Sdougm 	int ret = 0;
7483034Sdougm 	if (proto != NULL)
7494653Sdougm 		ret = sa_proto_security_prop(proto, optname);
7503034Sdougm 	return (ret);
7513034Sdougm }
7523034Sdougm 
7533034Sdougm /*
7543034Sdougm  * add_syntax_comment(root, line, err, todfstab)
7553034Sdougm  *
7564653Sdougm  * Add a comment to the document indicating a syntax error. If
7573034Sdougm  * todfstab is set, write it back to the dfstab file as well.
7583034Sdougm  */
7593034Sdougm 
7603034Sdougm static void
add_syntax_comment(xmlNodePtr root,char * line,char * err,int todfstab)7613034Sdougm add_syntax_comment(xmlNodePtr root, char *line, char *err, int todfstab)
7623034Sdougm {
7633034Sdougm 	xmlNodePtr node;
7643034Sdougm 
7653034Sdougm 	node = xmlNewChild(root, NULL, (xmlChar *)"error", (xmlChar *)line);
7664653Sdougm 	if (node != NULL)
7676012Sthurlow 		(void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)err);
7683034Sdougm 	if (todfstab)
7694653Sdougm 		sa_comment_line(line, err);
7703034Sdougm }
7713034Sdougm 
7723034Sdougm /*
7733034Sdougm  * sa_is_share(object)
7743034Sdougm  *
7753034Sdougm  * returns true of the object is of type "share".
7763034Sdougm  */
7773034Sdougm 
7783034Sdougm int
sa_is_share(void * object)7793034Sdougm sa_is_share(void *object)
7803034Sdougm {
7813034Sdougm 	if (object != NULL) {
7824653Sdougm 		if (strcmp((char *)((xmlNodePtr)object)->name, "share") == 0)
7833034Sdougm 		return (1);
7843034Sdougm 	}
7853034Sdougm 	return (0);
7863034Sdougm }
7875331Samw /*
7885331Samw  * sa_is_resource(object)
7895331Samw  *
7905331Samw  * returns true of the object is of type "share".
7915331Samw  */
7925331Samw 
7935331Samw int
sa_is_resource(void * object)7945331Samw sa_is_resource(void *object)
7955331Samw {
7965331Samw 	if (object != NULL) {
7975331Samw 		if (strcmp((char *)((xmlNodePtr)object)->name, "resource") == 0)
7985331Samw 			return (1);
7995331Samw 	}
8005331Samw 	return (0);
8015331Samw }
8023034Sdougm 
8033034Sdougm /*
8043034Sdougm  * _sa_remove_property(property)
8053034Sdougm  *
8063034Sdougm  * remove a property only from the document.
8073034Sdougm  */
8083034Sdougm 
8093034Sdougm static void
_sa_remove_property(sa_property_t property)8103034Sdougm _sa_remove_property(sa_property_t property)
8113034Sdougm {
8123034Sdougm 	xmlUnlinkNode((xmlNodePtr)property);
8133034Sdougm 	xmlFreeNode((xmlNodePtr)property);
8143034Sdougm }
8153034Sdougm 
8163034Sdougm /*
8174180Sdougm  * _sa_create_dummy_share()
8184180Sdougm  *
8194180Sdougm  * Create a share entry suitable for parsing but not tied to any real
8204180Sdougm  * config tree.  Need to have a parent as well as the node to parse
8214180Sdougm  * on.  Free using _sa_free_dummy_share(share);
8224180Sdougm  */
8234180Sdougm 
8244180Sdougm static sa_group_t
_sa_create_dummy_share()8254180Sdougm _sa_create_dummy_share()
8264180Sdougm {
8274180Sdougm 	xmlNodePtr parent_node = NULL;
8284180Sdougm 	xmlNodePtr child_node = NULL;
8294180Sdougm 
8304180Sdougm 	parent_node = xmlNewNode(NULL, (xmlChar *)"group");
8314180Sdougm 	if (parent_node != NULL) {
8324653Sdougm 		child_node = xmlNewChild(parent_node, NULL, (xmlChar *)"share",
8334653Sdougm 		    NULL);
8344653Sdougm 		if (child_node != NULL) {
8354653Sdougm 			/*
8364653Sdougm 			 * Use a "zfs" tag since that will make sure nothing
8374653Sdougm 			 * really attempts to put values into the
8384653Sdougm 			 * repository. Also ZFS is currently the only user of
8394653Sdougm 			 * this interface.
8404653Sdougm 			 */
8414653Sdougm 			set_node_attr(parent_node, "type", "transient");
8424653Sdougm 			set_node_attr(parent_node, "zfs", "true");
8434653Sdougm 			set_node_attr(child_node, "type", "transient");
8444653Sdougm 			set_node_attr(child_node, "zfs", "true");
8454653Sdougm 		} else {
8464653Sdougm 			xmlFreeNode(parent_node);
8474653Sdougm 		}
8484180Sdougm 	}
8494180Sdougm 	return (child_node);
8504180Sdougm }
8514180Sdougm 
8524180Sdougm /*
8534180Sdougm  * _sa_free_dummy_share(share)
8544180Sdougm  *
8554180Sdougm  * Free the dummy share and its parent.  It is an error to try and
8564180Sdougm  * free something that isn't a dummy.
8574180Sdougm  */
8584180Sdougm 
8594180Sdougm static int
_sa_free_dummy_share(sa_share_t share)8604180Sdougm _sa_free_dummy_share(sa_share_t share)
8614180Sdougm {
8624180Sdougm 	xmlNodePtr node = (xmlNodePtr)share;
8634180Sdougm 	xmlNodePtr parent;
8644180Sdougm 	int ret = SA_OK;
8654180Sdougm 	char *name;
8664180Sdougm 
8674180Sdougm 	if (node != NULL) {
8684653Sdougm 		parent = node->parent;
8694653Sdougm 		name = (char *)xmlGetProp(node, (xmlChar *)"path");
8704653Sdougm 		if (name != NULL) {
8714653Sdougm 			/* Real shares always have a path but a dummy doesn't */
8724653Sdougm 			ret = SA_NOT_ALLOWED;
8734653Sdougm 			sa_free_attr_string(name);
8744653Sdougm 		} else {
8754653Sdougm 			/*
8764653Sdougm 			 * If there is a parent, do the free on that since
8774653Sdougm 			 * xmlFreeNode is a recursive function and free's an
8784653Sdougm 			 * child nodes.
8794653Sdougm 			 */
8804653Sdougm 			if (parent != NULL) {
8814653Sdougm 				node = parent;
8824653Sdougm 			}
8834653Sdougm 			xmlUnlinkNode(node);
8844653Sdougm 			xmlFreeNode(node);
8854180Sdougm 		}
8864180Sdougm 	}
8874180Sdougm 	return (ret);
8884180Sdougm }
8894180Sdougm 
8904180Sdougm 
8914180Sdougm /*
8923034Sdougm  * sa_parse_legacy_options(group, options, proto)
8933034Sdougm  *
8943034Sdougm  * In order to support legacy configurations, we allow the protocol
8953034Sdougm  * specific plugin to parse legacy syntax options (like those in
8963034Sdougm  * /etc/dfs/dfstab). This adds a new optionset to the group (or
8973034Sdougm  * share).
8983034Sdougm  *
8993034Sdougm  * Once the optionset has been created, we then get the derived
9003034Sdougm  * optionset of the parent (options from the optionset of the parent
9013034Sdougm  * and any parent it might have) and remove those from the created
9023034Sdougm  * optionset. This avoids duplication of options.
9033034Sdougm  */
9043034Sdougm 
9053034Sdougm int
sa_parse_legacy_options(sa_group_t group,char * options,char * proto)9063034Sdougm sa_parse_legacy_options(sa_group_t group, char *options, char *proto)
9073034Sdougm {
9083034Sdougm 	int ret = SA_INVALID_PROTOCOL;
9093034Sdougm 	sa_group_t parent;
9104180Sdougm 	int using_dummy = B_FALSE;
9114461Sdougm 	char *pvalue;
9124653Sdougm 	sa_optionset_t optionset;
9134653Sdougm 	sa_property_t popt, prop;
9144653Sdougm 	sa_optionset_t localoptions;
9154180Sdougm 
9164180Sdougm 	/*
9174653Sdougm 	 * If "group" is NULL, this is just a parse without saving
9184180Sdougm 	 * anything in either SMF or ZFS.  Create a dummy group to
9194180Sdougm 	 * handle this case.
9204180Sdougm 	 */
9214180Sdougm 	if (group == NULL) {
9224653Sdougm 		group = (sa_group_t)_sa_create_dummy_share();
9234653Sdougm 		using_dummy = B_TRUE;
9244180Sdougm 	}
9254180Sdougm 
9263034Sdougm 	parent = sa_get_parent_group(group);
9273034Sdougm 
9283034Sdougm 	if (proto != NULL)
9294653Sdougm 		ret = sa_proto_legacy_opts(proto, group, options);
9304180Sdougm 
9314180Sdougm 	if (using_dummy) {
9324653Sdougm 		/* Since this is a dummy parse, cleanup and quit here */
9334653Sdougm 		(void) _sa_free_dummy_share(parent);
9344653Sdougm 		return (ret);
9354180Sdougm 	}
9364653Sdougm 
9374653Sdougm 	if (ret != SA_OK)
9384653Sdougm 		return (ret);
9394653Sdougm 
9403034Sdougm 	/*
9414653Sdougm 	 * If in a group, remove the inherited options and security
9423034Sdougm 	 */
9434653Sdougm 
9444653Sdougm 	if (parent == NULL)
9454653Sdougm 		return (ret);
9464653Sdougm 
9474653Sdougm 	/* Find parent options to remove from child */
9484653Sdougm 	optionset = sa_get_derived_optionset(parent, proto, 1);
9494653Sdougm 	localoptions = sa_get_optionset(group, proto);
9504653Sdougm 	if (optionset != NULL) {
9514653Sdougm 		for (popt = sa_get_property(optionset, NULL);
9524653Sdougm 		    popt != NULL;
9534653Sdougm 		    popt = sa_get_next_property(popt)) {
9543034Sdougm 			char *tag;
9554461Sdougm 			char *value;
9563034Sdougm 			tag = sa_get_property_attr(popt, "type");
9574653Sdougm 			if (tag == NULL)
9584653Sdougm 				continue;
9594653Sdougm 			prop = sa_get_property(localoptions, tag);
9604653Sdougm 			if (prop != NULL) {
9614653Sdougm 				value = sa_get_property_attr(popt,
9624653Sdougm 				    "value");
9634653Sdougm 				pvalue = sa_get_property_attr(prop,
9644653Sdougm 				    "value");
9654461Sdougm 				if (value != NULL && pvalue != NULL &&
9664461Sdougm 				    strcmp(value, pvalue) == 0) {
9674461Sdougm 					/*
9684653Sdougm 					 * Remove the property
9694653Sdougm 					 * from the
9704653Sdougm 					 * child. While we
9714653Sdougm 					 * removed it, we
9724653Sdougm 					 * don't need to reset
9734653Sdougm 					 * as we do below
9744653Sdougm 					 * since we always
9754653Sdougm 					 * search from the
9764653Sdougm 					 * beginning.
9774461Sdougm 					 */
9784653Sdougm 					(void) _sa_remove_property(
9794653Sdougm 					    prop);
9803034Sdougm 				}
9814461Sdougm 				if (value != NULL)
9824653Sdougm 					sa_free_attr_string(value);
9834461Sdougm 				if (pvalue != NULL)
9844653Sdougm 					sa_free_attr_string(pvalue);
9853034Sdougm 			}
9864653Sdougm 			sa_free_attr_string(tag);
9874653Sdougm 		}
9884653Sdougm 		prop = sa_get_property(localoptions, NULL);
9894653Sdougm 		if (prop == NULL && sa_is_share(group)) {
9903034Sdougm 			/*
9914653Sdougm 			 * All properties removed so remove the
9923034Sdougm 			 * optionset if it is on a share
9933034Sdougm 			 */
9943034Sdougm 			(void) _sa_remove_optionset(localoptions);
9953034Sdougm 		}
9964653Sdougm 		sa_free_derived_optionset(optionset);
9974653Sdougm 	}
9984653Sdougm 	/*
9994653Sdougm 	 * Need to remove security here. If there are no
10004653Sdougm 	 * security options on the local group/share, don't
10014653Sdougm 	 * bother since those are the only ones that would be
10024653Sdougm 	 * affected.
10034653Sdougm 	 */
10044653Sdougm 	localoptions = sa_get_all_security_types(group, proto, 0);
10054653Sdougm 	if (localoptions != NULL) {
10064653Sdougm 		for (prop = sa_get_property(localoptions, NULL);
10074653Sdougm 		    prop != NULL;
10084653Sdougm 		    prop = sa_get_next_property(prop)) {
10093034Sdougm 			char *tag;
10103034Sdougm 			sa_security_t security;
10113034Sdougm 			tag = sa_get_property_attr(prop, "type");
10123034Sdougm 			if (tag != NULL) {
10134653Sdougm 				sa_property_t nextpopt = NULL;
10144653Sdougm 				security = sa_get_security(group, tag, proto);
10154653Sdougm 				sa_free_attr_string(tag);
10164461Sdougm 				/*
10174653Sdougm 				 * prop's value only changes outside this loop
10184461Sdougm 				 */
10194653Sdougm 				pvalue = sa_get_property_attr(prop, "value");
10204653Sdougm 				for (popt = sa_get_property(security, NULL);
10214653Sdougm 				    popt != NULL;
10224653Sdougm 				    popt = nextpopt) {
10234653Sdougm 					char *value;
10244653Sdougm 					/*
10254653Sdougm 					 * Need to get the next prop
10264653Sdougm 					 * now since we could break
10274653Sdougm 					 * the list during removal.
10284653Sdougm 					 */
10294653Sdougm 					nextpopt = sa_get_next_property(popt);
10304653Sdougm 					/* remove Duplicates from this level */
10314653Sdougm 					value = sa_get_property_attr(popt,
10324653Sdougm 					    "value");
10334653Sdougm 					if (value != NULL && pvalue != NULL &&
10344653Sdougm 					    strcmp(value, pvalue) == 0) {
10354653Sdougm 						/*
10364653Sdougm 						 * remove the property
10374653Sdougm 						 * from the child
10384653Sdougm 						 */
10394653Sdougm 						(void) _sa_remove_property
10404653Sdougm 						    (popt);
10414653Sdougm 					}
10424653Sdougm 					if (value != NULL)
10434653Sdougm 						sa_free_attr_string(value);
10443034Sdougm 				}
10454653Sdougm 				if (pvalue != NULL)
10464653Sdougm 					sa_free_attr_string(pvalue);
10473034Sdougm 			}
10483034Sdougm 		}
10494653Sdougm 		(void) sa_destroy_optionset(localoptions);
10503034Sdougm 	}
10513034Sdougm 	return (ret);
10523034Sdougm }
10533034Sdougm 
10543034Sdougm /*
10553034Sdougm  * dfs_free_list(list)
10563034Sdougm  *
10573034Sdougm  * Free the data in each list entry of the list as well as freeing the
10583034Sdougm  * entries themselves. We need to avoid memory leaks and don't want to
10593034Sdougm  * dereference any NULL members.
10603034Sdougm  */
10613034Sdougm 
10623034Sdougm static void
dfs_free_list(xfs_sharelist_t * list)10633034Sdougm dfs_free_list(xfs_sharelist_t *list)
10643034Sdougm {
10653034Sdougm 	xfs_sharelist_t *entry;
10663034Sdougm 	for (entry = list; entry != NULL; entry = list) {
10674653Sdougm 		if (entry->path != NULL)
10684653Sdougm 			free(entry->path);
10694653Sdougm 		if (entry->resource != NULL)
10704653Sdougm 			free(entry->resource);
10714653Sdougm 		if (entry->fstype != NULL)
10724653Sdougm 			free(entry->fstype);
10734653Sdougm 		if (entry->options != NULL)
10744653Sdougm 			free(entry->options);
10754653Sdougm 		if (entry->description != NULL)
10764653Sdougm 			free(entry->description);
10774653Sdougm 		if (entry->origline != NULL)
10784653Sdougm 			free(entry->origline);
10794653Sdougm 		if (entry->group != NULL)
10804653Sdougm 			free(entry->group);
10814653Sdougm 		list = list->next;
10824653Sdougm 			free(entry);
10833034Sdougm 	}
10843034Sdougm }
10853034Sdougm 
10863034Sdougm /*
10873034Sdougm  * parse_dfstab(dfstab, root)
10883034Sdougm  *
10893034Sdougm  * Open and read the existing dfstab, parsing each line and adding it
10903034Sdougm  * to the internal configuration. Make sure syntax errors, etc are
10913034Sdougm  * preserved as comments.
10923034Sdougm  */
10933034Sdougm 
10943034Sdougm static void
parse_dfstab(sa_handle_t handle,char * dfstab,xmlNodePtr root)10953910Sdougm parse_dfstab(sa_handle_t handle, char *dfstab, xmlNodePtr root)
10963034Sdougm {
10973034Sdougm 	sa_share_t share;
10983034Sdougm 	sa_group_t group;
10993034Sdougm 	sa_group_t sgroup = NULL;
11003034Sdougm 	sa_group_t defgroup;
11013034Sdougm 	xfs_sharelist_t *head, *list;
11023034Sdougm 	int err;
11033034Sdougm 	int defined_group;
11043034Sdougm 	FILE *dfs;
11053034Sdougm 	char *oldprops;
11063034Sdougm 
11073034Sdougm 	/* read the dfstab format file and fill in the doc tree */
11083034Sdougm 
11093034Sdougm 	dfs = fopen(dfstab, "r");
11104653Sdougm 	if (dfs == NULL)
11114653Sdougm 		return;
11123034Sdougm 
11133910Sdougm 	defgroup = sa_get_group(handle, "default");
11143034Sdougm 
11153034Sdougm 	for (head = list = getdfstab(dfs);
11164653Sdougm 	    list != NULL;
11174653Sdougm 	    list = list->next) {
11184653Sdougm 		share = NULL;
11194653Sdougm 		group = NULL;
11204653Sdougm 		defined_group = 0;
11214653Sdougm 		err = 0;
11223034Sdougm 
11234653Sdougm 		if (list->origline == NULL) {
11244653Sdougm 			/*
11254653Sdougm 			 * Comment line that we will likely skip.
11264653Sdougm 			 * If the line has the syntax:
11274653Sdougm 			 *	# error: string: string
11284653Sdougm 			 * It should be preserved until manually deleted.
11294653Sdougm 			 */
11304653Sdougm 			if (list->description != NULL &&
11314653Sdougm 			    strncmp(list->description, "# Error: ", 9) == 0) {
11324653Sdougm 				char *line;
11334653Sdougm 				char *error;
11344653Sdougm 				char *cmd;
11354653Sdougm 				line = strdup(list->description);
11364653Sdougm 				if (line != NULL) {
11374653Sdougm 					error = line + 9;
11384653Sdougm 					cmd = strchr(error, ':');
11394653Sdougm 					if (cmd != NULL) {
11404653Sdougm 						int len;
11414653Sdougm 						*cmd = '\0';
11424653Sdougm 						cmd += 2;
11434653Sdougm 						len = strlen(cmd);
11444653Sdougm 						cmd[len - 1] = '\0';
11454653Sdougm 						add_syntax_comment(root, cmd,
11464653Sdougm 						    error, 0);
11474653Sdougm 					}
11484653Sdougm 					free(line);
11494653Sdougm 				}
11503034Sdougm 			}
11514653Sdougm 			continue;
11523034Sdougm 		}
11534653Sdougm 		if (list->path != NULL && strlen(list->path) > 0 &&
11543910Sdougm 		    *list->path == '/') {
11554653Sdougm 			share = sa_find_share(handle, list->path);
11564653Sdougm 			if (share != NULL)
11574653Sdougm 				sgroup = sa_get_parent_group(share);
11584653Sdougm 			else
11594653Sdougm 				sgroup = NULL;
11604653Sdougm 		} else {
11614653Sdougm 			(void) printf(dgettext(TEXT_DOMAIN,
11624653Sdougm 			    "No share specified in dfstab: "
11634653Sdougm 			    "line %d: %s\n"),
11644653Sdougm 			    list->lineno, list->origline);
11654653Sdougm 			add_syntax_comment(root, list->origline,
11664653Sdougm 			    dgettext(TEXT_DOMAIN, "No share specified"), 1);
11674653Sdougm 			continue;
11684653Sdougm 		}
11694653Sdougm 		if (list->group != NULL && strlen(list->group) > 0) {
11704653Sdougm 			group = sa_get_group(handle, list->group);
11714653Sdougm 			defined_group = 1;
11724653Sdougm 		} else {
11734653Sdougm 			group = defgroup;
11744653Sdougm 		}
11754653Sdougm 		if (defined_group && group == NULL) {
11764653Sdougm 			(void) printf(dgettext(TEXT_DOMAIN,
11774653Sdougm 			    "Unknown group used in dfstab: line %d: %s\n"),
11784653Sdougm 			    list->lineno, list->origline);
11794653Sdougm 			add_syntax_comment(root, list->origline,
11804653Sdougm 			    dgettext(TEXT_DOMAIN, "Unknown group specified"),
11814653Sdougm 			    1);
11824653Sdougm 			continue;
11834653Sdougm 		}
11844653Sdougm 		if (group == NULL) {
11854653Sdougm 			/* Shouldn't happen unless an SMF error */
11864653Sdougm 			err = SA_CONFIG_ERR;
11874653Sdougm 			continue;
11884653Sdougm 		}
11893034Sdougm 		if (share == NULL) {
11904653Sdougm 			if (defined_group || group != defgroup)
11914653Sdougm 				continue;
11924653Sdougm 			/* This is an OK add for legacy */
11933034Sdougm 			share = sa_add_share(defgroup, list->path,
11944653Sdougm 			    SA_SHARE_PERMANENT | SA_SHARE_PARSER, &err);
11953034Sdougm 			if (share != NULL) {
11964653Sdougm 				if (list->description != NULL &&
11974653Sdougm 				    strlen(list->description) > 0)
11984653Sdougm 					(void) sa_set_share_description(share,
11994653Sdougm 					    list->description);
12004653Sdougm 				if (list->options != NULL &&
12014653Sdougm 				    strlen(list->options) > 0) {
12024653Sdougm 					(void) sa_parse_legacy_options(share,
12034653Sdougm 					    list->options, list->fstype);
12044653Sdougm 				}
12054653Sdougm 				if (list->resource != NULL)
12064653Sdougm 					(void) sa_set_share_attr(share,
12074653Sdougm 					    "resource", list->resource);
12083034Sdougm 			} else {
12094653Sdougm 				(void) printf(dgettext(TEXT_DOMAIN,
12104653Sdougm 				    "Error in dfstab: line %d: %s\n"),
12113034Sdougm 				    list->lineno, list->origline);
12124653Sdougm 				if (err != SA_BAD_PATH)
12134653Sdougm 					add_syntax_comment(root, list->origline,
12144653Sdougm 					    dgettext(TEXT_DOMAIN, "Syntax"), 1);
12154653Sdougm 				else
12164653Sdougm 					add_syntax_comment(root, list->origline,
12174653Sdougm 					    dgettext(TEXT_DOMAIN,
12184653Sdougm 					    "Path"), 1);
12194653Sdougm 				continue;
12204653Sdougm 			}
12214653Sdougm 		} else {
12224653Sdougm 			if (group != sgroup) {
12234653Sdougm 				(void) printf(dgettext(TEXT_DOMAIN,
12244653Sdougm 				    "Attempt to change configuration in "
12254653Sdougm 				    "dfstab: line %d: %s\n"),
12264653Sdougm 				    list->lineno, list->origline);
12273034Sdougm 				add_syntax_comment(root, list->origline,
12284653Sdougm 				    dgettext(TEXT_DOMAIN,
12294653Sdougm 				    "Attempt to change configuration"), 1);
12304653Sdougm 				continue;
12313034Sdougm 			}
12324524Sdougm 			/*
12334524Sdougm 			 * It is the same group but could have changed
12344524Sdougm 			 * options. Make sure we include the group's
12354524Sdougm 			 * properties so we don't end up moving them to
12364524Sdougm 			 * the share inadvertantly. The last arg being
12374524Sdougm 			 * true says to get the inherited properties as well
12384524Sdougm 			 * as the local properties.
12394524Sdougm 			 */
12404653Sdougm 			oldprops = sa_proto_legacy_format(list->fstype, share,
12414653Sdougm 			    B_TRUE);
12424653Sdougm 
12434653Sdougm 			if (oldprops == NULL)
12444653Sdougm 				continue;
12454653Sdougm 
12463034Sdougm 			if (list->options != NULL &&
12474653Sdougm 			    strcmp(oldprops, list->options) != 0) {
12484653Sdougm 				sa_optionset_t opts;
12494653Sdougm 				sa_security_t secs;
12504653Sdougm 
12514653Sdougm 				/* possibly different values */
12524653Sdougm 				opts = sa_get_optionset((sa_group_t)
12534653Sdougm 				    share, list->fstype);
12544653Sdougm 				(void) sa_destroy_optionset(opts);
12554653Sdougm 
12564653Sdougm 				for (secs = sa_get_security(
12574653Sdougm 				    (sa_group_t)share, NULL, list->fstype);
12584653Sdougm 				    secs != NULL;
12594653Sdougm 				    secs = sa_get_security((sa_group_t)share,
12604653Sdougm 				    NULL, list->fstype)) {
12614653Sdougm 					(void) sa_destroy_security(
12624653Sdougm 					    secs);
12634653Sdougm 				}
12644653Sdougm 				(void) sa_parse_legacy_options(share,
12654653Sdougm 				    list->options, list->fstype);
12663034Sdougm 			}
12673663Sdougm 			sa_format_free(oldprops);
12683034Sdougm 		}
12693034Sdougm 	}
12703034Sdougm 	dfs_free_list(head);
12713034Sdougm }
12723034Sdougm 
12733034Sdougm /*
12743034Sdougm  * legacy_removes(group, file)
12753034Sdougm  *
12763034Sdougm  * Find any shares that are "missing" from the legacy file. These
12773034Sdougm  * should be removed from the configuration since they are likely from
12783034Sdougm  * a legacy app or the admin modified the dfstab file directly. We
12793034Sdougm  * have to support this even if it is not the recommended way to do
12803034Sdougm  * things.
12813034Sdougm  */
12823034Sdougm 
12833034Sdougm static void
legacy_removes(sa_group_t group,char * file)12843034Sdougm legacy_removes(sa_group_t group, char *file)
12853034Sdougm {
12863034Sdougm 	sa_share_t share;
12873034Sdougm 	char *path;
12883034Sdougm 	xfs_sharelist_t *list, *item;
12893034Sdougm 	FILE *dfstab;
12903034Sdougm 
12913034Sdougm 	dfstab = fopen(file, "r");
12923034Sdougm 	if (dfstab != NULL) {
12934653Sdougm 		list = getdfstab(dfstab);
12944653Sdougm 		(void) fclose(dfstab);
12953348Sdougm retry:
12964653Sdougm 		for (share = sa_get_share(group, NULL);
12974653Sdougm 		    share != NULL;
12984653Sdougm 		    share = sa_get_next_share(share)) {
12994653Sdougm 			/* now see if the share is in the dfstab file */
13004653Sdougm 			path = sa_get_share_attr(share, "path");
13014653Sdougm 			if (path != NULL) {
13024653Sdougm 				item = finddfsentry(list, path);
13034653Sdougm 				sa_free_attr_string(path);
13044653Sdougm 				if (item == NULL) {
13054653Sdougm 					/* The share was removed this way */
13064653Sdougm 					(void) sa_remove_share(share);
13073348Sdougm 
13084653Sdougm 					/*
13094653Sdougm 					 * Start over since the list was broken
13104653Sdougm 					 */
13114653Sdougm 					goto retry;
13124653Sdougm 				}
13134653Sdougm 			}
13143034Sdougm 		}
13154653Sdougm 		if (list != NULL)
13164653Sdougm 			dfs_free_list(list);
13173034Sdougm 	}
13183034Sdougm }
13193034Sdougm 
13203034Sdougm /*
13213034Sdougm  * getlegacyconfig(path, root)
13223034Sdougm  *
13233034Sdougm  * Parse dfstab and build the legacy configuration. This only gets
13243034Sdougm  * called when a change was detected.
13253034Sdougm  */
13263034Sdougm 
13273034Sdougm void
getlegacyconfig(sa_handle_t handle,char * path,xmlNodePtr * root)13283910Sdougm getlegacyconfig(sa_handle_t handle, char *path, xmlNodePtr *root)
13293034Sdougm {
13303034Sdougm 	sa_group_t defgroup;
13313034Sdougm 
13323034Sdougm 	if (root != NULL) {
13334653Sdougm 		if (*root == NULL)
13344653Sdougm 			*root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
13354653Sdougm 		if (*root != NULL) {
13364653Sdougm 			if (strcmp(path, SA_LEGACY_DFSTAB) == 0) {
13374653Sdougm 				/*
13384653Sdougm 				 * Walk the default shares and find anything
13394653Sdougm 				 * missing.  we do this first to make sure it
13404653Sdougm 				 * is cleaned up since there may be legacy
13414653Sdougm 				 * code add/del via dfstab and we need to
13424653Sdougm 				 * cleanup SMF.
13434653Sdougm 				 */
13444653Sdougm 				defgroup = sa_get_group(handle, "default");
13454653Sdougm 				if (defgroup != NULL)
13464653Sdougm 					legacy_removes(defgroup, path);
13474653Sdougm 				/* Parse the dfstab and add anything new */
13484653Sdougm 				parse_dfstab(handle, path, *root);
13494653Sdougm 			}
13503034Sdougm 		}
13513034Sdougm 	}
13523034Sdougm }
13533034Sdougm 
13543034Sdougm /*
13553218Sdougm  * get_share_list(&err)
13563218Sdougm  *
13573218Sdougm  * Get a linked list of all the shares on the system from
13583218Sdougm  * /etc/dfs/sharetab. This is partially copied from libfsmgt which we
13593218Sdougm  * can't use due to package dependencies.
13603218Sdougm  */
13613218Sdougm static xfs_sharelist_t *
get_share_list(int * errp)13623218Sdougm get_share_list(int *errp)
13633218Sdougm {
13643218Sdougm 	xfs_sharelist_t	*newp;
13653218Sdougm 	xfs_sharelist_t	*headp;
13663218Sdougm 	xfs_sharelist_t	*tailp;
13673218Sdougm 	FILE		*fp;
13683218Sdougm 
13693218Sdougm 	headp = NULL;
13703218Sdougm 	tailp = NULL;
13713218Sdougm 
13723218Sdougm 	if ((fp = fopen(SHARETAB, "r")) != NULL) {
13733218Sdougm 		struct share	*sharetab_entry;
13743218Sdougm 
13758334SJose.Borrego@Sun.COM 		(void) lockf(fileno(fp), F_LOCK, 0);
13768334SJose.Borrego@Sun.COM 		(void) mutex_lock(&sharetab_lock);
13778334SJose.Borrego@Sun.COM 
13783218Sdougm 		while (getshare(fp, &sharetab_entry) > 0) {
13794653Sdougm 			newp = alloc_sharelist();
13808334SJose.Borrego@Sun.COM 			if (newp == NULL) {
13818334SJose.Borrego@Sun.COM 				(void) mutex_unlock(&sharetab_lock);
13828334SJose.Borrego@Sun.COM 				(void) lockf(fileno(fp), F_ULOCK, 0);
13834653Sdougm 				goto err;
13848334SJose.Borrego@Sun.COM 			}
13853218Sdougm 
13863218Sdougm 			/*
13874653Sdougm 			 * Link into the list here so we don't leak
13883218Sdougm 			 * memory on a failure from strdup().
13893218Sdougm 			 */
13904653Sdougm 			if (headp == NULL) {
13914653Sdougm 				headp = newp;
13924653Sdougm 				tailp = newp;
13934653Sdougm 			} else {
13944653Sdougm 				tailp->next = newp;
13954653Sdougm 				tailp = newp;
13964653Sdougm 			}
13973218Sdougm 
13984653Sdougm 			newp->path = strdup(sharetab_entry->sh_path);
13994653Sdougm 			newp->resource = strdup(sharetab_entry->sh_res);
14004653Sdougm 			newp->fstype = strdup(sharetab_entry->sh_fstype);
14018334SJose.Borrego@Sun.COM 			newp->options = strdup(sharetab_entry->sh_opts);
14028334SJose.Borrego@Sun.COM 			newp->description = strdup(sharetab_entry->sh_descr);
14038334SJose.Borrego@Sun.COM 
14048334SJose.Borrego@Sun.COM 			if (newp->path == NULL || newp->resource == NULL ||
14058334SJose.Borrego@Sun.COM 			    newp->fstype == NULL || newp->options == NULL ||
14068334SJose.Borrego@Sun.COM 			    newp->description == NULL) {
14078334SJose.Borrego@Sun.COM 				(void) mutex_unlock(&sharetab_lock);
14088334SJose.Borrego@Sun.COM 				(void) lockf(fileno(fp), F_ULOCK, 0);
14094653Sdougm 				goto err;
14108334SJose.Borrego@Sun.COM 			}
14113218Sdougm 		}
14128334SJose.Borrego@Sun.COM 
14138334SJose.Borrego@Sun.COM 		(void) mutex_unlock(&sharetab_lock);
14143663Sdougm 		(void) lockf(fileno(fp), F_ULOCK, 0);
14153218Sdougm 		(void) fclose(fp);
14163218Sdougm 	} else {
14174653Sdougm 		*errp = errno;
14183218Sdougm 	}
14193218Sdougm 
14203218Sdougm 	/*
14213218Sdougm 	 * Caller must free the mount list
14223218Sdougm 	 */
14233218Sdougm 	return (headp);
14243218Sdougm err:
14253218Sdougm 	/*
14263218Sdougm 	 * Out of memory so cleanup and leave.
14273218Sdougm 	 */
14283218Sdougm 	dfs_free_list(headp);
14293218Sdougm 	(void) fclose(fp);
14303218Sdougm 	return (NULL);
14313218Sdougm }
14323218Sdougm 
14333218Sdougm /*
14343910Sdougm  * parse_sharetab(handle)
14353034Sdougm  *
14363218Sdougm  * Read the /etc/dfs/sharetab file and see which entries don't exist
14373218Sdougm  * in the repository. These shares are marked transient.  We also need
14383218Sdougm  * to see if they are ZFS shares since ZFS bypasses the SMF
14393218Sdougm  * repository.
14403034Sdougm  */
14413034Sdougm 
14423034Sdougm int
parse_sharetab(sa_handle_t handle)14433910Sdougm parse_sharetab(sa_handle_t handle)
14443034Sdougm {
14453218Sdougm 	xfs_sharelist_t *list, *tmplist;
14463034Sdougm 	int err = 0;
14473034Sdougm 	sa_share_t share;
14483034Sdougm 	sa_group_t group;
14493034Sdougm 	sa_group_t lgroup;
14503034Sdougm 	char *groupname;
14513034Sdougm 	int legacy = 0;
14525331Samw 	char shareopts[MAXNAMLEN];
14533034Sdougm 
14543218Sdougm 	list = get_share_list(&err);
14553034Sdougm 	if (list == NULL)
14564653Sdougm 		return (legacy);
14573034Sdougm 
14583910Sdougm 	lgroup = sa_get_group(handle, "default");
14593034Sdougm 
14603034Sdougm 	for (tmplist = list; tmplist != NULL; tmplist = tmplist->next) {
14614653Sdougm 		group = NULL;
14624653Sdougm 		share = sa_find_share(handle, tmplist->path);
14634653Sdougm 		if (share != NULL) {
14644653Sdougm 			/*
14654653Sdougm 			 * If this is a legacy share, mark as shared so we
14664653Sdougm 			 * only update sharetab appropriately. We also keep
14674653Sdougm 			 * the sharetab options in order to display for legacy
14684653Sdougm 			 * share with no arguments.
14694653Sdougm 			 */
14704653Sdougm 			set_node_attr(share, "shared", "true");
14715331Samw 			(void) snprintf(shareopts, MAXNAMLEN, "shareopts-%s",
14725331Samw 			    tmplist->fstype);
14735331Samw 			set_node_attr(share, shareopts, tmplist->options);
14744653Sdougm 			continue;
14754653Sdougm 		}
14764653Sdougm 
14773034Sdougm 		/*
14784653Sdougm 		 * This share is transient so needs to be
14793034Sdougm 		 * added. Initially, this will be under
14803034Sdougm 		 * default(legacy) unless it is a ZFS
14813034Sdougm 		 * share. If zfs, we need a zfs group.
14823034Sdougm 		 */
14833034Sdougm 		if (tmplist->resource != NULL &&
14843034Sdougm 		    (groupname = strchr(tmplist->resource, '@')) != NULL) {
14854653Sdougm 			/* There is a defined group */
14864653Sdougm 			*groupname++ = '\0';
14874653Sdougm 			group = sa_get_group(handle, groupname);
14884653Sdougm 			if (group != NULL) {
14895331Samw 				share = _sa_add_share(group, tmplist->path,
14905331Samw 				    SA_SHARE_TRANSIENT, &err,
14915331Samw 				    (uint64_t)SA_FEATURE_NONE);
14924653Sdougm 			} else {
14934653Sdougm 				/*
14944653Sdougm 				 * While this case shouldn't
14954653Sdougm 				 * occur very often, it does
14964653Sdougm 				 * occur out of a "zfs set
14974653Sdougm 				 * sharenfs=off" when the
14984653Sdougm 				 * dataset is also set to
14994653Sdougm 				 * canmount=off. A warning
15004653Sdougm 				 * will then cause the zfs
15014653Sdougm 				 * command to abort. Since we
15024653Sdougm 				 * add it to the default list,
15034653Sdougm 				 * everything works properly
15044653Sdougm 				 * anyway and the library
15054653Sdougm 				 * doesn't need to give a
15064653Sdougm 				 * warning.
15074653Sdougm 				 */
15084653Sdougm 				share = _sa_add_share(lgroup,
15094653Sdougm 				    tmplist->path, SA_SHARE_TRANSIENT,
15105331Samw 				    &err, (uint64_t)SA_FEATURE_NONE);
15114653Sdougm 			}
15123034Sdougm 		} else {
15134653Sdougm 			if (sa_zfs_is_shared(handle, tmplist->path)) {
15144653Sdougm 				group = sa_get_group(handle, "zfs");
15154653Sdougm 				if (group == NULL) {
15164653Sdougm 					group = sa_create_group(handle,
15174653Sdougm 					    "zfs", &err);
15184653Sdougm 					if (group == NULL &&
15194653Sdougm 					    err == SA_NO_PERMISSION) {
15204653Sdougm 						group = _sa_create_group(
15214653Sdougm 						    (sa_handle_impl_t)
15224653Sdougm 						    handle,
15234653Sdougm 						    "zfs");
15244653Sdougm 					}
15254653Sdougm 					if (group != NULL) {
15264653Sdougm 						(void) sa_create_optionset(
15274653Sdougm 						    group, tmplist->fstype);
15284653Sdougm 						(void) sa_set_group_attr(group,
15294653Sdougm 						    "zfs", "true");
15304653Sdougm 					}
15314653Sdougm 				}
15324653Sdougm 				if (group != NULL) {
15334653Sdougm 					share = _sa_add_share(group,
15344653Sdougm 					    tmplist->path, SA_SHARE_TRANSIENT,
15355331Samw 					    &err, (uint64_t)SA_FEATURE_NONE);
15364653Sdougm 				}
15374653Sdougm 			} else {
15384653Sdougm 				share = _sa_add_share(lgroup, tmplist->path,
15395331Samw 				    SA_SHARE_TRANSIENT, &err,
15405331Samw 				    (uint64_t)SA_FEATURE_NONE);
15413034Sdougm 			}
15423034Sdougm 		}
15433034Sdougm 		if (share == NULL)
15444653Sdougm 			(void) printf(dgettext(TEXT_DOMAIN,
15454653Sdougm 			    "Problem with transient: %s\n"), sa_errorstr(err));
15463034Sdougm 		if (share != NULL)
15474653Sdougm 			set_node_attr(share, "shared", "true");
15483034Sdougm 		if (err == SA_OK) {
15494653Sdougm 			if (tmplist->options != NULL &&
15504653Sdougm 			    strlen(tmplist->options) > 0) {
15514653Sdougm 				(void) sa_parse_legacy_options(share,
15524653Sdougm 				    tmplist->options, tmplist->fstype);
15534653Sdougm 			}
15544653Sdougm 			if (tmplist->resource != NULL &&
15554653Sdougm 			    strcmp(tmplist->resource, "-") != 0)
15564653Sdougm 				set_node_attr(share, "resource",
15574653Sdougm 				    tmplist->resource);
15584653Sdougm 			if (tmplist->description != NULL) {
15594653Sdougm 				xmlNodePtr node;
15604653Sdougm 				node = xmlNewChild((xmlNodePtr)share, NULL,
15614653Sdougm 				    (xmlChar *)"description", NULL);
15624653Sdougm 				xmlNodeSetContent(node,
15634653Sdougm 				    (xmlChar *)tmplist->description);
15644653Sdougm 			}
15654653Sdougm 			legacy = 1;
15663034Sdougm 		}
15673034Sdougm 	}
15683218Sdougm 	dfs_free_list(list);
15693034Sdougm 	return (legacy);
15703034Sdougm }
15713034Sdougm 
15723034Sdougm /*
15734653Sdougm  * Get the transient shares from the sharetab (or other) file.  since
15743034Sdougm  * these are transient, they only appear in the working file and not
15753034Sdougm  * in a repository.
15763034Sdougm  */
15773034Sdougm int
gettransients(sa_handle_impl_t ihandle,xmlNodePtr * root)15783910Sdougm gettransients(sa_handle_impl_t ihandle, xmlNodePtr *root)
15793034Sdougm {
15803034Sdougm 	int legacy = 0;
15815331Samw 	int numproto;
15825331Samw 	char **protocols = NULL;
15835331Samw 	int i;
15843034Sdougm 
15853034Sdougm 	if (root != NULL) {
15864653Sdougm 		if (*root == NULL)
15874653Sdougm 			*root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
15885331Samw 		if (*root != NULL) {
15894653Sdougm 			legacy = parse_sharetab(ihandle);
15905331Samw 			numproto = sa_get_protocols(&protocols);
15915331Samw 			for (i = 0; i < numproto; i++)
15925331Samw 				legacy |= sa_proto_get_transients(
15935331Samw 				    (sa_handle_t)ihandle, protocols[i]);
15945331Samw 			if (protocols != NULL)
15955331Samw 				free(protocols);
15965331Samw 		}
15973034Sdougm 	}
15983034Sdougm 	return (legacy);
15993034Sdougm }
16003034Sdougm 
16013034Sdougm /*
16023034Sdougm  * sa_has_prop(optionset, prop)
16033034Sdougm  *
16043034Sdougm  * Is the specified property a member of the optionset?
16053034Sdougm  */
16063034Sdougm 
16073034Sdougm int
sa_has_prop(sa_optionset_t optionset,sa_property_t prop)16083034Sdougm sa_has_prop(sa_optionset_t optionset, sa_property_t prop)
16093034Sdougm {
16103034Sdougm 	char *name;
16113034Sdougm 	sa_property_t otherprop;
16123034Sdougm 	int result = 0;
16133034Sdougm 
16143034Sdougm 	if (optionset != NULL) {
16154653Sdougm 		name = sa_get_property_attr(prop, "type");
16164653Sdougm 		if (name != NULL) {
16174653Sdougm 			otherprop = sa_get_property(optionset, name);
16184653Sdougm 			if (otherprop != NULL)
16194653Sdougm 				result = 1;
16204653Sdougm 			sa_free_attr_string(name);
16214653Sdougm 		}
16223034Sdougm 	}
16233034Sdougm 	return (result);
16243034Sdougm }
16253034Sdougm 
16263034Sdougm /*
16273034Sdougm  * Update legacy files
16283034Sdougm  *
16293034Sdougm  * Provides functions to add/remove/modify individual entries
16303034Sdougm  * in dfstab and sharetab
16313034Sdougm  */
16323034Sdougm 
16333034Sdougm void
update_legacy_config(sa_handle_t handle)16343910Sdougm update_legacy_config(sa_handle_t handle)
16353034Sdougm {
16363034Sdougm 	/*
16373034Sdougm 	 * no longer used -- this is a placeholder in case we need to
16383034Sdougm 	 * add it back later.
16393034Sdougm 	 */
16403910Sdougm #ifdef lint
16413910Sdougm 	handle = handle;
16423910Sdougm #endif
16433034Sdougm }
16443034Sdougm 
16453034Sdougm /*
16466214Sdougm  * sa_valid_property(handle, object, proto, property)
16473034Sdougm  *
16483034Sdougm  * check to see if the specified property is valid relative to the
16493034Sdougm  * specified protocol. The protocol plugin is called to do the work.
16503034Sdougm  */
16513034Sdougm 
16523034Sdougm int
sa_valid_property(sa_handle_t handle,void * object,char * proto,sa_property_t property)16536214Sdougm sa_valid_property(sa_handle_t handle, void *object, char *proto,
16546214Sdougm     sa_property_t property)
16553034Sdougm {
16563034Sdougm 	int ret = SA_OK;
16573034Sdougm 
16583034Sdougm 	if (proto != NULL && property != NULL) {
16596214Sdougm 		ret = sa_proto_valid_prop(handle, proto, property, object);
16603034Sdougm 	}
16613034Sdougm 
16623034Sdougm 	return (ret);
16633034Sdougm }
16643034Sdougm 
16653034Sdougm /*
16663034Sdougm  * sa_fstype(path)
16673034Sdougm  *
16683034Sdougm  * Given path, return the string representing the path's file system
16693034Sdougm  * type. This is used to discover ZFS shares.
16703034Sdougm  */
16713034Sdougm 
16723034Sdougm char *
sa_fstype(char * path)16733034Sdougm sa_fstype(char *path)
16743034Sdougm {
16753034Sdougm 	int err;
16763034Sdougm 	struct stat st;
16773034Sdougm 
16783034Sdougm 	err = stat(path, &st);
16794653Sdougm 	if (err < 0)
16804653Sdougm 		err = SA_NO_SUCH_PATH;
16814653Sdougm 	else
16824653Sdougm 		err = SA_OK;
16834653Sdougm 
16844653Sdougm 	/*
16854653Sdougm 	 * If we have a valid path at this point ret, return the fstype.
16864653Sdougm 	 */
16874653Sdougm 	if (err == SA_OK)
16884653Sdougm 		return (strdup(st.st_fstype));
16894653Sdougm 
16903034Sdougm 	return (NULL);
16913034Sdougm }
16923034Sdougm 
16933034Sdougm void
sa_free_fstype(char * type)16943034Sdougm sa_free_fstype(char *type)
16953034Sdougm {
16963034Sdougm 	free(type);
16973034Sdougm }
16983034Sdougm 
16993034Sdougm /*
17003034Sdougm  * sa_get_derived_optionset(object, proto, hier)
17013034Sdougm  *
17023034Sdougm  *	Work backward to the top of the share object tree and start
17033034Sdougm  *	copying protocol specific optionsets into a newly created
17043034Sdougm  *	optionset that doesn't have a parent (it will be freed
17055331Samw  *	later). This provides for the property inheritance model. That
17063034Sdougm  *	is, properties closer to the share take precedence over group
17073034Sdougm  *	level. This also provides for groups of groups in the future.
17083034Sdougm  */
17093034Sdougm 
17103034Sdougm sa_optionset_t
sa_get_derived_optionset(void * object,char * proto,int hier)17113034Sdougm sa_get_derived_optionset(void *object, char *proto, int hier)
17123034Sdougm {
17133034Sdougm 	sa_optionset_t newoptionset;
17143034Sdougm 	sa_optionset_t optionset;
17153034Sdougm 	sa_group_t group;
17163034Sdougm 
17173034Sdougm 	if (hier &&
17183034Sdougm 	    (group = sa_get_parent_group((sa_share_t)object)) != NULL) {
17194653Sdougm 		newoptionset = sa_get_derived_optionset((void *)group, proto,
17204653Sdougm 		    hier);
17213034Sdougm 	} else {
17224653Sdougm 		newoptionset = (sa_optionset_t)xmlNewNode(NULL,
17234653Sdougm 		    (xmlChar *)"optionset");
17244653Sdougm 		if (newoptionset != NULL) {
17254653Sdougm 			sa_set_optionset_attr(newoptionset, "type", proto);
17264653Sdougm 		}
17273034Sdougm 	}
17284653Sdougm 	/* Dont' do anything if memory wasn't allocated */
17293034Sdougm 	if (newoptionset == NULL)
17304653Sdougm 		return (NULL);
17313034Sdougm 
17324653Sdougm 	/* Found the top so working back down the stack */
17333034Sdougm 	optionset = sa_get_optionset((sa_optionset_t)object, proto);
17343034Sdougm 	if (optionset != NULL) {
17354653Sdougm 		sa_property_t prop;
17364653Sdougm 		/* add optionset to the newoptionset */
17374653Sdougm 		for (prop = sa_get_property(optionset, NULL);
17384653Sdougm 		    prop != NULL;
17394653Sdougm 		    prop = sa_get_next_property(prop)) {
17404653Sdougm 			sa_property_t newprop;
17414653Sdougm 			char *name;
17424653Sdougm 			char *value;
17434653Sdougm 			name = sa_get_property_attr(prop, "type");
17444653Sdougm 			value = sa_get_property_attr(prop, "value");
17454653Sdougm 			if (name == NULL)
17464653Sdougm 				continue;
17474653Sdougm 			newprop = sa_get_property(newoptionset, name);
17484653Sdougm 			/* Replace the value with the new value */
17494653Sdougm 			if (newprop != NULL) {
17504653Sdougm 				/*
17514653Sdougm 				 * Only set if value is non NULL, old value ok
17524653Sdougm 				 * if it is NULL.
17534653Sdougm 				 */
17544653Sdougm 				if (value != NULL)
17554653Sdougm 					set_node_attr(newprop, "value", value);
17564653Sdougm 			} else {
17574653Sdougm 				/* an entirely new property */
17584653Sdougm 				if (value != NULL) {
17594653Sdougm 					newprop = sa_create_property(name,
17604653Sdougm 					    value);
17614653Sdougm 					if (newprop != NULL) {
17624653Sdougm 						newprop = (sa_property_t)
17634653Sdougm 						    xmlAddChild(
17644653Sdougm 						    (xmlNodePtr)newoptionset,
17654653Sdougm 						    (xmlNodePtr)newprop);
17664653Sdougm 					}
17674653Sdougm 				}
17684653Sdougm 			}
17694653Sdougm 			sa_free_attr_string(name);
17704653Sdougm 
17713034Sdougm 			if (value != NULL)
17724653Sdougm 				sa_free_attr_string(value);
17733034Sdougm 		}
17743034Sdougm 	}
17753034Sdougm 	return (newoptionset);
17763034Sdougm }
17773034Sdougm 
17783034Sdougm void
sa_free_derived_optionset(sa_optionset_t optionset)17793034Sdougm sa_free_derived_optionset(sa_optionset_t optionset)
17803034Sdougm {
17814653Sdougm 	/* While it shouldn't be linked, it doesn't hurt */
17823034Sdougm 	if (optionset != NULL) {
17834653Sdougm 		xmlUnlinkNode((xmlNodePtr) optionset);
17844653Sdougm 		xmlFreeNode((xmlNodePtr) optionset);
17853034Sdougm 	}
17863034Sdougm }
17873034Sdougm 
17883034Sdougm /*
17893034Sdougm  *  sa_get_all_security_types(object, proto, hier)
17903034Sdougm  *
17914653Sdougm  *	Find all the security types set for this object.  This is
17923034Sdougm  *	preliminary to getting a derived security set. The return value is an
17933034Sdougm  *	optionset containg properties which are the sectype values found by
17945331Samw  *	walking up the XML document structure. The returned optionset
17953034Sdougm  *	is a derived optionset.
17963034Sdougm  *
17973034Sdougm  *	If hier is 0, only look at object. If non-zero, walk up the tree.
17983034Sdougm  */
17993034Sdougm sa_optionset_t
sa_get_all_security_types(void * object,char * proto,int hier)18003034Sdougm sa_get_all_security_types(void *object, char *proto, int hier)
18013034Sdougm {
18023034Sdougm 	sa_optionset_t options;
18033034Sdougm 	sa_security_t security;
18043034Sdougm 	sa_group_t group;
18053034Sdougm 	sa_property_t prop;
18063034Sdougm 
18073034Sdougm 	options = NULL;
18083034Sdougm 
18093034Sdougm 	if (hier &&
18104653Sdougm 	    (group = sa_get_parent_group((sa_share_t)object)) != NULL)
18114653Sdougm 		options = sa_get_all_security_types((void *)group, proto, hier);
18124653Sdougm 	else
18134653Sdougm 		options = (sa_optionset_t)xmlNewNode(NULL,
18144653Sdougm 		    (xmlChar *)"optionset");
18154653Sdougm 
18164653Sdougm 	if (options == NULL)
18174653Sdougm 		return (options);
18184653Sdougm 
18194653Sdougm 	/* Hit the top so collect the security types working back. */
18204653Sdougm 	for (security = sa_get_security((sa_group_t)object, NULL, NULL);
18214653Sdougm 	    security != NULL;
18224653Sdougm 	    security = sa_get_next_security(security)) {
18233034Sdougm 		char *type;
18243034Sdougm 		char *sectype;
18253034Sdougm 
18263034Sdougm 		type = sa_get_security_attr(security, "type");
18273034Sdougm 		if (type != NULL) {
18284653Sdougm 			if (strcmp(type, proto) != 0) {
18294653Sdougm 				sa_free_attr_string(type);
18304653Sdougm 				continue;
18314653Sdougm 			}
18324653Sdougm 			sectype = sa_get_security_attr(security, "sectype");
18334653Sdougm 			if (sectype != NULL) {
18344653Sdougm 				/*
18354653Sdougm 				 * Have a security type, check to see if
18364653Sdougm 				 * already present in optionset and add if it
18374653Sdougm 				 * isn't.
18384653Sdougm 				 */
18394653Sdougm 				if (sa_get_property(options, sectype) == NULL) {
18404653Sdougm 					prop = sa_create_property(sectype,
18414653Sdougm 					    "true");
18424653Sdougm 					if (prop != NULL)
18434653Sdougm 						prop = (sa_property_t)
18444653Sdougm 						    xmlAddChild(
18454653Sdougm 						    (xmlNodePtr)options,
18464653Sdougm 						    (xmlNodePtr)prop);
18474653Sdougm 				}
18484653Sdougm 				sa_free_attr_string(sectype);
18494653Sdougm 			}
18503034Sdougm 			sa_free_attr_string(type);
18513034Sdougm 		}
18523034Sdougm 	}
18534653Sdougm 
18543034Sdougm 	return (options);
18553034Sdougm }
18563034Sdougm 
18573034Sdougm /*
18583034Sdougm  * sa_get_derived_security(object, sectype, proto, hier)
18593034Sdougm  *
18603034Sdougm  * Get the derived security(named optionset) for the object given the
18613034Sdougm  * sectype and proto. If hier is non-zero, walk up the tree to get all
18623034Sdougm  * properties defined for this object, otherwise just those on the
18633034Sdougm  * object.
18643034Sdougm  */
18653034Sdougm 
18663034Sdougm sa_security_t
sa_get_derived_security(void * object,char * sectype,char * proto,int hier)18673034Sdougm sa_get_derived_security(void *object, char *sectype, char *proto, int hier)
18683034Sdougm {
18693034Sdougm 	sa_security_t newsecurity;
18703034Sdougm 	sa_security_t security;
18713034Sdougm 	sa_group_t group;
18724653Sdougm 	sa_property_t prop;
18733034Sdougm 
18743034Sdougm 	if (hier &&
18753034Sdougm 	    (group = sa_get_parent_group((sa_share_t)object)) != NULL) {
18764653Sdougm 		newsecurity = sa_get_derived_security((void *)group,
18774653Sdougm 		    sectype, proto, hier);
18783034Sdougm 	} else {
18794653Sdougm 		newsecurity = (sa_security_t)xmlNewNode(NULL,
18804653Sdougm 		    (xmlChar *)"security");
18814653Sdougm 		if (newsecurity != NULL) {
18824653Sdougm 			sa_set_security_attr(newsecurity, "type", proto);
18834653Sdougm 			sa_set_security_attr(newsecurity, "sectype", sectype);
18844653Sdougm 		}
18853034Sdougm 	}
18864653Sdougm 	/* Don't do anything if memory wasn't allocated */
18873034Sdougm 	if (newsecurity == NULL)
18884653Sdougm 		return (newsecurity);
18893034Sdougm 
18904653Sdougm 	/* Found the top so working back down the stack. */
18913034Sdougm 	security = sa_get_security((sa_security_t)object, sectype, proto);
18924653Sdougm 	if (security == NULL)
18934653Sdougm 		return (newsecurity);
18944653Sdougm 
18954653Sdougm 	/* add security to the newsecurity */
18964653Sdougm 	for (prop = sa_get_property(security, NULL);
18974653Sdougm 	    prop != NULL; prop = sa_get_next_property(prop)) {
18983034Sdougm 		sa_property_t newprop;
18993034Sdougm 		char *name;
19003034Sdougm 		char *value;
19013034Sdougm 		name = sa_get_property_attr(prop, "type");
19023034Sdougm 		value = sa_get_property_attr(prop, "value");
19033034Sdougm 		if (name != NULL) {
19044653Sdougm 			newprop = sa_get_property(newsecurity, name);
19054653Sdougm 			/* Replace the value with the new value */
19064653Sdougm 			if (newprop != NULL) {
19074653Sdougm 				/*
19085454Sdougm 				 * Only set if value is non NULL, old
19095454Sdougm 				 * value ok if it is NULL. The value
19105454Sdougm 				 * must be associated with the "value"
19115454Sdougm 				 * tag within XML.
19124653Sdougm 				 */
19134653Sdougm 				if (value != NULL)
19145454Sdougm 					set_node_attr(newprop, "value", value);
19154653Sdougm 			} else {
19164653Sdougm 				/* An entirely new property */
19174653Sdougm 				if (value != NULL) {
19184653Sdougm 					newprop = sa_create_property(name,
19194653Sdougm 					    value);
19204653Sdougm 					newprop = (sa_property_t)
19214653Sdougm 					    xmlAddChild((xmlNodePtr)newsecurity,
19223034Sdougm 					    (xmlNodePtr)newprop);
19234653Sdougm 				}
19243034Sdougm 			}
19254653Sdougm 			sa_free_attr_string(name);
19263034Sdougm 		}
19273034Sdougm 		if (value != NULL)
19284653Sdougm 			sa_free_attr_string(value);
19293034Sdougm 	}
19303034Sdougm 	return (newsecurity);
19313034Sdougm }
19323034Sdougm 
19333034Sdougm void
sa_free_derived_security(sa_security_t security)19343034Sdougm sa_free_derived_security(sa_security_t security)
19353034Sdougm {
19363034Sdougm 	/* while it shouldn't be linked, it doesn't hurt */
19373034Sdougm 	if (security != NULL) {
19384653Sdougm 		xmlUnlinkNode((xmlNodePtr)security);
19394653Sdougm 		xmlFreeNode((xmlNodePtr)security);
19403034Sdougm 	}
19413034Sdougm }
19423034Sdougm 
19433034Sdougm /*
19443034Sdougm  * sharetab utility functions
19453034Sdougm  *
19464653Sdougm  * Makes use of the original sharetab.c from fs.d/nfs/lib
19473034Sdougm  */
19483034Sdougm 
19493034Sdougm /*
19504543Smarks  * sa_fillshare(share, proto, sh)
19513034Sdougm  *
19523034Sdougm  * Fill the struct share with values obtained from the share object.
19533034Sdougm  */
19544543Smarks void
sa_fillshare(sa_share_t share,char * proto,struct share * sh)19554543Smarks sa_fillshare(sa_share_t share, char *proto, struct share *sh)
19563034Sdougm {
19573034Sdougm 	char *groupname = NULL;
19583034Sdougm 	char *value;
19593034Sdougm 	sa_group_t group;
19603034Sdougm 	char *buff;
19613034Sdougm 	char *zfs;
19625331Samw 	sa_resource_t resource;
19635331Samw 	char *rsrcname = NULL;
19645331Samw 	char *defprop;
19655331Samw 
19665331Samw 	/*
19675331Samw 	 * We only want to deal with the path level shares for the
19685331Samw 	 * sharetab file. If a resource, get the parent.
19695331Samw 	 */
19705331Samw 	if (sa_is_resource(share)) {
19715331Samw 		resource = (sa_resource_t)share;
19725331Samw 		share = sa_get_resource_parent(resource);
19735331Samw 		rsrcname = sa_get_resource_attr(resource, "name");
19745331Samw 	}
19753034Sdougm 
19763034Sdougm 	group = sa_get_parent_group(share);
19773034Sdougm 	if (group != NULL) {
19784653Sdougm 		zfs = sa_get_group_attr(group, "zfs");
19794653Sdougm 		groupname = sa_get_group_attr(group, "name");
19803034Sdougm 
19814653Sdougm 		if (groupname != NULL &&
19824653Sdougm 		    (strcmp(groupname, "default") == 0 || zfs != NULL)) {
19834653Sdougm 			/*
19844653Sdougm 			 * since the groupname is either "default" or the
19854653Sdougm 			 * group is a ZFS group, we don't want to keep
19864653Sdougm 			 * groupname. We do want it if it is any other type of
19874653Sdougm 			 * group.
19884653Sdougm 			 */
19894653Sdougm 			sa_free_attr_string(groupname);
19904653Sdougm 			groupname = NULL;
19914653Sdougm 		}
19924653Sdougm 		if (zfs != NULL)
19934653Sdougm 			sa_free_attr_string(zfs);
19943034Sdougm 	}
19953034Sdougm 
19963034Sdougm 	value = sa_get_share_attr(share, "path");
19973034Sdougm 	if (value != NULL) {
19984653Sdougm 		sh->sh_path = strdup(value);
19994653Sdougm 		sa_free_attr_string(value);
20003034Sdougm 	}
20013034Sdougm 
20025331Samw 	if (rsrcname != NULL || groupname != NULL) {
20034653Sdougm 		int len = 0;
20043034Sdougm 
20055331Samw 		if (rsrcname != NULL)
20065331Samw 			len += strlen(rsrcname);
20074653Sdougm 		if (groupname != NULL)
20084653Sdougm 			len += strlen(groupname);
20094653Sdougm 		len += 3; /* worst case */
20104653Sdougm 		buff = malloc(len);
20114653Sdougm 		(void) snprintf(buff, len, "%s%s%s",
20125331Samw 		    (rsrcname != NULL &&
20135331Samw 		    strlen(rsrcname) > 0) ? rsrcname : "-",
20143034Sdougm 		    groupname != NULL ? "@" : "",
20153034Sdougm 		    groupname != NULL ? groupname : "");
20164653Sdougm 		sh->sh_res = buff;
20175331Samw 		if (rsrcname != NULL)
20185331Samw 			sa_free_attr_string(rsrcname);
20195331Samw 		if (groupname != NULL)
20204653Sdougm 			sa_free_attr_string(groupname);
20213034Sdougm 	} else {
20224653Sdougm 		sh->sh_res = strdup("-");
20233034Sdougm 	}
20243034Sdougm 
20255331Samw 	/*
20265331Samw 	 * Get correct default prop string. NFS uses "rw", others use
20275331Samw 	 * "".
20285331Samw 	 */
20295331Samw 	if (strcmp(proto, "nfs") != 0)
20305331Samw 		defprop = "\"\"";
20315331Samw 	else
20325331Samw 		defprop = "rw";
20335331Samw 
20343034Sdougm 	sh->sh_fstype = strdup(proto);
20353034Sdougm 	value = sa_proto_legacy_format(proto, share, 1);
20363034Sdougm 	if (value != NULL) {
20374653Sdougm 		if (strlen(value) > 0)
20384653Sdougm 			sh->sh_opts = strdup(value);
20394653Sdougm 		else
20405331Samw 			sh->sh_opts = strdup(defprop);
20414653Sdougm 		free(value);
20424653Sdougm 	} else {
20435331Samw 		sh->sh_opts = strdup(defprop);
20444653Sdougm 	}
20453034Sdougm 
20463034Sdougm 	value = sa_get_share_description(share);
20473034Sdougm 	if (value != NULL) {
20484653Sdougm 		sh->sh_descr = strdup(value);
20494653Sdougm 		sa_free_share_description(value);
20504653Sdougm 	} else {
20514653Sdougm 		sh->sh_descr = strdup("");
20524653Sdougm 	}
20533034Sdougm }
20543034Sdougm 
20553034Sdougm /*
20564543Smarks  * sa_emptyshare(sh)
20573034Sdougm  *
20583034Sdougm  * Free the strings in the non-NULL members of sh.
20593034Sdougm  */
20603034Sdougm 
20614543Smarks void
sa_emptyshare(struct share * sh)20624543Smarks sa_emptyshare(struct share *sh)
20633034Sdougm {
20643034Sdougm 	if (sh->sh_path != NULL)
20654653Sdougm 		free(sh->sh_path);
20663034Sdougm 	sh->sh_path = NULL;
20673034Sdougm 	if (sh->sh_res != NULL)
20684653Sdougm 		free(sh->sh_res);
20693034Sdougm 	sh->sh_res = NULL;
20703034Sdougm 	if (sh->sh_fstype != NULL)
20714653Sdougm 		free(sh->sh_fstype);
20723034Sdougm 	sh->sh_fstype = NULL;
20733034Sdougm 	if (sh->sh_opts != NULL)
20744653Sdougm 		free(sh->sh_opts);
20753034Sdougm 	sh->sh_opts = NULL;
20763034Sdougm 	if (sh->sh_descr != NULL)
20774653Sdougm 		free(sh->sh_descr);
20783034Sdougm 	sh->sh_descr = NULL;
20793034Sdougm }
20803034Sdougm 
20813034Sdougm /*
20825951Sdougm  * sa_update_sharetab_ts(handle)
20835951Sdougm  *
20845951Sdougm  * Update the internal timestamp of when sharetab was last
20855951Sdougm  * changed. This needs to be public for ZFS to get at it.
20865951Sdougm  */
20875951Sdougm 
20885951Sdougm void
sa_update_sharetab_ts(sa_handle_t handle)20895951Sdougm sa_update_sharetab_ts(sa_handle_t handle)
20905951Sdougm {
20915951Sdougm 	struct stat st;
20925951Sdougm 	sa_handle_impl_t implhandle = (sa_handle_impl_t)handle;
20935951Sdougm 
20945951Sdougm 	if (implhandle != NULL && stat(SA_LEGACY_SHARETAB, &st) == 0)
20955951Sdougm 		implhandle->tssharetab = TSTAMP(st.st_mtim);
20965951Sdougm }
20975951Sdougm 
20985951Sdougm /*
20993034Sdougm  * sa_update_sharetab(share, proto)
21003034Sdougm  *
21013034Sdougm  * Update the sharetab file with info from the specified share.
21023034Sdougm  * This could be an update or add.
21033034Sdougm  */
21043034Sdougm 
21053034Sdougm int
sa_update_sharetab(sa_share_t share,char * proto)21063034Sdougm sa_update_sharetab(sa_share_t share, char *proto)
21073034Sdougm {
21083957Sth199096 	int	ret = SA_OK;
21093957Sth199096 	share_t	sh;
21103957Sth199096 	char	*path;
21115951Sdougm 	sa_handle_t handle;
21123034Sdougm 
21133034Sdougm 	path = sa_get_share_attr(share, "path");
21143034Sdougm 	if (path != NULL) {
21153957Sth199096 		(void) memset(&sh, '\0', sizeof (sh));
21163957Sth199096 
21175951Sdougm 		handle = sa_find_group_handle((sa_group_t)share);
21185951Sdougm 		if (handle != NULL) {
21195951Sdougm 			/*
21205951Sdougm 			 * Fill in share structure and send it to the kernel.
21215951Sdougm 			 */
21225951Sdougm 			(void) sa_fillshare(share, proto, &sh);
21235951Sdougm 			(void) _sharefs(SHAREFS_ADD, &sh);
21245951Sdougm 			/*
21255951Sdougm 			 * We need the timestamp of the sharetab file right
21265951Sdougm 			 * after the update was done. This lets us detect a
21275951Sdougm 			 * change that made by a different process.
21285951Sdougm 			 */
21295951Sdougm 			sa_update_sharetab_ts(handle);
21305951Sdougm 			sa_emptyshare(&sh);
21315951Sdougm 		} else {
21325951Sdougm 			ret = SA_CONFIG_ERR;
21335951Sdougm 		}
21343957Sth199096 		sa_free_attr_string(path);
21353034Sdougm 	}
21363957Sth199096 
21373034Sdougm 	return (ret);
21383034Sdougm }
21393034Sdougm 
21403034Sdougm /*
21415951Sdougm  * sa_delete_sharetab(handle, path, proto)
21423034Sdougm  *
21433034Sdougm  * remove the specified share from sharetab.
21443034Sdougm  */
21453034Sdougm 
21463034Sdougm int
sa_delete_sharetab(sa_handle_t handle,char * path,char * proto)21475951Sdougm sa_delete_sharetab(sa_handle_t handle, char *path, char *proto)
21483034Sdougm {
21493957Sth199096 	int	ret = SA_OK;
21505951Sdougm 	struct stat st;
21513957Sth199096 
21523957Sth199096 	share_t	sh;
21533957Sth199096 	/*
21543957Sth199096 	 * Both the path and the proto are
21553957Sth199096 	 * keys into the sharetab.
21563957Sth199096 	 */
21573957Sth199096 	if (path != NULL && proto != NULL) {
21583957Sth199096 		(void) memset(&sh, '\0', sizeof (sh));
21593957Sth199096 		sh.sh_path = path;
21603957Sth199096 		sh.sh_fstype = proto;
21613957Sth199096 
21624995Sth199096 		ret = _sharefs(SHAREFS_REMOVE, &sh);
21635951Sdougm 		if (handle != NULL && stat(SA_LEGACY_SHARETAB, &st) == 0)
21645951Sdougm 			sa_update_sharetab_ts(handle);
21655951Sdougm 	}
21665951Sdougm 	return (ret);
21675951Sdougm }
21685951Sdougm 
21695951Sdougm /*
21705951Sdougm  * sa_needs_refresh(handle)
21715951Sdougm  *
21725951Sdougm  * Returns B_TRUE if the internal cache needs to be refreshed do to a
21735951Sdougm  * change by another process.  B_FALSE returned otherwise.
21745951Sdougm  */
21755951Sdougm boolean_t
sa_needs_refresh(sa_handle_t handle)21765958Sdougm sa_needs_refresh(sa_handle_t handle)
21775951Sdougm {
21785951Sdougm 	sa_handle_impl_t implhandle = (sa_handle_impl_t)handle;
21795951Sdougm 	struct stat st;
21805951Sdougm 	char *str;
21815951Sdougm 	uint64_t tstamp;
21825951Sdougm 	scf_simple_prop_t *prop;
21835951Sdougm 
21845951Sdougm 	if (handle == NULL)
21855951Sdougm 		return (B_TRUE);
21865951Sdougm 
21875951Sdougm 	/*
21885951Sdougm 	 * If sharetab has changed, then there was an external
21895951Sdougm 	 * change. Check sharetab first since it is updated by ZFS as
21905951Sdougm 	 * well as sharemgr.  This is where external ZFS changes are
21915951Sdougm 	 * caught.
21925951Sdougm 	 */
21935951Sdougm 	if (stat(SA_LEGACY_SHARETAB, &st) == 0 &&
21945951Sdougm 	    TSTAMP(st.st_mtim) != implhandle->tssharetab)
21955951Sdougm 		return (B_TRUE);
21965951Sdougm 
21975951Sdougm 	/*
21985951Sdougm 	 * If sharetab wasn't changed, check whether there were any
21995951Sdougm 	 * SMF transactions that modified the config but didn't
22005951Sdougm 	 * initiate a share.  This is less common but does happen.
22015951Sdougm 	 */
22025951Sdougm 	prop = scf_simple_prop_get(implhandle->scfhandle->handle,
22035951Sdougm 	    (const char *)SA_SVC_FMRI_BASE ":default", "state",
22045951Sdougm 	    "lastupdate");
22055951Sdougm 	if (prop != NULL) {
22065951Sdougm 		str = scf_simple_prop_next_astring(prop);
22075951Sdougm 		if (str != NULL)
22085951Sdougm 			tstamp = strtoull(str, NULL, 0);
22095951Sdougm 		else
22105951Sdougm 			tstamp = 0;
22115951Sdougm 		scf_simple_prop_free(prop);
22125951Sdougm 		if (tstamp != implhandle->tstrans)
22135951Sdougm 			return (B_TRUE);
22143034Sdougm 	}
22153957Sth199096 
22165951Sdougm 	return (B_FALSE);
22173034Sdougm }
22185951Sdougm 
22195331Samw /*
22205331Samw  * sa_fix_resource_name(path)
22215331Samw  *
22228474SJose.Borrego@Sun.COM  * Convert invalid characters in a resource name (SMB share name)
22238474SJose.Borrego@Sun.COM  * to underscores ('_').  The list of invalid characters includes
22248474SJose.Borrego@Sun.COM  * control characters and the following:
22258474SJose.Borrego@Sun.COM  *
22268474SJose.Borrego@Sun.COM  *	" / \ [ ] : | < > + ; , ? * =
22278474SJose.Borrego@Sun.COM  *
22288474SJose.Borrego@Sun.COM  * The caller must pass a valid path.  Leading and trailing slashes
22298474SJose.Borrego@Sun.COM  * are stripped from the path before converting invalid characters.
22308474SJose.Borrego@Sun.COM  * Resource names are restricted to SA_MAX_RESOURCE_NAME characters.
22315331Samw  */
22325331Samw void
sa_fix_resource_name(char * path)22335331Samw sa_fix_resource_name(char *path)
22345331Samw {
22358474SJose.Borrego@Sun.COM 	char *invalid = "\"/\\[]:|<>+;,?*=";
22368474SJose.Borrego@Sun.COM 	char *p = path;
22378474SJose.Borrego@Sun.COM 	char *q;
22385331Samw 	size_t len;
22395331Samw 
22405331Samw 	assert(path != NULL);
22415331Samw 
22428474SJose.Borrego@Sun.COM 	/*
22438474SJose.Borrego@Sun.COM 	 * Strip leading and trailing /'s.
22448474SJose.Borrego@Sun.COM 	 */
22458474SJose.Borrego@Sun.COM 	p += strspn(p, "/");
22468474SJose.Borrego@Sun.COM 	q = strchr(p, '\0');
22478474SJose.Borrego@Sun.COM 	if (q != NULL && q != path) {
22488474SJose.Borrego@Sun.COM 		while ((--q, *q == '/'))
22498474SJose.Borrego@Sun.COM 			*q = '\0';
22505331Samw 	}
22518474SJose.Borrego@Sun.COM 
22528474SJose.Borrego@Sun.COM 	if (*p == '\0') {
22538474SJose.Borrego@Sun.COM 		(void) strcpy(path, "_");
22548474SJose.Borrego@Sun.COM 		return;
22555331Samw 	}
22565331Samw 
22575331Samw 	/*
22588474SJose.Borrego@Sun.COM 	 * Stride over path components until the remaining
22598474SJose.Borrego@Sun.COM 	 * path is no longer than SA_MAX_RESOURCE_NAME.
22605331Samw 	 */
22618474SJose.Borrego@Sun.COM 	q = p;
22628474SJose.Borrego@Sun.COM 	while ((q != NULL) && (strlen(q) > SA_MAX_RESOURCE_NAME)) {
22638474SJose.Borrego@Sun.COM 		if ((q = strchr(q, '/')) != NULL) {
22648474SJose.Borrego@Sun.COM 			++q;
22658474SJose.Borrego@Sun.COM 			p = q;
22665331Samw 		}
22678474SJose.Borrego@Sun.COM 	}
22688474SJose.Borrego@Sun.COM 
22698474SJose.Borrego@Sun.COM 	/*
22708474SJose.Borrego@Sun.COM 	 * If the path is still longer than SA_MAX_RESOURCE_NAME,
22718474SJose.Borrego@Sun.COM 	 * take the trailing SA_MAX_RESOURCE_NAME characters.
22728474SJose.Borrego@Sun.COM 	 */
22738474SJose.Borrego@Sun.COM 	if ((len = strlen(p)) > SA_MAX_RESOURCE_NAME) {
22748474SJose.Borrego@Sun.COM 		len = SA_MAX_RESOURCE_NAME;
22758474SJose.Borrego@Sun.COM 		p = strchr(p, '\0') - (SA_MAX_RESOURCE_NAME - 1);
22768474SJose.Borrego@Sun.COM 	}
22778474SJose.Borrego@Sun.COM 
22788474SJose.Borrego@Sun.COM 	(void) memmove(path, p, len);
22798474SJose.Borrego@Sun.COM 	path[len] = '\0';
22808474SJose.Borrego@Sun.COM 
22818474SJose.Borrego@Sun.COM 	for (p = path; *p != '\0'; ++p) {
22828474SJose.Borrego@Sun.COM 		if ((iscntrl(*p)) || strchr(invalid, *p))
22838474SJose.Borrego@Sun.COM 			*p = '_';
22845331Samw 	}
22855331Samw }
2286