view usr/src/cmd/ndmpd/tlm/tlm_util.c @ 13622:e5889df1eaac

2077 lots of unreachable breaks in illumos gate Reviewed by: Dan McDonald <danmcd@nexenta.com> Reviewed by: Garrett D'Amore <garrett@damore.org> Approved by: Richard Lowe <richlowe@richlowe.net>
author Milan Jurik <milan.jurik@xylab.cz>
date Sat, 18 Feb 2012 19:52:02 +0100
parents 79dfd3e11c19
children
line wrap: on
line source

/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 * Copyright 2012 Milan Jurik. All rights reserved.
 */

/*
 * BSD 3 Clause License
 *
 * Copyright (c) 2007, The Storage Networking Industry Association.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 	- Redistributions of source code must retain the above copyright
 *	  notice, this list of conditions and the following disclaimer.
 *
 * 	- Redistributions in binary form must reproduce the above copyright
 *	  notice, this list of conditions and the following disclaimer in
 *	  the documentation and/or other materials provided with the
 *	  distribution.
 *
 *	- Neither the name of The Storage Networking Industry Association (SNIA)
 *	  nor the names of its contributors may be used to endorse or promote
 *	  products derived from this software without specific prior written
 *	  permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <cstack.h>
#include <ctype.h>
#include <tlm.h>
#include "tlm_proto.h"

/*
 * Implementation of a list based stack class. The stack only holds
 * pointers/references to application objects. The objects are not
 * copied and the stack never attempts to dereference or access the
 * data objects. Applications should treat cstack_t references as
 * opaque handles.
 */

/*
 * cstack_new
 *
 * Allocate and initialize a new stack, which is just an empty cstack_t.
 * A pointer to the new stack is returned. This should be treated as an
 * opaque handle by the caller.
 */
cstack_t *
cstack_new(void)
{
	cstack_t *stk;

	if ((stk = ndmp_malloc(sizeof (cstack_t))) == NULL)
		return (NULL);

	return (stk);
}


/*
 * cstack_delete
 *
 * Deallocate the stack. This goes through the list freeing all of the
 * cstack nodes but not the data because we don't know how the data was
 * allocated. A stack really should be empty before it is deleted.
 */
void
cstack_delete(cstack_t *stk)
{
	cstack_t *tmp;

	if (stk == NULL) {
		NDMP_LOG(LOG_DEBUG, "cstack_delete: invalid stack");
		return;
	}

	while ((tmp = stk->next) != NULL) {
		stk->next = tmp->next;
		NDMP_LOG(LOG_DEBUG, "cstack_delete(element): 0x%p", tmp);
		free(tmp);
	}

	NDMP_LOG(LOG_DEBUG, "cstack_delete: 0x%p", stk);
	free(stk);
}


/*
 * cstack_push
 *
 * Push an element onto the stack. Allocate a new node and assign the
 * data and len values. We don't care what about the real values of
 * data or len and we never try to access them. The stack head will
 * point to the new node.
 *
 * Returns 0 on success. Otherwise returns -1 to indicate overflow.
 */
int
cstack_push(cstack_t *stk, void *data, int len)
{
	cstack_t *stk_node;

	if (stk == NULL) {
		NDMP_LOG(LOG_DEBUG, "cstack_push: invalid stack");
		return (-1);
	}

	if ((stk_node = ndmp_malloc(sizeof (cstack_t))) == NULL)
		return (-1);

	stk_node->data = data;
	stk_node->len = len;
	stk_node->next = stk->next;
	stk->next = stk_node;

	NDMP_LOG(LOG_DEBUG, "cstack_push(0x%p): 0x%p", stk, stk_node);
	return (0);
}


/*
 * cstack_pop
 *
 * Pop an element off the stack. Set up the data and len references for
 * the caller, advance the stack head and free the popped stack node.
 *
 * Returns 0 on success. Otherwise returns -1 to indicate underflow.
 */
