xref: /illumos-gate/usr/src/lib/libpkg/common/isdir.c (revision 56f33205c9ed776c3c909e07d52e94610a675740)
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 }
392