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 *
  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
  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
 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
 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
 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
 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
 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
 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 *
 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
 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 *
 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 *
 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 *
 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 *
 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
 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
 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 *
 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 *
 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
 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
 573 sysattr_rw(char *name)
 574 {
 575         return (name && strcmp(name, SYSATTR_RW) == 0);
 576 }