/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <locale.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <dirent.h>
#include <limits.h>
#include <thread.h>
#include <sys/systeminfo.h>
#include <rpcsvc/nfs_prot.h>
#include <rpcsvc/daemon_utils.h>
#include <assert.h>
#include "automount.h"
#include <deflt.h>
#include <zone.h>
#include <priv.h>
#include <fcntl.h>
#include <libshare.h>
#include <libscf.h>
#include "smfcfg.h"
static char *check_hier(char *);
/*
* If the system is labeled then we need to
* have a uniquely-named auto_home map for each zone.
* The maps are made unique by appending the zonename.
* The home directory is made unique by prepending /zone/<zonename>
* for each zone that is dominated by the current zone.
* The current zone's home directory mount point is not changed.
*
* For each auto_home_<zonename> a default template map is created
* only if it doesn't exist yet. The default entry is used to declare
* local home directories created within each zone. For example:
*
* +auto_home_public
*/
static void
{
int i;
if (!priv_ineffect(PRIV_SYS_MOUNT))
return;
return;
}
if (nzents == 0)
return;
return;
}
if (nzents != nzents_saved) {
/* list changed, try again */
goto again;
}
for (i = 0; i < nzents; i++) {
int fd;
/* for current zone, leave mntpnt alone */
(void) snprintf(prepended_mntpnt,
sizeof (prepended_mntpnt),
continue;
} else {
zoneroot[0] = '\0';
}
stkptr);
/*
* Next create auto_home_<zone> maps for each zone
*/
"/etc/%s", appended_map);
/*
* If the map file doesn't exist create a template
*/
int len;
}
}
}
}
void
char ***stkptr)
{
char *p;
nodirect_map = TRUE;
goto enter;
}
if (*p == '/')
*p = '\0'; /* trim trailing / */
if (*mntpnt != '/') {
return;
}
if (p = check_hier(mntpnt)) {
pr_msg("hierarchical mountpoint: %s and %s",
p, mntpnt);
return;
}
/*
* If it's a direct map then call dirinit
* for every map entry.
*/
return;
}
/*
* Home directories are polyinstantiated on
* labeled systems.
*/
if (is_system_labeled() &&
return;
}
goto alloc_failed;
goto alloc_failed;
goto alloc_failed;
goto alloc_failed;
dir->dir_remount = 0;
/*
* Append to dir chain
*/
else
return;
}
pr_msg("dirinit: memory allocation failed");
}
/*
* Check whether the mount point is a
* subdirectory or a parent directory
* of any previously mounted automount
* mount point.
*/
static char *
char *mntpnt;
{
register char *p, *q;
q = mntpnt;
for (; *p == *q; p++, q++)
if (*p == '\0')
break;
if (*p == '/' && *q == '\0')
if (*p == '\0' && *q == '/')
if (*p == '\0' && *q == '\0')
return (NULL);
}
return (NULL); /* it's not a subdir or parent */
}
/*
* Gets the next token from the string "p" and copies it into "w". The "wq" is
* a quote vector for "w" and is derived from "pq", which is a quote vector for
* "p". Delim is the character to be used as a delimiter for the scan. A space
* means "whitespace". The call to getword must provide buffers w and wq of size
* at least wordsz. getword() will pass strings of maximum length (wordsz-1),
* since it needs to null terminate the string.
* Returns 0 on ok and -1 on error.
*/
int
{
char *tmp = w;
if (wordsz <= 0) {
if (verbose)
"getword: input word size %d must be > 0", wordsz);
return (-1);
}
(*p)++, (*pq)++;
while (**p &&
**pq == ' ')) {
if (--count <= 0) {
*tmp = '\0';
*tmpq = '\0';
"maximum word length (%d) exceeded", wordsz);
return (-1);
}
*w++ = *(*p)++;
}
*w = '\0';
*wq = '\0';
return (0);
}
/*
* get_line attempts to get a line from the map, upto LINESZ. A line in
* the map is a concatenation of lines if the continuation symbol '\'
* is used at the end of the line. Returns line on success, a NULL on
* EOF, and an empty string on lines > linesz.
*/
char *
{
register char *p = line;
register int len;
int excess = 0;
*p = '\0';
for (;;) {
}
if (len <= 0) {
p = line;
continue;
}
/*
* Is input line too long?
*/
if (*p != '\n') {
excess = 1;
/*
* Perhaps last char read was '\'. Reinsert it
* into the stream to ease the parsing when we
* read the rest of the line to discard.
*/
break;
}
trim:
/* trim trailing white space */
*p-- = '\0';
if (p < line) { /* empty line */
p = line;
continue;
}
if (*p == '\\') { /* continuation */
*p = '\0';
continue;
}
/*
* Ignore comments. Comments start with '#'
* which must be preceded by a whitespace, unless
* if '#' is the first character in the line.
*/
p = line;
while (p = strchr(p, '#')) {
*p-- = '\0';
goto trim;
}
p++;
}
break;
}
if (excess) {
int c;
/*
* discard rest of line and return an empty string.
* done to set the stream to the correct place when
* we are done with this line.
*/
*p = c;
if (*p == '\n') /* end of the long line */
break;
else if (*p == '\\') { /* continuation */
break;
}
}
"map %s: line too long (max %d chars)",
*line = '\0';
}
return (line);
}
/*
* Gets the retry=n entry from opts.
* Returns 0 if retry=n is not present in option string,
* retry=n is invalid, or when option string is NULL.
*/
int
{
int retry = 0;
return (retry);
}
}
/*
* Returns zero if "opt" is found in mnt->mnt_opts, setting
* *sval to whatever follows the equal sign after "opt".
* str_opt allocates a string long enough to store the value of
* "opt" plus a terminating null character and returns it as *sval.
* It is the responsability of the caller to deallocate *sval.
* *sval will be equal to NULL upon return if either "opt=" is not found,
* or "opt=" has no value associated with it.
*
* stropt will return -1 on error.
*/
int
{
/*
* is "opt" in the options field?
*/
if (*str++ != '=' ||
return (-1);
}
*comma = '\0';
*comma = ',';
return (-1);
} else
return (0);
}
/*
* Performs text expansions in the string "pline".
* "plineq" is the quote vector for "pline".
* An identifier prefixed by "$" is replaced by the
* corresponding environment variable string. A "&"
* is replaced by the key string for the map entry.
*
* This routine will return an error (non-zero) if *size* would be
* exceeded after expansion, indicating that the macro_expand failed.
* This is to prevent writing past the end of pline and plineq.
* Both pline and plineq are left untouched in such error case.
*/
int
int size;
{
register char *p, *q;
register char *s;
int expand = 0;
while (*p) {
if (*p == '&' && *q == ' ') { /* insert key */
/*
* make sure we don't overflow buffer
*/
for (s = key; *s; s++) {
*bp++ = *s;
*bq++ = ' ';
}
expand++;
p++; q++;
continue;
} else {
/*
* line too long...
*/
return (1);
}
}
if (*p == '$' && *q == ' ') { /* insert env var */
p++; q++;
if (*p == '{') {
p++; q++;
while (*p && *p != '}') {
*pn++ = *p++;
q++;
}
if (*p) {
p++; q++;
}
} else {
while (*p && (*p == '_' || isalnum(*p))) {
*pn++ = *p++;
q++;
}
}
*pn = '\0';
if (!s) {
/* not found in env */
FALSE))
s = procbuf;
s = procbuf;
TRUE))
s = procbuf;
s = isaname;
s = procbuf;
}
}
if (s) {
while (*s) {
*bp++ = *s++;
*bq++ = ' ';
}
} else {
/*
* line too long...
*/
return (1);
}
}
expand++;
continue;
}
/*
* Since buffp needs to be null terminated, we need to
* check that there's still room in the buffer to
* place at least two more characters, *p and the
* terminating null.
*/
/*
* There was not enough room for at least two more
* characters, return with an error.
*/
return (1);
}
/*
* The total number of characters so far better be less
* than the size of buffer passed in.
*/
*bp++ = *p++;
*bq++ = *q++;
}
if (!expand)
return (0);
*bp = '\0';
*bq = '\0';
/*
* processed at most size characters.
*/
return (0);
}
/*
* Removes backslashes, quotes and brackets from the string "str"
* and returns the quoting information in "qbuf". Character is
* considered escaped when it is
*
* preceded with '\' e.g. \a
* within quotes e.g. "string"
* a ':' in brackets e.g. [an:ip:6::ad::d:re:s:s]
*
* original str: 'the "brown" f\ox said: [fe80::20a:e4ff:fe35:8b0d]'
* unquoted str: 'the brown fox said: [fe80::20a:e4ff:fe35:8b0d]'
* and the qbuf: ' ^^^^^ ^ ^^ ^ ^ ^ '
*/
void
{
if (!escaped) {
if (*ip == '\\') {
escaped = 1;
quoted++;
continue;
} else
if (*ip == '"') {
quoted++;
continue;
} else
if (*ip == '[') {
inbracket++;
quoted++;
} else
if (*ip == ']') {
}
}
escaped = 0;
}
*bp = '\0';
*qp = '\0';
if (quoted)
}
/*
* If str is enclosed in [brackets], trim them off.
*/
void
unbracket(s)
char **s;
{
char *b = *s + strlen(*s) - 1;
if (*b == ']')
*b = '\0';
if (**s == '[')
(*s)++;
}
/*
* Removes trailing spaces from string "s".
*/
void
trim(s)
char *s;
{
char *p = &s[strlen(s) - 1];
*p-- = '\0';
}
/*
* try to allocate memory using malloc, if malloc fails, then flush the
* rddir caches, and retry. If the second allocation after the readdir
* caches have been flushed fails too, then return NULL to indicate
* memory could not be allocated.
*/
char *
{
char *p;
int again = 0;
/*
* No memory, free rddir caches and try again
*/
} else {
again = 1;
}
}
if (again)
return (p);
}
/*
* try to strdup a string, if it fails, then flush the rddir caches,
* and retry. If the second strdup fails, return NULL to indicate failure.
*/
char *
{
char *s2;
int again = 0;
/*
* No memory, free rddir caches and try again
*/
} else {
again = 1;
}
}
if (again)
return (s2);
}
/*
* Returns a pointer to the entry corresponding to 'name' if found,
* otherwise it returns NULL.
*/
struct dir_entry *
{
register struct dir_entry *p;
register int direction;
if (direction == 0)
return (p);
if (direction > 0)
p = p->right;
else p = p->left;
}
return (NULL);
}
/*
* Add entry to binary tree
* Duplicate entries are not added
*/
void
{
register int direction;
return;
}
prev = p;
if (direction == 0) {
/*
* entry already in btree
*/
return;
}
if (direction > 0)
p = p->right;
else p = p->left;
}
if (direction > 0)
}
/*
* If entry doesn't exist already, add it to the linear list
* after '*last' and to the binary tree list.
* If '*last == NULL' then the list is walked till the end.
* *last is always set to the new element after successful completion.
* if entry already exists '*last' is only updated if not previously
* provided.
*/
int
{
struct dir_entry *e, *l;
/*
* walk the list to find last element
*/
*last = l;
}
/*
* not a duplicate, add it to list
*/
/* LINTED pointer alignment */
e = (struct dir_entry *)
auto_rddir_malloc(sizeof (struct dir_entry));
if (e == NULL)
return (ENOMEM);
(void) memset((char *)e, 0, sizeof (*e));
free(e);
return (ENOMEM);
}
/*
* list is empty
*/
} else {
/*
* append to end of list
*/
*last = e;
}
/*
* add to binary tree
*/
btree_enter(list, e);
}
return (0);
}
/*
* Print trace output.
* Like fprintf(stderr, fmt, ...) except that if "id" is nonzero, the output
* is preceeded by the ID of the calling thread.
*/
void
{
if (id) {
}
}
/*
* Extract the isalist(5) for userland from the kernel.
*/
static char *
isalist(void)
{
char *buf;
long ret;
do {
if (ret == -1l)
return (NULL);
} else
break;
return (buf);
}
/*
* Classify isa's as to bitness of the corresponding ABIs.
* isa's which have no "official" system ABI are returned
* unrecognised i.e. zero bits.
*/
static int
{
return (32);
return (64);
return (0);
}
/*
* Determine the application architecture (derived from uname -m) to expand
* the $ARCH and $KARCH macros.
*
* Like arch(1), we need to substitute "sun4" for "sun4u", "sun4v", ... for
* backward compatibility. When kflag is set (like arch -k), the unmodifed
* value is returned instead.
*/
static int
{
long ret;
if (ret == -1L)
return (0);
return (1);
}
/*
* Determine the basic ISA (uname -p) to expand the $CPU macro.
*/
static int
{
long ret;
if (ret == -1L)
return (0);
else
return (1);
}
/*
* Find the left-most element in the isalist that matches our idea of a
* system ABI.
*
* On machines with only one ABI, this is usually the same as uname -p.
*/
static int
{
int bits;
char *lasts;
return (0);
break; /* ignore "extension" architectures */
return (0); /* can't figure it out :( */
}
return (1);
}
/*
* Determine the platform (uname -i) to expand the $PLATFORM macro.
*/
static int
{
long ret;
if (ret == -1L)
return (0);
else
return (1);
}
/*
* Set environment variables
*/
void
put_automountd_env(void)
{
a = c = defval;
if (*a == NULL)
return;
/*
* Environment variables can have more than one value
* seperated by a comma and there can be multiple
* environment variables. * a=b\,c,d=e. For multiple
* valued environment variable, values are seperated
* with an escape character.
*/
if (*(p - 1) == '\\') {
c = p + 1;
continue;
}
*p = '\0';
a = c = p + 1;
}
if (*a != NULL) {
}
}
}