dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libdevinfo / devinfo_finddev.c
blobd2810a69bb276f4330d49a85a065879ebc540b9f
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 #include <stdio.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <thread.h>
31 #include <synch.h>
32 #include <limits.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <strings.h>
36 #include <dirent.h>
37 #include <regex.h>
38 #include <errno.h>
39 #include <stdarg.h>
40 #include <libdevinfo.h>
41 #include <zone.h>
42 #include <sys/modctl.h>
43 #include <syslog.h>
44 #include <sys/stat.h>
45 #include <assert.h>
48 struct finddevhdl {
49 int npaths;
50 int curpath;
51 char **paths;
55 #define GLOBAL_DEV_PATH(devpath) \
56 ((getzoneid() == GLOBAL_ZONEID) && \
57 ((strcmp(devpath, "/dev") == 0) || \
58 (strncmp(devpath, "/dev/", strlen("/dev/")) == 0)))
61 * Return true if a device exists
62 * If the path refers into the /dev filesystem, use a
63 * private interface to query if the device exists but
64 * without triggering an implicit reconfig if it does not.
65 * Note: can only function properly with absolute pathnames
66 * and only functions for persisted global /dev names, ie
67 * those managed by devfsadm. For paths other than
68 * /dev, stat(2) is sufficient.
70 int
71 device_exists(const char *devname)
73 int rv;
74 struct stat st;
76 if (GLOBAL_DEV_PATH(devname)) {
77 rv = modctl(MODDEVEXISTS, devname, strlen(devname));
78 return ((rv == 0) ? 1 : 0);
80 if (stat(devname, &st) == 0)
81 return (1);
82 return (0);
87 * Use the standard library readdir to read the contents of
88 * directories on alternate root mounted filesystems.
89 * Return results as per dev_readdir_devfs().
91 * The directory is traversed twice. First, to calculate
92 * the size of the buffer required; second, to copy the
93 * directory contents into the buffer. If the directory
94 * contents grow in between passes, which should almost
95 * never happen, start over again.
97 static int
98 finddev_readdir_alt(const char *path, finddevhdl_t *handlep)
100 struct finddevhdl *handle;
101 DIR *dir;
102 struct dirent *dp;
103 size_t n;
105 *handlep = NULL;
106 if ((dir = opendir(path)) == NULL)
107 return (ENOENT);
109 restart:
110 handle = calloc(1, sizeof (struct finddevhdl));
111 if (handle == NULL) {
112 (void) closedir(dir);
113 return (ENOMEM);
116 handle->npaths = 0;
117 handle->curpath = 0;
118 handle->paths = NULL;
120 n = 0;
121 rewinddir(dir);
122 while ((dp = readdir(dir)) != NULL) {
123 if ((strcmp(dp->d_name, ".") == 0) ||
124 (strcmp(dp->d_name, "..") == 0))
125 continue;
126 n++;
129 handle->npaths = n;
130 handle->paths = calloc(n, sizeof (char *));
131 if (handle->paths == NULL) {
132 free(handle);
133 (void) closedir(dir);
134 return (ENOMEM);
137 n = 0;
138 rewinddir(dir);
139 while ((dp = readdir(dir)) != NULL) {
140 if ((strcmp(dp->d_name, ".") == 0) ||
141 (strcmp(dp->d_name, "..") == 0))
142 continue;
143 if (n == handle->npaths) {
145 * restart if directory contents have out-grown
146 * buffer allocated in the first pass.
148 finddev_close((finddevhdl_t)handle);
149 goto restart;
151 handle->paths[n] = strdup(dp->d_name);
152 if (handle->paths[n] == NULL) {
153 (void) closedir(dir);
154 finddev_close((finddevhdl_t)handle);
155 return (ENOMEM);
157 n++;
159 (void) closedir(dir);
160 *handlep = (finddevhdl_t)handle;
161 return (0);
165 * Use of the dev filesystem's private readdir does not trigger
166 * the implicit device reconfiguration.
168 * Note: only useable with paths mounted on an instance of the
169 * dev filesystem.
171 * Does not return the . and .. entries.
172 * Empty directories are returned as an zero-length list.
173 * ENOENT is returned as a NULL list pointer.
175 static int
176 finddev_readdir_devfs(const char *path, finddevhdl_t *handlep)
178 struct finddevhdl *handle;
179 int n;
180 int rv;
181 int64_t bufsiz;
182 char *pathlist;
183 char *p;
184 int len;
186 *handlep = NULL;
187 handle = calloc(1, sizeof (struct finddevhdl));
188 if (handle == NULL)
189 return (ENOMEM);
191 handle->npaths = 0;
192 handle->curpath = 0;
193 handle->paths = NULL;
195 rv = modctl(MODDEVREADDIR, path, strlen(path), NULL, &bufsiz);
196 if (rv != 0) {
197 free(handle);
198 return (rv);
201 for (;;) {
202 assert(bufsiz != 0);
203 if ((pathlist = malloc(bufsiz)) == NULL) {
204 free(handle);
205 return (ENOMEM);
208 rv = modctl(MODDEVREADDIR, path, strlen(path),
209 pathlist, &bufsiz);
210 if (rv == 0) {
211 for (n = 0, p = pathlist;
212 (len = strlen(p)) > 0; p += len+1) {
213 n++;
215 handle->npaths = n;
216 handle->paths = calloc(n, sizeof (char *));
217 if (handle->paths == NULL) {
218 free(handle);
219 free(pathlist);
220 return (ENOMEM);
222 for (n = 0, p = pathlist;
223 (len = strlen(p)) > 0; p += len+1, n++) {
224 handle->paths[n] = strdup(p);
225 if (handle->paths[n] == NULL) {
226 finddev_close((finddevhdl_t)handle);
227 free(pathlist);
228 return (ENOMEM);
231 *handlep = (finddevhdl_t)handle;
232 free(pathlist);
233 return (0);
235 free(pathlist);
236 switch (errno) {
237 case EAGAIN:
238 break;
239 case ENOENT:
240 default:
241 free(handle);
242 return (errno);
245 /*NOTREACHED*/
249 finddev_readdir(const char *path, finddevhdl_t *handlep)
251 if (GLOBAL_DEV_PATH(path)) {
252 return (finddev_readdir_devfs(path, handlep));
254 return (finddev_readdir_alt(path, handlep));
258 * Return true if a directory is empty
259 * Use the standard library readdir to determine if a directory is
260 * empty.
262 static int
263 finddev_emptydir_alt(const char *path)
265 DIR *dir;
266 struct dirent *dp;
268 if ((dir = opendir(path)) == NULL)
269 return (ENOENT);
271 while ((dp = readdir(dir)) != NULL) {
272 if ((strcmp(dp->d_name, ".") == 0) ||
273 (strcmp(dp->d_name, "..") == 0))
274 continue;
275 (void) closedir(dir);
276 return (0); /* not empty */
278 (void) closedir(dir);
279 return (1); /* empty */
283 * Use of the dev filesystem's private readdir does (not trigger
284 * the implicit device reconfiguration) to determine if a directory
285 * is empty.
287 * Note: only useable with paths mounted on an instance of the
288 * dev filesystem.
290 * Does not return the . and .. entries.
291 * Empty directories are returned as an zero-length list.
292 * ENOENT is returned as a NULL list pointer.
294 static int
295 finddev_emptydir_devfs(const char *path)
297 int rv;
298 int empty;
300 rv = modctl(MODDEVEMPTYDIR, path, strlen(path), &empty);
301 if (rv == 0) {
302 return (empty);
304 return (0);
308 finddev_emptydir(const char *path)
310 if (GLOBAL_DEV_PATH(path)) {
311 return (finddev_emptydir_devfs(path));
313 return (finddev_emptydir_alt(path));
316 void
317 finddev_close(finddevhdl_t arg)
319 struct finddevhdl *handle = (struct finddevhdl *)arg;
320 int i;
322 for (i = 0; i < handle->npaths; i++) {
323 free(handle->paths[i]);
325 free(handle->paths);
326 free(handle);
329 const char *
330 finddev_next(finddevhdl_t arg)
332 struct finddevhdl *handle = (struct finddevhdl *)arg;
333 const char *path = NULL;
335 if (handle->curpath < handle->npaths) {
336 path = handle->paths[handle->curpath];
337 handle->curpath++;
339 return (path);