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
isdir(char * path)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
isfile(char * dir,char * file)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
iscpio(char * path,int * iscomp)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
isPathRemote(char * a_path)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
isFdRemote(int a_fd)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
isFstypeRemote(char * a_fstype)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
_InitRemoteFstypes(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 }
392