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 }