int
cstack_pop(cstack_t *stk, void **data, int *len)
{
	cstack_t *stk_node;

	if (stk == NULL) {
		NDMP_LOG(LOG_DEBUG, "cstack_pop: invalid stack");
		return (-1);
	}

	if ((stk_node = stk->next) == NULL) {
		NDMP_LOG(LOG_DEBUG, "cstack_pop: underflow");
		return (-1);
	}

	if (data)
		*data = stk_node->data;

	if (len)
		*len = stk_node->len;

	stk->next = stk_node->next;
	NDMP_LOG(LOG_DEBUG, "cstack_pop(0x%p): 0x%p", stk, stk_node);

	free(stk_node);
	return (0);
}

/*
 * cstack_top
 *
 * Returns the top data element on the stack without removing it.
 *
 * Returns 0 on success. Otherwise returns -1 to indicate underflow.
 */
int
cstack_top(cstack_t *stk, void **data, int *len)
{
	if (stk == NULL) {
		NDMP_LOG(LOG_DEBUG, "cstack_pop: invalid stack");
		return (-1);
	}

	if (stk->next == NULL) {
		NDMP_LOG(LOG_DEBUG, "cstack_pop: underflow");
		return (-1);
	}

	if (data)
		*data = stk->next->data;

	if (len)
		*len = stk->next->len;

	return (0);
}

/*
 * match
 *
 * Matching rules:
 *	c	Any non-special character matches itslef
 *	?	Match any character
 *	ab	character 'a' followed by character 'b'
 *	S	Any string of non-special characters
 *	AB	String 'A' followed by string 'B'
 *	*	Any String, including the empty string
 */
boolean_t
match(char *patn, char *str)
{
	for (; ; ) {
		switch (*patn) {
		case 0:
			return (*str == 0);

		case '?':
			if (*str != 0) {
				str++;
				patn++;
				continue;
			}
			return (FALSE);

		case '*':
			patn++;
			if (*patn == 0)
				return (TRUE);

			while (*str) {
				if (match(patn, str))
					return (TRUE);
				str++;
			}
			return (FALSE);

		default:
			if (*str != *patn)
				return (FALSE);
			str++;
			patn++;
			continue;
		}
	}
}

/*
 * Match recursive call
 */
int
match_ci(char *patn, char *str)
{
	/*
	 * "<" is a special pattern that matches only those names
	 * that do NOT have an extension. "." and ".." are ok.
	 */
	if (strcmp(patn, "<") == 0) {
		if ((strcmp(str, ".") == 0) || (strcmp(str, "..") == 0))
			return (TRUE);
		if (strchr(str, '.') == 0)
			return (TRUE);
		return (FALSE);
	}
	for (; ; ) {
		switch (*patn) {
		case 0:
			return (*str == 0);

		case '?':
			if (*str != 0) {
				str++;
				patn++;
				continue;
			}
			return (FALSE);

		case '*':
			patn++;
			if (*patn == 0)
				return (TRUE);

			while (*str) {
				if (match_ci(patn, str))
					return (TRUE);
				str++;
			}
			return (FALSE);

		default:
			if (*str != *patn) {
				int	c1 = *str;
				int	c2 = *patn;

				c1 = tolower(c1);
				c2 = tolower(c2);
				if (c1 != c2)
					return (FALSE);
			}
			str++;
			patn++;
			continue;
		}
	}
	/* NOT REACHED */
}

/*
 * Linear matching against a list utility function
 */
static boolean_t
parse_match(char line, char *seps)
{
	char *sep = seps;

	while (*sep != 0) {
		/* compare this char with the seperator list */
		if (*sep == line)
			return (TRUE);
		sep++;
	}
	return (FALSE);
}

/*
 * Returns the next entry of the list after
 * each separator
 */
char *
parse(char **line, char *seps)
{
	char *start = *line;

	while (**line != 0) {
		*line = *line + 1;
		if (parse_match(**line, seps)) {
			/* hit a terminator, skip trailing terminators */
			while (parse_match(**line, seps)) {
				**line = 0;
				*line = *line + 1;
			}
			break;
		}
	}
	return (start);
}

/*
 * oct_atoi
 *
 * Convert an octal string to integer
 */
int
oct_atoi(char *p)
{
	int v = 0;
	int c;

	while (*p == ' ')
		p++;

	while ('0' <= (c = *p++) && c <= '7') {
		v <<= 3;
		v += c - '0';
	}

	return (v);
}

