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