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.
26 #pragma ident "%Z%%M% %I% %E% SMI"
42 #include <libdevinfo.h>
44 #include <sys/modctl.h>
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.
73 device_exists(const char *devname
)
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)
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.
100 finddev_readdir_alt(const char *path
, finddevhdl_t
*handlep
)
102 struct finddevhdl
*handle
;
108 if ((dir
= opendir(path
)) == NULL
)
112 handle
= calloc(1, sizeof (struct finddevhdl
));
113 if (handle
== NULL
) {
114 (void) closedir(dir
);
120 handle
->paths
= NULL
;
124 while ((dp
= readdir(dir
)) != NULL
) {
125 if ((strcmp(dp
->d_name
, ".") == 0) ||
126 (strcmp(dp
->d_name
, "..") == 0))
132 handle
->paths
= calloc(n
, sizeof (char *));
133 if (handle
->paths
== NULL
) {
135 (void) closedir(dir
);
141 while ((dp
= readdir(dir
)) != NULL
) {
142 if ((strcmp(dp
->d_name
, ".") == 0) ||
143 (strcmp(dp
->d_name
, "..") == 0))
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
);
153 handle
->paths
[n
] = strdup(dp
->d_name
);
154 if (handle
->paths
[n
] == NULL
) {
155 (void) closedir(dir
);
156 finddev_close((finddevhdl_t
)handle
);
161 (void) closedir(dir
);
162 *handlep
= (finddevhdl_t
)handle
;
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
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.
178 finddev_readdir_devfs(const char *path
, finddevhdl_t
*handlep
)
180 struct finddevhdl
*handle
;
189 handle
= calloc(1, sizeof (struct finddevhdl
));
195 handle
->paths
= NULL
;
197 rv
= modctl(MODDEVREADDIR
, path
, strlen(path
), NULL
, &bufsiz
);
205 if ((pathlist
= malloc(bufsiz
)) == NULL
) {
210 rv
= modctl(MODDEVREADDIR
, path
, strlen(path
),
213 for (n
= 0, p
= pathlist
;
214 (len
= strlen(p
)) > 0; p
+= len
+1) {
218 handle
->paths
= calloc(n
, sizeof (char *));
219 if (handle
->paths
== NULL
) {
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
);
233 *handlep
= (finddevhdl_t
)handle
;
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
265 finddev_emptydir_alt(const char *path
)
270 if ((dir
= opendir(path
)) == NULL
)
273 while ((dp
= readdir(dir
)) != NULL
) {
274 if ((strcmp(dp
->d_name
, ".") == 0) ||
275 (strcmp(dp
->d_name
, "..") == 0))
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
289 * Note: only useable with paths mounted on an instance of the
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.
297 finddev_emptydir_devfs(const char *path
)
302 rv
= modctl(MODDEVEMPTYDIR
, path
, strlen(path
), &empty
);
310 finddev_emptydir(const char *path
)
312 if (GLOBAL_DEV_PATH(path
)) {
313 return (finddev_emptydir_devfs(path
));
315 return (finddev_emptydir_alt(path
));
319 finddev_close(finddevhdl_t arg
)
321 struct finddevhdl
*handle
= (struct finddevhdl
*)arg
;
324 for (i
= 0; i
< handle
->npaths
; i
++) {
325 if (handle
->paths
[i
])
326 free(handle
->paths
[i
]);
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
];