xref: /illumos-gate/usr/src/cmd/ndmpd/tlm/tlm_util.c (revision 33f5ff17)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  * Copyright 2012 Milan Jurik. All rights reserved.
5  */
6 
7 /*
8  * BSD 3 Clause License
9  *
10  * Copyright (c) 2007, The Storage Networking Industry Association.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 	- Redistributions of source code must retain the above copyright
16  *	  notice, this list of conditions and the following disclaimer.
17  *
18  * 	- Redistributions in binary form must reproduce the above copyright
19  *	  notice, this list of conditions and the following disclaimer in
20  *	  the documentation and/or other materials provided with the
21  *	  distribution.
22  *
23  *	- Neither the name of The Storage Networking Industry Association (SNIA)
24  *	  nor the names of its contributors may be used to endorse or promote
25  *	  products derived from this software without specific prior written
26  *	  permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
32  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <strings.h>
44 #include <cstack.h>
45 #include <ctype.h>
46 #include <tlm.h>
47 #include "tlm_proto.h"
48 
49 /*
50  * Implementation of a list based stack class. The stack only holds
51  * pointers/references to application objects. The objects are not
52  * copied and the stack never attempts to dereference or access the
53  * data objects. Applications should treat cstack_t references as
54  * opaque handles.
55  */
56 
57 /*
58  * cstack_new
59  *
60  * Allocate and initialize a new stack, which is just an empty cstack_t.
61  * A pointer to the new stack is returned. This should be treated as an
62  * opaque handle by the caller.
63  */
64 cstack_t *
cstack_new(void)65 cstack_new(void)
66 {
67 	cstack_t *stk;
68 
69 	if ((stk = ndmp_malloc(sizeof (cstack_t))) == NULL)
70 		return (NULL);
71 
72 	return (stk);
73 }
74 
75 
76 /*
77  * cstack_delete
78  *
79  * Deallocate the stack. This goes through the list freeing all of the
80  * cstack nodes but not the data because we don't know how the data was
81  * allocated. A stack really should be empty before it is deleted.
82  */
83 void
cstack_delete(cstack_t * stk)84 cstack_delete(cstack_t *stk)
85 {
86 	cstack_t *tmp;
87 
88 	if (stk == NULL) {
89 		NDMP_LOG(LOG_DEBUG, "cstack_delete: invalid stack");
90 		return;
91 	}
92 
93 	while ((tmp = stk->next) != NULL) {
94 		stk->next = tmp->next;
95 		NDMP_LOG(LOG_DEBUG, "cstack_delete(element): 0x%p", tmp);
96 		free(tmp);
97 	}
98 
99 	NDMP_LOG(LOG_DEBUG, "cstack_delete: 0x%p", stk);
100 	free(stk);
101 }
102 
103 
104 /*
105  * cstack_push
106  *
107  * Push an element onto the stack. Allocate a new node and assign the
108  * data and len values. We don't care what about the real values of
109  * data or len and we never try to access them. The stack head will
110  * point to the new node.
111  *
112  * Returns 0 on success. Otherwise returns -1 to indicate overflow.
113  */
114 int
cstack_push(cstack_t * stk,void * data,int len)115 cstack_push(cstack_t *stk, void *data, int len)
116 {
117 	cstack_t *stk_node;
118 
119 	if (stk == NULL) {
120 		NDMP_LOG(LOG_DEBUG, "cstack_push: invalid stack");
121 		return (-1);
122 	}
123 
124 	if ((stk_node = ndmp_malloc(sizeof (cstack_t))) == NULL)
125 		return (-1);
126 
127 	stk_node->data = data;
128 	stk_node->len = len;
129 	stk_node->next = stk->next;
130 	stk->next = stk_node;
131 
132 	NDMP_LOG(LOG_DEBUG, "cstack_push(0x%p): 0x%p", stk, stk_node);
133 	return (0);
134 }
135 
136 
137 /*
138  * cstack_pop
139  *
140  * Pop an element off the stack. Set up the data and len references for
141  * the caller, advance the stack head and free the popped stack node.
142  *
143  * Returns 0 on success. Otherwise returns -1 to indicate underflow.
144  */
145 int
cstack_pop(cstack_t * stk,void ** data,int * len)146 cstack_pop(cstack_t *stk, void **data, int *len)
147 {
148 	cstack_t *stk_node;
149 
150 	if (stk == NULL) {
151 		NDMP_LOG(LOG_DEBUG, "cstack_pop: invalid stack");
152 		return (-1);
153 	}
154 
155 	if ((stk_node = stk->next) == NULL) {
156 		NDMP_LOG(LOG_DEBUG, "cstack_pop: underflow");
157 		return (-1);
158 	}
159 
160 	if (data)
161 		*data = stk_node->data;
162 
163 	if (len)
164 		*len = stk_node->len;
165 
166 	stk->next = stk_node->next;
167 	NDMP_LOG(LOG_DEBUG, "cstack_pop(0x%p): 0x%p", stk, stk_node);
168 
169 	free(stk_node);
170 	return (0);
171 }
172 
173 /*
174  * cstack_top
175  *
176  * Returns the top data element on the stack without removing it.
177  *
178  * Returns 0 on success. Otherwise returns -1 to indicate underflow.
179  */
180 int
cstack_top(cstack_t * stk,void ** data,int * len)181 cstack_top(cstack_t *stk, void **data, int *len)
182 {
183 	if (stk == NULL) {
184 		NDMP_LOG(LOG_DEBUG, "cstack_pop: invalid stack");
185 		return (-1);
186 	}
187 
188 	if (stk->next == NULL) {
189 		NDMP_LOG(LOG_DEBUG, "cstack_pop: underflow");
190 		return (-1);
191 	}
192 
193 	if (data)
194 		*data = stk->next->data;
195 
196 	if (len)
197 		*len = stk->next->len;
198 
199 	return (0);
200 }
201 
202 /*
203  * match
204  *
205  * Matching rules:
206  *	c	Any non-special character matches itslef
207  *	?	Match any character
208  *	ab	character 'a' followed by character 'b'
209  *	S	Any string of non-special characters
210  *	AB	String 'A' followed by string 'B'
211  *	*	Any String, including the empty string
212  */
213 boolean_t
match(char * patn,char * str)214 match(char *patn, char *str)
215 {
216 	for (; ; ) {
217 		switch (*patn) {
218 		case 0:
219 			return (*str == 0);
220 
221 		case '?':
222 			if (*str != 0) {
223 				str++;
224 				patn++;
225 				continue;
226 			}
227 			return (FALSE);
228 
229 		case '*':
230 			patn++;
231 			if (*patn == 0)
232 				return (TRUE);
233 
234 			while (*str) {
235 				if (match(patn, str))
236 					return (TRUE);
237 				str++;
238 			}
239 			return (FALSE);
240 
241 		default:
242 			if (*str != *patn)
243 				return (FALSE);
244 			str++;
245 			patn++;
246 			continue;
247 		}
248 	}
249 }
250 
251 /*
252  * Match recursive call
253  */
254 int
match_ci(char * patn,char * str)255 match_ci(char *patn, char *str)
256 {
257 	/*
258 	 * "<" is a special pattern that matches only those names
259 	 * that do NOT have an extension. "." and ".." are ok.
260 	 */
261 	if (strcmp(patn, "<") == 0) {
262 		if ((strcmp(str, ".") == 0) || (strcmp(str, "..") == 0))
263 			return (TRUE);
264 		if (strchr(str, '.') == 0)
265 			return (TRUE);
266 		return (FALSE);
267 	}
268 	for (; ; ) {
269 		switch (*patn) {
270 		case 0:
271 			return (*str == 0);
272 
273 		case '?':
274 			if (*str != 0) {
275 				str++;
276 				patn++;
277 				continue;
278 			}
279 			return (FALSE);
280 
281 		case '*':
282 			patn++;
283 			if (*patn == 0)
284 				return (TRUE);
285 
286 			while (*str) {
287 				if (match_ci(patn, str))
288 					return (TRUE);
289 				str++;
290 			}
291 			return (FALSE);
292 
293 		default:
294 			if (*str != *patn) {
295 				int	c1 = *str;
296 				int	c2 = *patn;
297 
298 				c1 = tolower(c1);
299 				c2 = tolower(c2);
300 				if (c1 != c2)
301 					return (FALSE);
302 			}
303 			str++;
304 			patn++;
305 			continue;
306 		}
307 	}
308 	/* NOT REACHED */
309 }
310 
311 /*
312  * Linear matching against a list utility function
313  */
314 static boolean_t
parse_match(char line,char * seps)315 parse_match(char line, char *seps)
316 {
317 	char *sep = seps;
318 
319 	while (*sep != 0) {
320 		/* compare this char with the seperator list */
321 		if (*sep == line)
322 			return (TRUE);
323 		sep++;
324 	}
325 	return (FALSE);
326 }
327 
328 /*
329  * Returns the next entry of the list after
330  * each separator
331  */
332 char *
parse(char ** line,char * seps)333 parse(char **line, char *seps)
334 {
335 	char *start = *line;
336 
337 	while (**line != 0) {
338 		*line = *line + 1;
339 		if (parse_match(**line, seps)) {
340 			/* hit a terminator, skip trailing terminators */
341 			while (parse_match(**line, seps)) {
342 				**line = 0;
343 				*line = *line + 1;
344 			}
345 			break;
346 		}
347 	}
348 	return (start);
349 }
350 
351 /*
352  * oct_atoi
353  *
354  * Convert an octal string to integer
355  */
356 int
oct_atoi(char * p)357 oct_atoi(char *p)
358 {
359 	int v = 0;
360 	int c;
361 
362 	while (*p == ' ')
363 		p++;
364 
365 	while ('0' <= (c = *p++) && c <= '7') {
366 		v <<= 3;
367 		v += c - '0';
368 	}
369 
370 	return (v);
371 }
372 
373 /*
374  * strupr
375  *
376  * Convert a string to uppercase using the appropriate codepage. The
377  * string is converted in place. A pointer to the string is returned.
378  * There is an assumption here that uppercase and lowercase values
379  * always result encode to the same length.
380  */
381 char *
strupr(char * s)382 strupr(char *s)
383 {
384 	char c;
385 	unsigned char *p = (unsigned char *)s;
386 
387 	while (*p) {
388 		c = toupper(*p);
389 		*p++ = c;
390 	}
391 	return (s);
392 }
393 
394 /*
395  * trim_whitespace
396  *
397  * Trim leading and trailing whitespace chars(as defined by isspace)
398  * from a buffer. Example; if the input buffer contained "  text  ",
399  * it will contain "text", when we return. We assume that the buffer
400  * contains a null terminated string. A pointer to the buffer is
401  * returned.
402  */
403 char *
trim_whitespace(char * buf)404 trim_whitespace(char *buf)
405 {
406 	char *p = buf;
407 	char *q = buf;
408 
409 	if (buf == 0)
410 		return (0);
411 
412 	while (*p && isspace(*p))
413 		++p;
414 
415 	while ((*q = *p++) != 0)
416 		++q;
417 
418 	if (q != buf) {
419 		while ((--q, isspace(*q)) != 0)
420 			*q = '\0';
421 	}
422 
423 	return (buf);
424 }
425 
426 /*
427  * trim_name
428  *
429  * Trims the slash and dot slash from the beginning of the
430  * path name.
431  */
432 char *
trim_name(char * nm)433 trim_name(char *nm)
434 {
435 	while (*nm) {
436 		if (*nm == '/') {
437 			nm++;
438 			continue;
439 		}
440 		if (*nm == '.' && nm[1] == '/' && nm[2]) {
441 			nm += 2;
442 			continue;
443 		}
444 		break;
445 	}
446 	return (nm);
447 }
448 
449 /*
450  * get_volname
451  *
452  * Extract the volume name from the path
453  */
454 char *
get_volname(char * path)455 get_volname(char *path)
456 {
457 	char *cp, *save;
458 	int sp;
459 
460 	if (!path)
461 		return (NULL);
462 
463 	if (!(save = strdup(path)))
464 		return (NULL);
465 
466 	sp = strspn(path, "/");
467 	if (*(path + sp) == '\0') {
468 		free(save);
469 		return (NULL);
470 	}
471 
472 	if ((cp = strchr(save + sp, '/')))
473 		*cp = '\0';
474 
475 	return (save);
476 }
477 
478 /*
479  * fs_volexist
480  *
481  * Check if the volume exists
482  */
483 boolean_t
fs_volexist(char * path)484 fs_volexist(char *path)
485 {
486 	struct stat64 st;
487 	char *p;
488 
489 	if ((p = get_volname(path)) == NULL)
490 		return (FALSE);
491 
492 	if (stat64(p, &st) != 0) {
493 		free(p);
494 		return (FALSE);
495 	}
496 
497 	free(p);
498 	return (TRUE);
499 }
500 
501 /*
502  * tlm_tarhdr_size
503  *
504  * Returns the size of the TLM_TAR_HDR structure.
505  */
506 int
tlm_tarhdr_size(void)507 tlm_tarhdr_size(void)
508 {
509 	return (sizeof (tlm_tar_hdr_t));
510 }
511 
512 /*
513  * dup_dir_info
514  *
515  * Make and return a copy of the directory info.
516  */
517 struct full_dir_info *
dup_dir_info(struct full_dir_info * old_dir_info)518 dup_dir_info(struct full_dir_info *old_dir_info)
519 {
520 	struct	full_dir_info *new_dir_info;
521 	new_dir_info = ndmp_malloc(sizeof (struct full_dir_info));
522 
523 	if (new_dir_info) {
524 		bcopy(old_dir_info, new_dir_info,
525 		    sizeof (struct full_dir_info));
526 	}
527 	return (new_dir_info);
528 }
529 
530 /*
531  * tlm_new_dir_info
532  *
533  * Create a new structure, set fh field to what is specified and the path
534  * to the concatenation of directory and the component
535  */
536 struct full_dir_info *
tlm_new_dir_info(struct fs_fhandle * fhp,char * dir,char * nm)537 tlm_new_dir_info(struct  fs_fhandle *fhp, char *dir, char *nm)
538 {
539 	struct full_dir_info *fdip;
540 
541 	if (!(fdip = ndmp_malloc(sizeof (struct full_dir_info))))
542 		return (NULL);
543 
544 	(void) memcpy(&fdip->fd_dir_fh, fhp, sizeof (fs_fhandle_t));
545 	if (!tlm_cat_path(fdip->fd_dir_name, dir, nm)) {
546 		free(fdip);
547 		NDMP_LOG(LOG_DEBUG, "TAPE BACKUP Find> path too long [%s][%s]",
548 		    dir, nm);
549 		return (NULL);
550 	}
551 	return (fdip);
552 }
553 
554 /*
555  * sysattr_rdonly
556  *
557  * Check if the attribute file is one of the readonly system
558  * attributes.
559  */
560 int
sysattr_rdonly(char * name)561 sysattr_rdonly(char *name)
562 {
563 	return (name && strcmp(name, SYSATTR_RDONLY) == 0);
564 }
565 
566 /*
567  * sysattr_rw
568  *
569  * Check if the attribute file is one of the read/write system
570  * attributes.
571  */
572 int
sysattr_rw(char * name)573 sysattr_rw(char *name)
574 {
575 	return (name && strcmp(name, SYSATTR_RW) == 0);
576 }
577