xref: /illumos-gate/usr/src/lib/libpkg/common/isdir.c (revision bbf215553c7233fbab8a0afdf1fac74c44781867)
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
isdir(char * path)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
isfile(char * dir,char * file)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
iscpio(char * path,int * iscomp)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
isPathRemote(char * a_path)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
isFdRemote(int a_fd)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
isFstypeRemote(char * a_fstype)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
_InitRemoteFstypes(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(5):
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 }
391