5754 prtconf: assertion failure in libpcidb if vendor cannot be looked up
[illumos-gate.git] / usr / src / lib / libdevinfo / devinfo_finddev.c
blobeea252358f92d480215b5ace82d838fd491fbdcc
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <thread.h>
33 #include <synch.h>
34 #include <limits.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <dirent.h>
39 #include <regex.h>
40 #include <errno.h>
41 #include <stdarg.h>
42 #include <libdevinfo.h>
43 #include <zone.h>
44 #include <sys/modctl.h>
45 #include <syslog.h>
46 #include <sys/stat.h>
47 #include <assert.h>
50 struct finddevhdl {
51 int npaths;
52 int curpath;
53 char **paths;
57 #define GLOBAL_DEV_PATH(devpath) \
58 ((getzoneid() == GLOBAL_ZONEID) && \
59 ((strcmp(devpath, "/dev") == 0) || \
60 (strncmp(devpath, "/dev/", strlen("/dev/")) == 0)))
63 * Return true if a device exists
64 * If the path refers into the /dev filesystem, use a
65 * private interface to query if the device exists but
66 * without triggering an implicit reconfig if it does not.
67 * Note: can only function properly with absolute pathnames
68 * and only functions for persisted global /dev names, ie
69 * those managed by devfsadm. For paths other than
70 * /dev, stat(2) is sufficient.
72 int
73 device_exists(const char *devname)
75 int rv;
76 struct stat st;
78 if (GLOBAL_DEV_PATH(devname)) {
79 rv = modctl(MODDEVEXISTS, devname, strlen(devname));
80 return ((rv == 0) ? 1 : 0);
82 if (stat(devname, &st) == 0)
83 return (1);
84 return (0);
89 * Use the standard library readdir to read the contents of
90 * directories on alternate root mounted filesystems.
91 * Return results as per dev_readdir_devfs().
93 * The directory is traversed twice. First, to calculate
94 * the size of the buffer required; second, to copy the
95 * directory contents into the buffer. If the directory
96 * contents grow in between passes, which should almost
97 * never happen, start over again.
99 static int
100 finddev_readdir_alt(const char *path, finddevhdl_t *handlep)
102 struct finddevhdl *handle;
103 DIR *dir;
104 struct dirent *dp;
105 size_t n;
107 *handlep = NULL;
108 if ((dir = opendir(path)) == NULL)
109 return (ENOENT);
111 restart:
112 handle = calloc(1, sizeof (struct finddevhdl));
113 if (handle == NULL) {
114 (void) closedir(dir);
115 return (ENOMEM);
118 handle->npaths = 0;
119 handle->curpath = 0;
120 handle->paths = NULL;
122 n = 0;
123 rewinddir(dir);
124 while ((dp = readdir(dir)) != NULL) {
125 if ((strcmp(dp->d_name, ".") == 0) ||
126 (strcmp(dp->d_name, "..") == 0))
127 continue;
128 n++;
131 handle->npaths = n;
132 handle->paths = calloc(n, sizeof (char *));
133 if (handle->paths == NULL) {
134 free(handle);
135 (void) closedir(dir);
136 return (ENOMEM);
139 n = 0;
140 rewinddir(dir);
141 while ((dp = readdir(dir)) != NULL) {
142 if ((strcmp(dp->d_name, ".") == 0) ||
143 (strcmp(dp->d_name, "..") == 0))
144 continue;
145 if (n == handle->npaths) {
147 * restart if directory contents have out-grown
148 * buffer allocated in the first pass.
150 finddev_close((finddevhdl_t)handle);
151 goto restart;
153 handle->paths[n] = strdup(dp->d_name);
154 if (handle->paths[n] == NULL) {
155 (void) closedir(dir);
156 finddev_close((finddevhdl_t)handle);
157 return (ENOMEM);
159 n++;
161 (void) closedir(dir);
162 *handlep = (finddevhdl_t)handle;
163 return (0);
167 * Use of the dev filesystem's private readdir does not trigger
168 * the implicit device reconfiguration.
170 * Note: only useable with paths mounted on an instance of the
171 * dev filesystem.
173 * Does not return the . and .. entries.
174 * Empty directories are returned as an zero-length list.
175 * ENOENT is returned as a NULL list pointer.
177 static int
178 finddev_readdir_devfs(const char *path, finddevhdl_t *handlep)
180 struct finddevhdl *handle;
181 int n;
182 int rv;
183 int64_t bufsiz;
184 char *pathlist;
185 char *p;
186 int len;
188 *handlep = NULL;
189 handle = calloc(1, sizeof (struct finddevhdl));
190 if (handle == NULL)
191 return (ENOMEM);
193 handle->npaths = 0;
194 handle->curpath = 0;
195 handle->paths = NULL;
197 rv = modctl(MODDEVREADDIR, path, strlen(path), NULL, &bufsiz);
198 if (rv != 0) {
199 free(handle);
200 return (rv);
203 for (;;) {
204 assert(bufsiz != 0);
205 if ((pathlist = malloc(bufsiz)) == NULL) {
206 free(handle);
207 return (ENOMEM);
210 rv = modctl(MODDEVREADDIR, path, strlen(path),
211 pathlist, &bufsiz);
212 if (rv == 0) {
213 for (n = 0, p = pathlist;
214 (len = strlen(p)) > 0; p += len+1) {
215 n++;
217 handle->npaths = n;
218 handle->paths = calloc(n, sizeof (char *));
219 if (handle->paths == NULL) {
220 free(handle);
221 free(pathlist);
222 return (ENOMEM);
224 for (n = 0, p = pathlist;
225 (len = strlen(p)) > 0; p += len+1, n++) {
226 handle->paths[n] = strdup(p);
227 if (handle->paths[n] == NULL) {
228 finddev_close((finddevhdl_t)handle);
229 free(pathlist);
230 return (ENOMEM);
233 *handlep = (finddevhdl_t)handle;
234 free(pathlist);
235 return (0);
237 free(pathlist);
238 switch (errno) {
239 case EAGAIN:
240 break;
241 case ENOENT:
242 default:
243 free(handle);
244 return (errno);
247 /*NOTREACHED*/
251 finddev_readdir(const char *path, finddevhdl_t *handlep)
253 if (GLOBAL_DEV_PATH(path)) {
254 return (finddev_readdir_devfs(path, handlep));
256 return (finddev_readdir_alt(path, handlep));
260 * Return true if a directory is empty
261 * Use the standard library readdir to determine if a directory is
262 * empty.
264 static int
265 finddev_emptydir_alt(const char *path)
267 DIR *dir;
268 struct dirent *dp;
270 if ((dir = opendir(path)) == NULL)
271 return (ENOENT);
273 while ((dp = readdir(dir)) != NULL) {
274 if ((strcmp(dp->d_name, ".") == 0) ||
275 (strcmp(dp->d_name, "..") == 0))
276 continue;
277 (void) closedir(dir);
278 return (0); /* not empty */
280 (void) closedir(dir);
281 return (1); /* empty */
285 * Use of the dev filesystem's private readdir does (not trigger
286 * the implicit device reconfiguration) to determine if a directory
287 * is empty.
289 * Note: only useable with paths mounted on an instance of the
290 * dev filesystem.
292 * Does not return the . and .. entries.
293 * Empty directories are returned as an zero-length list.
294 * ENOENT is returned as a NULL list pointer.
296 static int
297 finddev_emptydir_devfs(const char *path)
299 int rv;
300 int empty;
302 rv = modctl(MODDEVEMPTYDIR, path, strlen(path), &empty);
303 if (rv == 0) {
304 return (empty);
306 return (0);
310 finddev_emptydir(const char *path)
312 if (GLOBAL_DEV_PATH(path)) {
313 return (finddev_emptydir_devfs(path));
315 return (finddev_emptydir_alt(path));
318 void
319 finddev_close(finddevhdl_t arg)
321 struct finddevhdl *handle = (struct finddevhdl *)arg;
322 int i;
324 for (i = 0; i < handle->npaths; i++) {
325 if (handle->paths[i])
326 free(handle->paths[i]);
328 free(handle->paths);
329 free(handle);
332 const char *
333 finddev_next(finddevhdl_t arg)
335 struct finddevhdl *handle = (struct finddevhdl *)arg;
336 const char *path = NULL;
338 if (handle->curpath < handle->npaths) {
339 path = handle->paths[handle->curpath];
340 handle->curpath++;
342 return (path);