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 2009 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 #include "pkglib.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 int eval_ftype(char *path, char ftype, char *myftype); 82 83 /* 84 * Name: isdir 85 * Description: determine if specified path exists and is a directory 86 * Arguments: path - pointer to string representing the path to verify 87 * returns: 0 - directory exists 88 * 1 - directory does not exist or is not a directory 89 * NOTE: errno is set appropriately 90 */ 91 92 int 93 isdir(char *path) 94 { 95 struct stat statbuf; 96 97 /* return error if path does not exist */ 98 99 if (stat(path, &statbuf) != 0) { 100 return (1); 101 } 102 103 /* return error if path is not a directory */ 104 105 if ((statbuf.st_mode & S_IFMT) != S_IFDIR) { 106 errno = ENOTDIR; 107 return (1); 108 } 109 110 return (0); 111 } 112 113 /* 114 * Name: isfile 115 * Description: determine if specified path exists and is a directory 116 * Arguments: dir - pointer to string representing the directory where 117 * the file is located 118 * == NULL - use "file" argument only 119 * file - pointer to string representing the file to verify 120 * Returns: 0 - success - file exists 121 * 1 - failure - file does not exist OR is not a file 122 * NOTE: errno is set appropriately 123 */ 124 125 int 126 isfile(char *dir, char *file) 127 { 128 struct stat statbuf; 129 char path[PATH_MAX]; 130 131 /* construct full path if directory specified */ 132 133 if (dir) { 134 (void) snprintf(path, sizeof (path), "%s/%s", dir, file); 135 file = path; 136 } 137 138 /* return error if path does not exist */ 139 140 if (stat(file, &statbuf) != 0) { 141 return (1); 142 } 143 144 /* return error if path is a directory */ 145 146 if ((statbuf.st_mode & S_IFMT) == S_IFDIR) { 147 errno = EISDIR; 148 return (1); 149 } 150 151 /* return error if path is not a file */ 152 153 if ((statbuf.st_mode & S_IFMT) != S_IFREG) { 154 errno = EINVAL; 155 return (1); 156 } 157 158 return (0); 159 } 160 161 int 162 iscpio(char *path, int *iscomp) 163 { 164 /* 165 * Compressed File Header. 166 */ 167 unsigned char m_h[] = { "\037\235" }; /* 1F 9D */ 168 169 static union { 170 short int b_mag; 171 char c_mag[CMS_LEN]; 172 } cm; 173 174 struct stat statb; 175 int fd; 176 177 178 *iscomp = 0; 179 180 if ((fd = open(path, O_RDONLY, 0)) == -1) { 181 if (errno != ENOENT) { 182 perror(""); 183 (void) fprintf(stderr, pkg_gt(ERR_ISCPIO_OPEN), path); 184 } 185 return (0); 186 } else { 187 if (fstat(fd, &statb) == -1) { 188 perror(""); 189 (void) fprintf(stderr, pkg_gt(ERR_ISCPIO_FSTAT), path); 190 (void) close(fd); 191 return (0); 192 } else { 193 if (S_ISREG(statb.st_mode)) { /* Must be a file */ 194 if (read(fd, cm.c_mag, sizeof (cm.c_mag)) != 195 sizeof (cm.c_mag)) { 196 perror(""); 197 (void) fprintf(stderr, 198 pkg_gt(ERR_ISCPIO_READ), path); 199 (void) close(fd); 200 return (0); 201 } 202 /* 203 * Try to determine if the file is a compressed 204 * file, if that fails, try to determine if it 205 * is a cpio archive, if that fails, then we 206 * fail! 207 */ 208 if (ISCOMPCPIO) { 209 *iscomp = 1; 210 (void) close(fd); 211 return (1); 212 } else if (ISCPIO) { 213 (void) fprintf(stderr, 214 pkg_gt(ERR_ISCPIO_NOCPIO), 215 path); 216 (void) close(fd); 217 return (0); 218 } 219 (void) close(fd); 220 return (1); 221 } else { 222 (void) close(fd); 223 return (0); 224 } 225 } 226 } 227 } 228 229 /* 230 * Name: isPathRemote 231 * Description: determine if a path object is local or remote 232 * Arguments: a_path - [RO, *RO] - (char *) 233 * Pointer to string representing the path to check 234 * Returns: int 235 * 1 - the path is remote 236 * 0 - the path is local to this system 237 * -1 - cannot determine if path is remote or local 238 */ 239 240 int 241 isPathRemote(char *a_path) 242 { 243 int r; 244 struct stat statbuf; 245 246 r = lstat(a_path, &statbuf); 247 if (r < 0) { 248 return (-1); 249 } 250 251 return (isFstypeRemote(statbuf.st_fstype)); 252 } 253 254 /* 255 * Name: isFdRemote 256 * Description: determine if an open file is local or remote 257 * Arguments: a_fd - [RO, *RO] - (int) 258 * Integer representing open file to check 259 * Returns: int 260 * 1 - the path is remote 261 * 0 - the path is local to this system 262 * -1 - cannot determine if path is remote or local 263 */ 264 265 int 266 isFdRemote(int a_fd) 267 { 268 int r; 269 struct stat statbuf; 270 271 r = fstat(a_fd, &statbuf); 272 if (r < 0) { 273 return (-1); 274 } 275 276 return (isFstypeRemote(statbuf.st_fstype)); 277 } 278 279 /* 280 * Name: isFstypeRemote 281 * Description: determine if a file system type is remote (distributed) 282 * Arguments: a_fstype - [RO, *RO] - (char *) 283 * Pointer to string representing the file system type 284 * to check 285 * Returns: int 286 * 1 - the file system type is remote 287 * 0 - the file system type is local to this system 288 */ 289 290 int 291 isFstypeRemote(char *a_fstype) 292 { 293 int i; 294 295 /* initialize the list if it is not yet initialized */ 296 297 _InitRemoteFstypes(); 298 299 /* scan the list looking for the specified type */ 300 301 for (i = 0; i < numRemoteFstypes; i++) { 302 if (strcmp(remoteFstypes[i], a_fstype) == 0) { 303 return (1); 304 } 305 } 306 307 /* type not found in remote file system type list - is not remote */ 308 309 return (0); 310 } 311 312 /* 313 * Name: _InitRemoteFstypes 314 * Description: initialize table of remote file system type names 315 * Arguments: none 316 * Returns: none 317 * Side Effects: 318 * - The global array "(char **)remoteFstypes" is set to the 319 * address of an array of string pointers, each of which represents 320 * a single remote file system type 321 * - The global variable "(long) numRemoteFstypes" is set to the total 322 * number of remote file system type strings (names) that are 323 * contained in the "remoteFstypes" global array. 324 * - numRemoteFstypes is initialized to "-1" before any attempt has been 325 * made to read the remote file system type name database. 326 */ 327 static void 328 _InitRemoteFstypes(void) 329 { 330 FILE *fp; 331 char line_buf[LINE_MAX]; 332 333 /* return if already initialized */ 334 335 if (numRemoteFstypes > 0) { 336 return; 337 } 338 339 /* if list is uninitialized, start with zero */ 340 341 if (numRemoteFstypes == -1) { 342 numRemoteFstypes = 0; 343 } 344 345 /* open the remote file system type database file */ 346 347 if ((fp = fopen(REMOTE_FS_DBFILE, "r")) == NULL) { 348 /* no remote type database: use predefined remote types */ 349 remoteFstypes = (char **)realloc(remoteFstypes, 350 sizeof (char *) * (numRemoteFstypes+3)); 351 remoteFstypes[numRemoteFstypes++] = "nfs"; /* +1 */ 352 remoteFstypes[numRemoteFstypes++] = "autofs"; /* +2 */ 353 remoteFstypes[numRemoteFstypes++] = "cachefs"; /* +3 */ 354 return; 355 } 356 357 /* 358 * Read the remote file system type database; from fstypes(4): 359 * 360 * fstypes resides in directory /etc/dfs and lists distributed file 361 * system utilities packages installed on the system. For each installed 362 * distributed file system type, there is a line that begins with the 363 * file system type name (for example, ``nfs''), followed by white space 364 * and descriptive text. 365 * 366 * Lines will look at lot like this: 367 * 368 * nfs NFS Utilities 369 * autofs AUTOFS Utilities 370 * cachefs CACHEFS Utilities 371 */ 372 373 while (fgets(line_buf, sizeof (line_buf), fp) != NULL) { 374 char buf[LINE_MAX]; 375 static char format[128] = {'\0'}; 376 377 if (format[0] == '\0') { 378 /* create bounded format: %ns */ 379 (void) snprintf(format, sizeof (format), 380 "%%%ds", sizeof (buf)-1); 381 } 382 383 (void) sscanf(line_buf, format, buf); 384 385 remoteFstypes = realloc(remoteFstypes, 386 sizeof (char *) * (numRemoteFstypes+1)); 387 remoteFstypes[numRemoteFstypes++] = strdup(buf); 388 } 389 390 /* close database file and return */ 391 392 (void) fclose(fp); 393 } 394 395 /* 396 * Name: eval_ftype 397 * Description: Evaluate the target's file type 398 * Arguments: path - Path on filesystem 399 * ftype - Type to be changed to 400 * myftype - Address into which current 401 * type of target will be stored 402 * Returns: int 403 * 0 - Success 404 * VE_EXIST - Path does not exist 405 * VE_FTYPE - Path file type is not recognized, 406 * is not supported, 407 * or is not what is expected 408 */ 409 int 410 eval_ftype(char *path, char ftype, char *myftype) 411 { 412 struct stat status; 413 int retcode = 0; 414 int statError = 0; 415 416 /* If we are to process symlinks the old way then we follow the link */ 417 if (nonABI_symlinks()) { 418 if ((ftype == 's') ? lstat(path, &status) : 419 stat(path, &status)) { 420 (void) reperr(pkg_gt(ERR_EXIST)); 421 retcode = VE_EXIST; 422 *myftype = '?'; 423 statError++; 424 } 425 /* If not then we inspect the target of the link */ 426 } else { 427 if (lstat(path, &status) == -1) { 428 reperr(pkg_gt(ERR_EXIST)); 429 retcode = VE_EXIST; 430 *myftype = '?'; 431 statError++; 432 } 433 } 434 if (!statError) { 435 /* determining actual type of existing object */ 436 switch (status.st_mode & S_IFMT) { 437 case S_IFLNK: 438 *myftype = 's'; 439 break; 440 441 case S_IFIFO: 442 *myftype = 'p'; 443 break; 444 445 case S_IFCHR: 446 *myftype = 'c'; 447 break; 448 449 case S_IFDIR: 450 *myftype = 'd'; 451 break; 452 453 case S_IFBLK: 454 *myftype = 'b'; 455 break; 456 457 case S_IFREG: 458 case 0: 459 *myftype = 'f'; 460 break; 461 462 case S_IFDOOR: 463 *myftype = 'D'; 464 break; 465 466 default: 467 *myftype = '?'; 468 return (VE_FTYPE); 469 } 470 retcode = 0; 471 } 472 return (retcode); 473 } 474