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