1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  26  */
  27 
  28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  29 /* All Rights Reserved */
  30 
  31 
  32 #include <stdio.h>
  33 #include <sys/types.h>
  34 #include <sys/stat.h>
  35 #include <archives.h>
  36 #include <errno.h>
  37 #include <fcntl.h>
  38 #include <limits.h>
  39 #include <stdlib.h>
  40 #include <unistd.h>
  41 #include <string.h>
  42 #include "pkglocale.h"
  43 #include "pkglibmsgs.h"
  44 
  45 /*
  46  * Defines for cpio/compression checks.
  47  */
  48 #define BIT_MASK                0x1f
  49 #define BLOCK_MASK              0x80
  50 
  51 #define MASK_CK(x, y)   (((x) & (y)) == (y))
  52 #define ISCOMPCPIO      ((unsigned char) cm.c_mag[0] == m_h[0] && \
  53                         (unsigned char) cm.c_mag[1] == m_h[1] && \
  54                         (MASK_CK((unsigned char) cm.c_mag[2], BLOCK_MASK) || \
  55                         MASK_CK((unsigned char) cm.c_mag[2], BIT_MASK)))
  56 
  57 #define ISCPIO          (cm.b_mag != CMN_BIN && \
  58                         (strcmp(cm.c_mag, CMS_ASC) == 0) && \
  59                         (strcmp(cm.c_mag, CMS_CHR) == 0) && \
  60                         (strcmp(cm.c_mag, CMS_CRC) == 0))
  61 
  62 /* location of distributed file system types database */
  63 
  64 #define REMOTE_FS_DBFILE        "/etc/dfs/fstypes"
  65 
  66 /* character array used to hold dfs types database contents */
  67 
  68 static long             numRemoteFstypes = -1;
  69 static char             **remoteFstypes = (char **)NULL;
  70 
  71 /* forward declarations */
  72 
  73 static void _InitRemoteFstypes(void);
  74 
  75 int isFdRemote(int a_fd);
  76 int isPathRemote(char *a_path);
  77 int isFstypeRemote(char *a_fstype);
  78 int isdir(char *path);
  79 int isfile(char *dir, char *file);
  80 int iscpio(char *path, int *iscomp);
  81 
  82 /*
  83  * Name:        isdir
  84  * Description: determine if specified path exists and is a directory
  85  * Arguments:   path - pointer to string representing the path to verify
  86  * returns: 0 - directory exists
  87  *          1 - directory does not exist or is not a directory
  88  * NOTE:        errno is set appropriately
  89  */
  90 
  91 int
  92 isdir(char *path)
  93 {
  94         struct stat statbuf;
  95 
  96         /* return error if path does not exist */
  97 
  98         if (stat(path, &statbuf) != 0) {
  99                 return (1);
 100         }
 101 
 102         /* return error if path is not a directory */
 103 
 104         if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
 105                 errno = ENOTDIR;
 106                 return (1);
 107         }
 108 
 109         return (0);
 110 }
 111 
 112 /*
 113  * Name:        isfile
 114  * Description: determine if specified path exists and is a directory
 115  * Arguments:   dir - pointer to string representing the directory where
 116  *                      the file is located
 117  *                      == NULL - use "file" argument only
 118  *              file - pointer to string representing the file to verify
 119  * Returns:     0 - success - file exists
 120  *              1 - failure - file does not exist OR is not a file
 121  * NOTE:        errno is set appropriately
 122  */
 123 
 124 int
 125 isfile(char *dir, char *file)
 126 {
 127         struct stat statbuf;
 128         char    path[PATH_MAX];
 129 
 130         /* construct full path if directory specified */
 131 
 132         if (dir) {
 133                 (void) snprintf(path, sizeof (path), "%s/%s", dir, file);
 134                 file = path;
 135         }
 136 
 137         /* return error if path does not exist */
 138 
 139         if (stat(file, &statbuf) != 0) {
 140                 return (1);
 141         }
 142 
 143         /* return error if path is a directory */
 144 
 145         if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
 146                 errno = EISDIR;
 147                 return (1);
 148         }
 149 
 150         /* return error if path is not a file */
 151 
 152         if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
 153                 errno = EINVAL;
 154                 return (1);
 155         }
 156 
 157         return (0);
 158 }
 159 
 160 int
 161 iscpio(char *path, int *iscomp)
 162 {
 163         /*
 164          * Compressed File Header.
 165          */
 166         unsigned char m_h[] = { "\037\235" };           /* 1F 9D */
 167 
 168         static union {
 169                 short int       b_mag;
 170                 char            c_mag[CMS_LEN];
 171         }       cm;
 172 
 173         struct stat     statb;
 174         int             fd;
 175 
 176 
 177         *iscomp = 0;
 178 
 179         if ((fd = open(path, O_RDONLY, 0)) == -1) {
 180                 if (errno != ENOENT) {
 181                         perror("");
 182                         (void) fprintf(stderr, pkg_gt(ERR_ISCPIO_OPEN), path);
 183                 }
 184                 return (0);
 185         } else {
 186                 if (fstat(fd, &statb) == -1) {
 187                         perror("");
 188                         (void) fprintf(stderr, pkg_gt(ERR_ISCPIO_FSTAT), path);
 189                         (void) close(fd);
 190                         return (0);
 191                 } else {
 192                         if (S_ISREG(statb.st_mode)) {   /* Must be a file */
 193                                 if (read(fd, cm.c_mag, sizeof (cm.c_mag)) !=
 194                                     sizeof (cm.c_mag)) {
 195                                         perror("");
 196                                         (void) fprintf(stderr,
 197                                             pkg_gt(ERR_ISCPIO_READ), path);
 198                                         (void) close(fd);
 199                                         return (0);
 200                                 }
 201                                 /*
 202                                  * Try to determine if the file is a compressed
 203                                  * file, if that fails, try to determine if it
 204                                  * is a cpio archive, if that fails, then we
 205                                  * fail!
 206                                  */
 207                                 if (ISCOMPCPIO) {
 208                                         *iscomp = 1;
 209                                         (void) close(fd);
 210                                         return (1);
 211                                 } else if (ISCPIO) {
 212                                         (void) fprintf(stderr,
 213                                             pkg_gt(ERR_ISCPIO_NOCPIO),
 214                                             path);
 215                                         (void) close(fd);
 216                                         return (0);
 217                                 }
 218                                 (void) close(fd);
 219                                 return (1);
 220                         } else {
 221                                 (void) close(fd);
 222                                 return (0);
 223                         }
 224                 }
 225         }
 226 }
 227 
 228 /*
 229  * Name:        isPathRemote
 230  * Description: determine if a path object is local or remote
 231  * Arguments:   a_path - [RO, *RO] - (char *)
 232  *                      Pointer to string representing the path to check
 233  * Returns:     int
 234  *                      1 - the path is remote
 235  *                      0 - the path is local to this system
 236  *                      -1 - cannot determine if path is remote or local
 237  */
 238 
 239 int
 240 isPathRemote(char *a_path)
 241 {
 242         int             r;
 243         struct stat     statbuf;
 244 
 245         r = lstat(a_path, &statbuf);
 246         if (r < 0) {
 247                 return (-1);
 248         }
 249 
 250         return (isFstypeRemote(statbuf.st_fstype));
 251 }
 252 
 253 /*
 254  * Name:        isFdRemote
 255  * Description: determine if an open file is local or remote
 256  * Arguments:   a_fd - [RO, *RO] - (int)
 257  *                      Integer representing open file to check
 258  * Returns:     int
 259  *                      1 - the path is remote
 260  *                      0 - the path is local to this system
 261  *                      -1 - cannot determine if path is remote or local
 262  */
 263 
 264 int
 265 isFdRemote(int a_fd)
 266 {
 267         int             r;
 268         struct stat     statbuf;
 269 
 270         r = fstat(a_fd, &statbuf);
 271         if (r < 0) {
 272                 return (-1);
 273         }
 274 
 275         return (isFstypeRemote(statbuf.st_fstype));
 276 }
 277 
 278 /*
 279  * Name:        isFstypeRemote
 280  * Description: determine if a file system type is remote (distributed)
 281  * Arguments:   a_fstype - [RO, *RO] - (char *)
 282  *                      Pointer to string representing the file system type
 283  *                      to check
 284  * Returns:     int
 285  *                      1 - the file system type is remote
 286  *                      0 - the file system type is local to this system
 287  */
 288 
 289 int
 290 isFstypeRemote(char *a_fstype)
 291 {
 292         int     i;
 293 
 294         /* initialize the list if it is not yet initialized */
 295 
 296         _InitRemoteFstypes();
 297 
 298         /* scan the list looking for the specified type */
 299 
 300         for (i = 0; i < numRemoteFstypes; i++) {
 301                 if (strcmp(remoteFstypes[i], a_fstype) == 0) {
 302                         return (1);
 303                 }
 304         }
 305 
 306         /* type not found in remote file system type list - is not remote */
 307 
 308         return (0);
 309 }
 310 
 311 /*
 312  * Name:        _InitRemoteFstypes
 313  * Description: initialize table of remote file system type names
 314  * Arguments:   none
 315  * Returns:     none
 316  * Side Effects:
 317  *      - The global array "(char **)remoteFstypes" is set to the
 318  *        address of an array of string pointers, each of which represents
 319  *        a single remote file system type
 320  *      - The global variable "(long) numRemoteFstypes" is set to the total
 321  *        number of remote file system type strings (names) that are
 322  *        contained in the "remoteFstypes" global array.
 323  *      - numRemoteFstypes is initialized to "-1" before any attempt has been
 324  *        made to read the remote file system type name database.
 325  */
 326 static void
 327 _InitRemoteFstypes(void)
 328 {
 329         FILE    *fp;
 330         char    line_buf[LINE_MAX];
 331 
 332         /* return if already initialized */
 333 
 334         if (numRemoteFstypes > 0) {
 335                 return;
 336         }
 337 
 338         /* if list is uninitialized, start with zero */
 339 
 340         if (numRemoteFstypes == -1) {
 341                 numRemoteFstypes = 0;
 342         }
 343 
 344         /* open the remote file system type database file */
 345 
 346         if ((fp = fopen(REMOTE_FS_DBFILE, "r")) == NULL) {
 347                 /* no remote type database: use predefined remote types */
 348                 remoteFstypes = (char **)realloc(remoteFstypes,
 349                     sizeof (char *) * (numRemoteFstypes+2));
 350                 remoteFstypes[numRemoteFstypes++] = "nfs";      /* +1 */
 351                 remoteFstypes[numRemoteFstypes++] = "autofs";   /* +2 */
 352                 return;
 353         }
 354 
 355         /*
 356          * Read the remote file system type database; from fstypes(4):
 357          *
 358          * fstypes resides in directory /etc/dfs and lists distributed file
 359          * system utilities packages installed on the system. For each installed
 360          * distributed file system type, there is a line that begins with the
 361          * file system type name (for example, ``nfs''), followed by white space
 362          * and descriptive text.
 363          *
 364          * Lines will look at lot like this:
 365          *
 366          *      nfs NFS Utilities
 367          *      autofs AUTOFS Utilities
 368          */
 369 
 370         while (fgets(line_buf, sizeof (line_buf), fp) != NULL) {
 371                 char            buf[LINE_MAX];
 372                 static char     format[128] = {'\0'};
 373 
 374                 if (format[0] == '\0') {
 375                         /* create bounded format: %ns */
 376                         (void) snprintf(format, sizeof (format),
 377                             "%%%ds", sizeof (buf)-1);
 378                 }
 379 
 380                 (void) sscanf(line_buf, format, buf);
 381 
 382                 remoteFstypes = realloc(remoteFstypes,
 383                     sizeof (char *) * (numRemoteFstypes+1));
 384                 remoteFstypes[numRemoteFstypes++] = strdup(buf);
 385         }
 386 
 387         /* close database file and return */
 388 
 389         (void) fclose(fp);
 390 }