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 /* Copyright 2016 Nexenta Systems, Inc. All rights reserved. */
41
42 #include <syslog.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <strings.h>
47 #include <cstack.h>
48 #include <ctype.h>
49 #include <tlm.h>
50 #include "tlm_proto.h"
51
52 /*
53 * Implementation of a list based stack class. The stack only holds
54 * pointers/references to application objects. The objects are not
55 * copied and the stack never attempts to dereference or access the
56 * data objects. Applications should treat cstack_t references as
57 * opaque handles.
58 */
59
60 /*
61 * cstack_new
62 *
63 * Allocate and initialize a new stack, which is just an empty cstack_t.
64 * A pointer to the new stack is returned. This should be treated as an
65 * opaque handle by the caller.
66 */
67 cstack_t *
68 cstack_new(void)
69 {
70 cstack_t *stk;
71
72 if ((stk = ndmp_malloc(sizeof (cstack_t))) == NULL)
73 return (NULL);
74
75 return (stk);
76 }
77
78
79 /*
80 * cstack_delete
81 *
82 * Deallocate the stack. This goes through the list freeing all of the
83 * cstack nodes but not the data because we don't know how the data was
84 * allocated. A stack really should be empty before it is deleted.
85 */
86 void
87 cstack_delete(cstack_t *stk)
88 {
89 cstack_t *tmp;
90
91 if (stk == NULL) {
92 return;
93 }
94
95 while ((tmp = stk->next) != NULL) {
96 stk->next = tmp->next;
97 free(tmp);
98 }
99
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
115 cstack_push(cstack_t *stk, void *data, int len)
116 {
117 cstack_t *stk_node;
118
119 if (stk == NULL) {
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 return (0);
132 }
133
134
135 /*
136 * cstack_pop
137 *
138 * Pop an element off the stack. Set up the data and len references for
139 * the caller, advance the stack head and free the popped stack node.
140 *
141 * Returns 0 on success. Otherwise returns -1 to indicate underflow.
142 */
143 int
144 cstack_pop(cstack_t *stk, void **data, int *len)
145 {
146 cstack_t *stk_node;
147
148 if (stk == NULL) {
149 return (-1);
150 }
151
152 if ((stk_node = stk->next) == NULL) {
153 return (-1);
154 }
155
156 if (data)
157 *data = stk_node->data;
158
159 if (len)
160 *len = stk_node->len;
161
162 stk->next = stk_node->next;
163
164 free(stk_node);
165 return (0);
166 }
167
168 /*
169 * cstack_top
170 *
171 * Returns the top data element on the stack without removing it.
172 *
173 * Returns 0 on success. Otherwise returns -1 to indicate underflow.
174 */
175 int
176 cstack_top(cstack_t *stk, void **data, int *len)
177 {
178 if (stk == NULL) {
179 return (-1);
180 }
181
182 if (stk->next == NULL) {
183 return (-1);
184 }
185
186 if (data)
187 *data = stk->next->data;
188
189 if (len)
190 *len = stk->next->len;
191
192 return (0);
193 }
194
195 /*
196 * match
197 *
198 * Matching rules:
199 * c Any non-special character matches itslef
200 * ? Match any character
201 * ab character 'a' followed by character 'b'
202 * S Any string of non-special characters
203 * AB String 'A' followed by string 'B'
204 * * Any String, including the empty string
205 */
206 boolean_t
207 match(char *patn, char *str)
208 {
209 for (; ; ) {
210 switch (*patn) {
211 case 0:
212 return (*str == 0);
213
214 case '?':
215 if (*str != 0) {
216 str++;
217 patn++;
218 continue;
219 }
220 return (FALSE);
221
222 case '*':
223 patn++;
224 if (*patn == 0)
225 return (TRUE);
226
227 while (*str) {
228 if (match(patn, str))
229 return (TRUE);
230 str++;
231 }
232 return (FALSE);
233
234 default:
235 if (*str != *patn)
236 return (FALSE);
237 str++;
238 patn++;
239 continue;
240 }
241 }
242 }
243
244 /*
245 * Match recursive call
246 */
247 int
248 match_ci(char *patn, char *str)
249 {
250 /*
251 * "<" is a special pattern that matches only those names
252 * that do NOT have an extension. "." and ".." are ok.
253 */
254 if (strcmp(patn, "<") == 0) {
255 if ((strcmp(str, ".") == 0) || (strcmp(str, "..") == 0))
256 return (TRUE);
257 if (strchr(str, '.') == 0)
258 return (TRUE);
259 return (FALSE);
260 }
261 for (; ; ) {
262 switch (*patn) {
263 case 0:
264 return (*str == 0);
265
266 case '?':
267 if (*str != 0) {
268 str++;
269 patn++;
270 continue;
271 }
272 return (FALSE);
273
274 case '*':
275 patn++;
276 if (*patn == 0)
277 return (TRUE);
278
279 while (*str) {
280 if (match_ci(patn, str))
281 return (TRUE);
282 str++;
283 }
284 return (FALSE);
285
286 default:
287 if (*str != *patn) {
288 int c1 = *str;
289 int c2 = *patn;
290
291 c1 = tolower(c1);
292 c2 = tolower(c2);
293 if (c1 != c2)
294 return (FALSE);
295 }
296 str++;
297 patn++;
298 continue;
299 }
300 }
301 /* NOT REACHED */
302 }
303
304 /*
305 * Linear matching against a list utility function
306 */
307 static boolean_t
308 parse_match(char line, char *seps)
309 {
310 char *sep = seps;
311
312 while (*sep != 0) {
313 /* compare this char with the seperator list */
314 if (*sep == line)
315 return (TRUE);
316 sep++;
317 }
318 return (FALSE);
319 }
320
321 /*
322 * Returns the next entry of the list after
323 * each separator
324 */
325 char *
326 parse(char **line, char *seps)
327 {
328 char *start = *line;
329
330 while (**line != 0) {
331 *line = *line + 1;
332 if (parse_match(**line, seps)) {
333 /* hit a terminator, skip trailing terminators */
334 while (parse_match(**line, seps)) {
335 **line = 0;
336 *line = *line + 1;
337 }
338 break;
339 }
340 }
341 return (start);
342 }
343
344 /*
345 * oct_atoi
346 *
347 * Convert an octal string to integer
348 */
349 int
350 oct_atoi(char *p)
351 {
352 int v = 0;
353 int c;
354
355 while (*p == ' ')
356 p++;
357
358 while ('0' <= (c = *p++) && c <= '7') {
359 v <<= 3;
360 v += c - '0';
361 }
362
363 return (v);
364 }
365
366 /*
367 * strupr
368 *
369 * Convert a string to uppercase using the appropriate codepage. The
370 * string is converted in place. A pointer to the string is returned.
371 * There is an assumption here that uppercase and lowercase values
372 * always result encode to the same length.
373 */
374 char *
375 strupr(char *s)
376 {
377 char c;
378 unsigned char *p = (unsigned char *)s;
379
380 while (*p) {
381 c = toupper(*p);
382 *p++ = c;
383 }
384 return (s);
385 }
386
387 /*
388 * trim_whitespace
389 *
390 * Trim leading and trailing whitespace chars(as defined by isspace)
391 * from a buffer. Example; if the input buffer contained " text ",
392 * it will contain "text", when we return. We assume that the buffer
393 * contains a null terminated string. A pointer to the buffer is
394 * returned.
395 */
396 char *
397 trim_whitespace(char *buf)
398 {
399 char *p = buf;
400 char *q = buf;
401
402 if (buf == 0)
403 return (0);
404
405 while (*p && isspace(*p))
406 ++p;
407
408 while ((*q = *p++) != 0)
409 ++q;
410
411 if (q != buf) {
412 while ((--q, isspace(*q)) != 0)
413 *q = '\0';
414 }
415
416 return (buf);
417 }
418
419 /*
420 * trim_name
421 *
422 * Trims the slash and dot slash from the beginning of the
423 * path name.
424 */
425 char *
426 trim_name(char *nm)
427 {
428 while (*nm) {
429 if (*nm == '/') {
430 nm++;
431 continue;
432 }
433 if (*nm == '.' && nm[1] == '/' && nm[2]) {
434 nm += 2;
435 continue;
436 }
437 break;
438 }
439 return (nm);
440 }
441
442 /*
443 * get_volname
444 *
445 * Extract the volume name from the path
446 */
447 char *
448 get_volname(char *path)
449 {
450 char *cp, *save;
451 int sp;
452
453 if (!path)
454 return (NULL);
455
456 if (!(save = strdup(path)))
457 return (NULL);
458
459 sp = strspn(path, "/");
460 if (*(path + sp) == '\0') {
461 free(save);
462 return (NULL);
463 }
464
465 if ((cp = strchr(save + sp, '/')))
466 *cp = '\0';
467
468 return (save);
469 }
470
471 /*
472 * fs_volexist
473 *
474 * Check if the volume exists
475 */
476 boolean_t
477 fs_volexist(char *path)
478 {
479 struct stat64 st;
480 char *p;
481
482 if ((p = get_volname(path)) == NULL)
483 return (FALSE);
484
485 if (stat64(p, &st) != 0) {
486 free(p);
487 return (FALSE);
488 }
489
490 free(p);
491 return (TRUE);
492 }
493
494 /*
495 * tlm_tarhdr_size
496 *
497 * Returns the size of the TLM_TAR_HDR structure.
498 */
499 int
500 tlm_tarhdr_size(void)
501 {
502 return (sizeof (tlm_tar_hdr_t));
503 }
504
505 /*
506 * dup_dir_info
507 *
508 * Make and return a copy of the directory info.
509 */
510 struct full_dir_info *
511 dup_dir_info(struct full_dir_info *old_dir_info)
512 {
513 struct full_dir_info *new_dir_info;
514 new_dir_info = ndmp_malloc(sizeof (struct full_dir_info));
515
516 if (new_dir_info) {
517 bcopy(old_dir_info, new_dir_info,
518 sizeof (struct full_dir_info));
519 }
520 return (new_dir_info);
521 }
522
523 /*
524 * tlm_new_dir_info
525 *
526 * Create a new structure, set fh field to what is specified and the path
527 * to the concatenation of directory and the component
528 */
529 struct full_dir_info *
530 tlm_new_dir_info(struct fs_fhandle *fhp, char *dir, char *nm)
531 {
532 struct full_dir_info *fdip;
533
534 if (!(fdip = ndmp_malloc(sizeof (struct full_dir_info))))
535 return (NULL);
536
537 (void) memcpy(&fdip->fd_dir_fh, fhp, sizeof (fs_fhandle_t));
538 if (!tlm_cat_path(fdip->fd_dir_name, dir, nm)) {
539 free(fdip);
540 syslog(LOG_DEBUG, "TAPE BACKUP Find> path too long [%s][%s]",
541 dir, nm);
542 return (NULL);
543 }
544 return (fdip);
545 }
546
547 /*
548 * sysattr_rdonly
549 *
550 * Check if the attribute file is one of the readonly system
551 * attributes.
552 */
553 int
554 sysattr_rdonly(char *name)
555 {
556 return (name && strcmp(name, SYSATTR_RDONLY) == 0);
557 }
558
559 /*
560 * sysattr_rw
561 *
562 * Check if the attribute file is one of the read/write system
563 * attributes.
564 */
565 int
566 sysattr_rw(char *name)
567 {
568 return (name && strcmp(name, SYSATTR_RW) == 0);
569 }