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 }