isdir.c revision 9781:ccf49524d5dc
1343181Sdim/*
2343181Sdim * CDDL HEADER START
3353358Sdim *
4353358Sdim * The contents of this file are subject to the terms of the
5353358Sdim * Common Development and Distribution License (the "License").
6343181Sdim * You may not use this file except in compliance with the License.
7343181Sdim *
8343181Sdim * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9343181Sdim * or http://www.opensolaris.org/os/licensing.
10343181Sdim * See the License for the specific language governing permissions
11343181Sdim * and limitations under the License.
12343181Sdim *
13343181Sdim * When distributing Covered Code, include this CDDL HEADER in each
14343181Sdim * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15343181Sdim * If applicable, add the following below this CDDL HEADER, with the
16343181Sdim * fields enclosed by brackets "[]" replaced with your own identifying
17343181Sdim * information: Portions Copyright [yyyy] [name of copyright owner]
18343181Sdim *
19343181Sdim * CDDL HEADER END
20343181Sdim */
21343181Sdim
22343181Sdim/*
23343181Sdim * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24343181Sdim * Use is subject to license terms.
25343181Sdim */
26343181Sdim
27343181Sdim/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28343181Sdim/* All Rights Reserved */
29343181Sdim
30343181Sdim
31343181Sdim#include <stdio.h>
32343181Sdim#include <sys/types.h>
33343181Sdim#include <sys/stat.h>
34343181Sdim#include <archives.h>
35343181Sdim#include <errno.h>
36343181Sdim#include <fcntl.h>
37343181Sdim#include <limits.h>
38343181Sdim#include <stdlib.h>
39343181Sdim#include <unistd.h>
40343181Sdim#include <string.h>
41343181Sdim#include "pkglocale.h"
42343181Sdim#include "pkglibmsgs.h"
43343181Sdim
44343181Sdim/*
45343181Sdim * Defines for cpio/compression checks.
46343181Sdim */
47343181Sdim#define	BIT_MASK		0x1f
48343181Sdim#define	BLOCK_MASK		0x80
49343181Sdim
50343181Sdim#define	MASK_CK(x, y)	(((x) & (y)) == (y))
51343181Sdim#define	ISCOMPCPIO	((unsigned char) cm.c_mag[0] == m_h[0] && \
52343181Sdim			(unsigned char) cm.c_mag[1] == m_h[1] && \
53343181Sdim			(MASK_CK((unsigned char) cm.c_mag[2], BLOCK_MASK) || \
54343181Sdim			MASK_CK((unsigned char) cm.c_mag[2], BIT_MASK)))
55343181Sdim
56343181Sdim#define	ISCPIO		(cm.b_mag != CMN_BIN && \
57343181Sdim			(strcmp(cm.c_mag, CMS_ASC) == 0) && \
58343181Sdim			(strcmp(cm.c_mag, CMS_CHR) == 0) && \
59343181Sdim			(strcmp(cm.c_mag, CMS_CRC) == 0))
60343181Sdim
61343181Sdim/* location of distributed file system types database */
62343181Sdim
63343181Sdim#define	REMOTE_FS_DBFILE	"/etc/dfs/fstypes"
64343181Sdim
65343181Sdim/* character array used to hold dfs types database contents */
66343181Sdim
67343181Sdimstatic long		numRemoteFstypes = -1;
68343181Sdimstatic char		**remoteFstypes = (char **)NULL;
69343181Sdim
70343181Sdim/* forward declarations */
71343181Sdim
72343181Sdimstatic void _InitRemoteFstypes(void);
73343181Sdim
74343181Sdimint isFdRemote(int a_fd);
75343181Sdimint isPathRemote(char *a_path);
76343181Sdimint isFstypeRemote(char *a_fstype);
77343181Sdimint isdir(char *path);
78343181Sdimint isfile(char *dir, char *file);
79343181Sdimint iscpio(char *path, int *iscomp);
80343181Sdim
81343181Sdim/*
82343181Sdim * Name:	isdir
83343181Sdim * Description:	determine if specified path exists and is a directory
84343181Sdim * Arguments:	path - pointer to string representing the path to verify
85343181Sdim * returns: 0 - directory exists
86343181Sdim *	    1 - directory does not exist or is not a directory
87343181Sdim * NOTE:	errno is set appropriately
88343181Sdim */
89343181Sdim
90343181Sdimint
91343181Sdimisdir(char *path)
92343181Sdim{
93343181Sdim	struct stat statbuf;
94343181Sdim
95343181Sdim	/* return error if path does not exist */
96343181Sdim
97343181Sdim	if (stat(path, &statbuf) != 0) {
98343181Sdim		return (1);
99343181Sdim	}
100343181Sdim
101343181Sdim	/* return error if path is not a directory */
102343181Sdim
103343181Sdim	if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
104343181Sdim		errno = ENOTDIR;
105343181Sdim		return (1);
106343181Sdim	}
107343181Sdim
108343181Sdim	return (0);
109343181Sdim}
110343181Sdim
111343181Sdim/*
112343181Sdim * Name:	isfile
113343181Sdim * Description:	determine if specified path exists and is a directory
114343181Sdim * Arguments:	dir - pointer to string representing the directory where
115343181Sdim *			the file is located
116343181Sdim *			== NULL - use "file" argument only
117343181Sdim *		file - pointer to string representing the file to verify
118343181Sdim * Returns:	0 - success - file exists
119343181Sdim *		1 - failure - file does not exist OR is not a file
120343181Sdim * NOTE:	errno is set appropriately
121343181Sdim */
122343181Sdim
123343181Sdimint
124343181Sdimisfile(char *dir, char *file)
125343181Sdim{
126343181Sdim	struct stat statbuf;
127343181Sdim	char	path[PATH_MAX];
128343181Sdim
129343181Sdim	/* construct full path if directory specified */
130360784Sdim
131360784Sdim	if (dir) {
132360784Sdim		(void) snprintf(path, sizeof (path), "%s/%s", dir, file);
133360784Sdim		file = path;
134343181Sdim	}
135343181Sdim
136343181Sdim	/* return error if path does not exist */
137343181Sdim
138343181Sdim	if (stat(file, &statbuf) != 0) {
139343181Sdim		return (1);
140343181Sdim	}
141343181Sdim
142343181Sdim	/* return error if path is a directory */
143343181Sdim
144343181Sdim	if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
145343181Sdim		errno = EISDIR;
146343181Sdim		return (1);
147343181Sdim	}
148343181Sdim
149343181Sdim	/* return error if path is not a file */
150343181Sdim
151343181Sdim	if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
152343181Sdim		errno = EINVAL;
153343181Sdim		return (1);
154343181Sdim	}
155343181Sdim
156343181Sdim	return (0);
157343181Sdim}
158343181Sdim
159343181Sdimint
160343181Sdimiscpio(char *path, int *iscomp)
161343181Sdim{
162343181Sdim	/*
163343181Sdim	 * Compressed File Header.
164343181Sdim	 */
165343181Sdim	unsigned char m_h[] = { "\037\235" };		/* 1F 9D */
166343181Sdim
167343181Sdim	static union {
168343181Sdim		short int	b_mag;
169343181Sdim		char		c_mag[CMS_LEN];
170343181Sdim	}	cm;
171343181Sdim
172343181Sdim	struct stat	statb;
173343181Sdim	int		fd;
174343181Sdim
175343181Sdim
176343181Sdim	*iscomp = 0;
177343181Sdim
178343181Sdim	if ((fd = open(path, O_RDONLY, 0)) == -1) {
179343181Sdim		if (errno != ENOENT) {
180343181Sdim			perror("");
181343181Sdim			(void) fprintf(stderr, pkg_gt(ERR_ISCPIO_OPEN), path);
182343181Sdim		}
183343181Sdim		return (0);
184343181Sdim	} else {
185343181Sdim		if (fstat(fd, &statb) == -1) {
186343181Sdim			perror("");
187343181Sdim			(void) fprintf(stderr, pkg_gt(ERR_ISCPIO_FSTAT), path);
188343181Sdim			(void) close(fd);
189343181Sdim			return (0);
190343181Sdim		} else {
191343181Sdim			if (S_ISREG(statb.st_mode)) {	/* Must be a file */
192343181Sdim				if (read(fd, cm.c_mag, sizeof (cm.c_mag)) !=
193343181Sdim				    sizeof (cm.c_mag)) {
194343181Sdim					perror("");
195343181Sdim					(void) fprintf(stderr,
196343181Sdim					    pkg_gt(ERR_ISCPIO_READ), path);
197343181Sdim					(void) close(fd);
198343181Sdim					return (0);
199343181Sdim				}
200343181Sdim				/*
201343181Sdim				 * Try to determine if the file is a compressed
202343181Sdim				 * file, if that fails, try to determine if it
203343181Sdim				 * is a cpio archive, if that fails, then we
204343181Sdim				 * fail!
205343181Sdim				 */
206343181Sdim				if (ISCOMPCPIO) {
207343181Sdim					*iscomp = 1;
208343181Sdim					(void) close(fd);
209343181Sdim					return (1);
210343181Sdim				} else if (ISCPIO) {
211343181Sdim					(void) fprintf(stderr,
212343181Sdim					    pkg_gt(ERR_ISCPIO_NOCPIO),
213343181Sdim					    path);
214343181Sdim					(void) close(fd);
215343181Sdim					return (0);
216343181Sdim				}
217343181Sdim				(void) close(fd);
218343181Sdim				return (1);
219343181Sdim			} else {
220343181Sdim				(void) close(fd);
221343181Sdim				return (0);
222343181Sdim			}
223343181Sdim		}
224343181Sdim	}
225343181Sdim}
226343181Sdim
227343181Sdim/*
228343181Sdim * Name:	isPathRemote
229343181Sdim * Description:	determine if a path object is local or remote
230343181Sdim * Arguments:	a_path - [RO, *RO] - (char *)
231343181Sdim *			Pointer to string representing the path to check
232343181Sdim * Returns:	int
233343181Sdim *			1 - the path is remote
234343181Sdim *			0 - the path is local to this system
235343181Sdim *			-1 - cannot determine if path is remote or local
236343181Sdim */
237343181Sdim
238343181Sdimint
239343181SdimisPathRemote(char *a_path)
240343181Sdim{
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
263int
264isFdRemote(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
288int
289isFstypeRemote(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 */
325static 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