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(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 */
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