/*
 * strupr
 *
 * Convert a string to uppercase using the appropriate codepage. The
 * string is converted in place. A pointer to the string is returned.
 * There is an assumption here that uppercase and lowercase values
 * always result encode to the same length.
 */
char *
strupr(char *s)
{
	char c;
	unsigned char *p = (unsigned char *)s;

	while (*p) {
		c = toupper(*p);
		*p++ = c;
	}
	return (s);
}

/*
 * trim_whitespace
 *
 * Trim leading and trailing whitespace chars(as defined by isspace)
 * from a buffer. Example; if the input buffer contained "  text  ",
 * it will contain "text", when we return. We assume that the buffer
 * contains a null terminated string. A pointer to the buffer is
 * returned.
 */
char *
trim_whitespace(char *buf)
{
	char *p = buf;
	char *q = buf;

	if (buf == 0)
		return (0);

	while (*p && isspace(*p))
		++p;

	while ((*q = *p++) != 0)
		++q;

	if (q != buf) {
		while ((--q, isspace(*q)) != 0)
			*q = '\0';
	}

	return (buf);
}

/*
 * trim_name
 *
 * Trims the slash and dot slash from the beginning of the
 * path name.
 */
char *
trim_name(char *nm)
{
	while (*nm) {
		if (*nm == '/') {
			nm++;
			continue;
		}
		if (*nm == '.' && nm[1] == '/' && nm[2]) {
			nm += 2;
			continue;
		}
		break;
	}
	return (nm);
}

/*
 * get_volname
 *
 * Extract the volume name from the path
 */
char *
get_volname(char *path)
{
	char *cp, *save;
	int sp;

	if (!path)
		return (NULL);

	if (!(save = strdup(path)))
		return (NULL);

	sp = strspn(path, "/");
	if (*(path + sp) == '\0') {
		free(save);
		return (NULL);
	}

	if ((cp = strchr(save + sp, '/')))
		*cp = '\0';

	return (save);
}

/*
 * fs_volexist
 *
 * Check if the volume exists
 */
boolean_t
fs_volexist(char *path)
{
	struct stat64 st;
	char *p;

	if ((p = get_volname(path)) == NULL)
		return (FALSE);

	if (stat64(p, &st) != 0) {
		free(p);
		return (FALSE);
	}

	free(p);
	return (TRUE);
}

/*
 * tlm_tarhdr_size
 *
 * Returns the size of the TLM_TAR_HDR structure.
 */
int
tlm_tarhdr_size(void)
{
	return (sizeof (tlm_tar_hdr_t));
}

/*
 * dup_dir_info
 *
 * Make and return a copy of the directory info.
 */
struct full_dir_info *
dup_dir_info(struct full_dir_info *old_dir_info)
{
	struct	full_dir_info *new_dir_info;
	new_dir_info = ndmp_malloc(sizeof (struct full_dir_info));

	if (new_dir_info) {
		bcopy(old_dir_info, new_dir_info,
		    sizeof (struct full_dir_info));
	}
	return (new_dir_info);
}

/*
 * tlm_new_dir_info
 *
 * Create a new structure, set fh field to what is specified and the path
 * to the concatenation of directory and the component
 */
struct full_dir_info *
tlm_new_dir_info(struct  fs_fhandle *fhp, char *dir, char *nm)
{
	struct full_dir_info *fdip;

	if (!(fdip = ndmp_malloc(sizeof (struct full_dir_info))))
		return (NULL);

	(void) memcpy(&fdip->fd_dir_fh, fhp, sizeof (fs_fhandle_t));
	if (!tlm_cat_path(fdip->fd_dir_name, dir, nm)) {
		free(fdip);
		NDMP_LOG(LOG_DEBUG, "TAPE BACKUP Find> path too long [%s][%s]",
		    dir, nm);
		return (NULL);
	}
	return (fdip);
}

/*
 * sysattr_rdonly
 *
 * Check if the attribute file is one of the readonly system
 * attributes.
 */
int
sysattr_rdonly(char *name)
{
	return (name && strcmp(name, SYSATTR_RDONLY) == 0);
}

/*
 * sysattr_rw
 *
 * Check if the attribute file is one of the read/write system
 * attributes.
 */
int
sysattr_rw(char *name)
{
	return (name && strcmp(name, SYSATTR_RW) == 0);
}