libsharecore.c revision 5cb0d67909d9970a3e7adbea9422ca3fc88000bf
"# compatibility. Configuration lines could be lost.\n",
/* will be much smaller, but this handles bad syntax in the file */ /* used internally only */ * block important signals for a critical region. Arg is a pointer to * a sigset_t that is used later for the unblock. * unblock previously blocked signals from the sigs arg. * allocator function to return an zfs_sharelist_t * Look at the beginning of the current /etc/dfs/dfstab file and add * the do not modify notice if it doesn't exist. * Returns an zfs_sharelist_t list of lines from the dfstab file * pointed to by the FILE pointer dfs. Each entry is parsed and the * original line is also preserved. Used in parsing and updating the /* if no path, then comment */ }
else if (
buff[0] ==
'\n') {
/* resource and/or groupname */ /* NFS is the default if none defined */ * finddfsentry(list, path) * Look for path in the zfs_sharelist_t list and return the entry if it * remdfsentry(list, path, proto) * Remove the specified path (with protocol) from the list. This will * remove it from dfstab when the file is rewritten. /* skip comment entry but don't lose it */ /* if proto is NULL, remove all protocols */ * Remove the line specified from the list. /* skip comment entry but don't lose it */ * adddfsentry(list, share, proto) * Add an entry to the dfstab list for share (relative to proto). This * is used to update dfstab for legacy purposes. * outdfstab(dfstab, list) * Output the list to dfstab making sure the file is truncated. * Comments and errors are preserved. "share %s%s%s%s%s%s%s %s%s%s%s%s\n",
* sa_comment_line(line, err) * Add a comment to the dfstab file with err as a prefix to the * don't ignore the return since the list could have * gone to NULL if the file only had one line in it. * sa_delete_legacy(share, protocol) * Delete the specified share from the legacy config file. * Protect against shares that don't have paths. This is not * really an error at this point. * may want to only do the dfstab if * this call returns NOT IMPLEMENTED * sa_update_legacy(share, proto) * There is an assumption that dfstab will be the most common form of * legacy configuration file for shares, but not the only one. Because * of that, dfstab handling is done in the main code with calls to * this function and protocol specific calls to deal with formatting * options into dfstab/share compatible syntax. Since not everything * will be dfstab, there is a provision for calling a protocol * specific plugin interface that allows the protocol plugin to do its * own legacy files and skip the dfstab update. /* do the dfstab format */ * only update if the share is not transient -- no share type * set or the type is not "transient". * sa_is_security(optname, proto) * Check to see if optname is a security (named optionset) specific * property for the specified protocol. * add_syntax_comment(root, line, err, todfstab) * Add a comment to the document indicating a syntax error. If * todfstab is set, write it back to the dfstab file as well. * returns true if the object is of type "share". * returns true if the object is of type "resource". * _sa_remove_property(property) * remove a property only from the document. * _sa_create_dummy_share() * Create a share entry suitable for parsing but not tied to any real * config tree. Need to have a parent as well as the node to parse * on. Free using _sa_free_dummy_share(share); * Use a "zfs" tag since that will make sure nothing * really attempts to put values into the * repository. Also ZFS is currently the only user of * _sa_free_dummy_share(share) * Free the dummy share and its parent. It is an error to try and * free something that isn't a dummy. /* Real shares always have a path but a dummy doesn't */ * If there is a parent, do the free on that since * xmlFreeNode is a recursive function and free's an * sa_parse_legacy_options(group, options, proto) * In order to support legacy configurations, we allow the protocol * specific plugin to parse legacy syntax options (like those in * /etc/dfs/dfstab). This adds a new optionset to the group (or * Once the optionset has been created, we then get the derived * optionset of the parent (options from the optionset of the parent * and any parent it might have) and remove those from the created * optionset. This avoids duplication of options. * If "group" is NULL, this is just a parse without saving * anything in either SMF or ZFS. Create a dummy group to /* Since this is a dummy parse, cleanup and quit here */ * If in a group, remove the inherited options and security /* Find parent options to remove from child */ * All properties removed so remove the * optionset if it is on a share * Need to remove security here. If there are no * security options on the local group/share, don't * bother since those are the only ones that would be * prop's value only changes outside this loop * Need to get the next prop * now since we could break * the list during removal. /* remove Duplicates from this level */ * Free the data in each list entry of the list as well as freeing the * entries themselves. We need to avoid memory leaks and don't want to * dereference any NULL members. * parse_dfstab(dfstab, root) * Open and read the existing dfstab, parsing each line and adding it * to the internal configuration. Make sure syntax errors, etc are /* read the dfstab format file and fill in the doc tree */ * Comment line that we will likely skip. * If the line has the syntax: * # error: string: string * It should be preserved until manually deleted. "No share specified in dfstab: " "Unknown group used in dfstab: line %d: %s\n"),
/* Shouldn't happen unless an SMF error */ /* This is an OK add for legacy */ "Error in dfstab: line %d: %s\n"),
"Attempt to change configuration in " "dfstab: line %d: %s\n"),
"Attempt to change configuration"),
1);
* It is the same group but could have changed * options. Make sure we include the group's * properties so we don't end up moving them to * the share inadvertantly. The last arg being * true says to get the inherited properties as well * as the local properties. /* possibly different values */ * legacy_removes(group, file) * Find any shares that are "missing" from the legacy file. These * should be removed from the configuration since they are likely from * a legacy app or the admin modified the dfstab file directly. We * have to support this even if it is not the recommended way to do /* now see if the share is in the dfstab file */ /* The share was removed this way */ * Start over since the list was broken * getlegacyconfig(path, root) * Parse dfstab and build the legacy configuration. This only gets * called when a change was detected. * Walk the default shares and find anything * missing. we do this first to make sure it * is cleaned up since there may be legacy * code add/del via dfstab and we need to /* Parse the dfstab and add anything new */ * Get a linked list of all the shares on the system from * can't use due to package dependencies. * Link into the list here so we don't leak * memory on a failure from strdup(). * Caller must free the mount list * Out of memory so cleanup and leave. * in the repository. These shares are marked transient. We also need * to see if they are ZFS shares since ZFS bypasses the SMF * If this is a legacy share, mark as shared so we * only update sharetab appropriately. We also keep * the sharetab options in order to display for legacy * share with no arguments. * This share is transient so needs to be * added. Initially, this will be under * default(legacy) unless it is a ZFS * share. If zfs, we need a zfs group. /* There is a defined group */ * While this case shouldn't * occur very often, it does * occur out of a "zfs set * canmount=off. A warning * will then cause the zfs * command to abort. Since we * add it to the default list, * everything works properly * Get the transient shares from the sharetab (or other) file. since * these are transient, they only appear in the working file and not * sa_has_prop(optionset, prop) * Is the specified property a member of the optionset? * no longer used -- this is a placeholder in case we need to * sa_valid_property(handle, object, proto, property) * check to see if the specified property is valid relative to the * specified protocol. The protocol plugin is called to do the work. * Given path, return the string representing the path's file system * type. This is used to discover ZFS shares. * If we have a valid path at this point ret, return the fstype. * sa_get_derived_optionset(object, proto, hier) * Work backward to the top of the share object tree and start * copying protocol specific optionsets into a newly created * optionset that doesn't have a parent (it will be freed * later). This provides for the property inheritance model. That * is, properties closer to the share take precedence over group * level. This also provides for groups of groups in the future. /* Dont' do anything if memory wasn't allocated */ /* Found the top so working back down the stack */ /* add optionset to the newoptionset */ /* Replace the value with the new value */ * Only set if value is non NULL, old value ok /* an entirely new property */ /* While it shouldn't be linked, it doesn't hurt */ * sa_get_all_security_types(object, proto, hier) * Find all the security types set for this object. This is * preliminary to getting a derived security set. The return value is an * optionset containg properties which are the sectype values found by * walking up the XML document structure. The returned optionset * is a derived optionset. * If hier is 0, only look at object. If non-zero, walk up the tree. /* Hit the top so collect the security types working back. */ * Have a security type, check to see if * already present in optionset and add if it * sa_get_derived_security(object, sectype, proto, hier) * Get the derived security(named optionset) for the object given the * sectype and proto. If hier is non-zero, walk up the tree to get all * properties defined for this object, otherwise just those on the /* Don't do anything if memory wasn't allocated */ /* Found the top so working back down the stack. */ /* add security to the newsecurity */ /* Replace the value with the new value */ * Only set if value is non NULL, old * value ok if it is NULL. The value * must be associated with the "value" /* An entirely new property */ /* while it shouldn't be linked, it doesn't hurt */ * sharetab utility functions * sa_fillshare(share, proto, sh) * Fill the struct share with values obtained from the share object. * We only want to deal with the path level shares for the * sharetab file. If a resource, get the parent. * since the groupname is either "default" or the * group is a ZFS group, we don't want to keep * groupname. We do want it if it is any other type of len +=
3;
/* worst case */ * Get correct default prop string. NFS uses "rw", others use * Free the strings in the non-NULL members of sh. * sa_update_sharetab_ts(handle) * Update the internal timestamp of when sharetab was last * changed. This needs to be public for ZFS to get at it. * sa_update_sharetab(share, proto) * Update the sharetab file with info from the specified share. * This could be an update or add. * Fill in share structure and send it to the kernel. * We need the timestamp of the sharetab file right * after the update was done. This lets us detect a * change that made by a different process. * sa_delete_sharetab(handle, path, proto) * remove the specified share from sharetab. * Both the path and the proto are * keys into the sharetab. * sa_needs_refresh(handle) * Returns B_TRUE if the internal cache needs to be refreshed do to a * change by another process. B_FALSE returned otherwise. * If sharetab has changed, then there was an external * change. Check sharetab first since it is updated by ZFS as * well as sharemgr. This is where external ZFS changes are * If sharetab wasn't changed, check whether there were any * SMF transactions that modified the config but didn't * initiate a share. This is less common but does happen. * sa_fix_resource_name(path) * Convert invalid characters in a resource name (SMB share name) * to underscores ('_'). The list of invalid characters includes * control characters and the following: * " / \ [ ] : | < > + ; , ? * = * The caller must pass a valid path. Leading and trailing slashes * are stripped from the path before converting invalid characters. * Resource names are restricted to SA_MAX_RESOURCE_NAME characters. char *
invalid =
"\"/\\[]:|<>+;,?*=";
* Strip leading and trailing /'s. * Stride over path components until the remaining * path is no longer than SA_MAX_RESOURCE_NAME. * If the path is still longer than SA_MAX_RESOURCE_NAME, * take the trailing SA_MAX_RESOURCE_NAME characters. for (p =
path; *p !=
'\0'; ++p) {