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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
40 #include <libdevinfo.h>
42 #include <sys/modctl.h>
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.
71 device_exists(const char *devname
)
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)
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.
98 finddev_readdir_alt(const char *path
, finddevhdl_t
*handlep
)
100 struct finddevhdl
*handle
;
106 if ((dir
= opendir(path
)) == NULL
)
110 handle
= calloc(1, sizeof (struct finddevhdl
));
111 if (handle
== NULL
) {
112 (void) closedir(dir
);
118 handle
->paths
= NULL
;
122 while ((dp
= readdir(dir
)) != NULL
) {
123 if ((strcmp(dp
->d_name
, ".") == 0) ||
124 (strcmp(dp
->d_name
, "..") == 0))
130 handle
->paths
= calloc(n
, sizeof (char *));
131 if (handle
->paths
== NULL
) {
133 (void) closedir(dir
);
139 while ((dp
= readdir(dir
)) != NULL
) {
140 if ((strcmp(dp
->d_name
, ".") == 0) ||
141 (strcmp(dp
->d_name
, "..") == 0))
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
);
151 handle
->paths
[n
] = strdup(dp
->d_name
);
152 if (handle
->paths
[n
] == NULL
) {
153 (void) closedir(dir
);
154 finddev_close((finddevhdl_t
)handle
);
159 (void) closedir(dir
);
160 *handlep
= (finddevhdl_t
)handle
;
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
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.
176 finddev_readdir_devfs(const char *path
, finddevhdl_t
*handlep
)
178 struct finddevhdl
*handle
;
187 handle
= calloc(1, sizeof (struct finddevhdl
));
193 handle
->paths
= NULL
;
195 rv
= modctl(MODDEVREADDIR
, path
, strlen(path
), NULL
, &bufsiz
);
203 if ((pathlist
= malloc(bufsiz
)) == NULL
) {
208 rv
= modctl(MODDEVREADDIR
, path
, strlen(path
),
211 for (n
= 0, p
= pathlist
;
212 (len
= strlen(p
)) > 0; p
+= len
+1) {
216 handle
->paths
= calloc(n
, sizeof (char *));
217 if (handle
->paths
== NULL
) {
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
);
231 *handlep
= (finddevhdl_t
)handle
;
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
263 finddev_emptydir_alt(const char *path
)
268 if ((dir
= opendir(path
)) == NULL
)
271 while ((dp
= readdir(dir
)) != NULL
) {
272 if ((strcmp(dp
->d_name
, ".") == 0) ||
273 (strcmp(dp
->d_name
, "..") == 0))
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
287 * Note: only useable with paths mounted on an instance of the
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.
295 finddev_emptydir_devfs(const char *path
)
300 rv
= modctl(MODDEVEMPTYDIR
, path
, strlen(path
), &empty
);
308 finddev_emptydir(const char *path
)
310 if (GLOBAL_DEV_PATH(path
)) {
311 return (finddev_emptydir_devfs(path
));
313 return (finddev_emptydir_alt(path
));
317 finddev_close(finddevhdl_t arg
)
319 struct finddevhdl
*handle
= (struct finddevhdl
*)arg
;
322 for (i
= 0; i
< handle
->npaths
; i
++) {
323 free(handle
->paths
[i
]);
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
];