4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 * ramdiskadm - administer ramdisk(7d). Allows creation and deletion of
27 * ramdisks, and display status. All the ioctls are private between
28 * ramdisk and ramdiskadm, and so are very simple - device information is
29 * communicated via a name or a minor number.
32 #pragma ident "%Z%%M% %I% %E% SMI"
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/ramdisk.h>
38 #include <sys/mkdev.h>
39 #include <sys/sunddi.h>
40 #include <libdevinfo.h>
52 #define RD_BLOCK_DEV_PFX "/dev/" RD_BLOCK_NAME "/"
53 #define RD_CHAR_DEV_PFX "/dev/" RD_CHAR_NAME "/"
55 #define HEADING "%-*.*s %20s %-10s\n"
56 #define FORMAT "%-*.*s %20llu %s\n"
57 #define FW (sizeof (RD_BLOCK_DEV_PFX) - 1 + RD_NAME_LEN)
64 (void) fprintf(stderr
,
65 gettext("Usage: %s [ -a <name> <size>[g|m|k|b] | -d <name> ]\n"),
71 * This might be the first time we've used this minor device. If so,
72 * it might also be that the /dev links are in the process of being created
73 * by devfsadmd (or that they'll be created "soon"). We cannot return
74 * until they're there or the invoker of ramdiskadm might try to use them
75 * and not find them. This can happen if a shell script is running on
79 wait_until_dev_complete(char *name
)
81 di_devlink_handle_t hdl
;
83 hdl
= di_devlink_init(RD_DRIVER_NAME
, DI_MAKE_LINK
);
85 die(gettext("couldn't create device link for\"%s\""), name
);
87 (void) di_devlink_fini(&hdl
);
91 * Create a named ramdisk.
94 alloc_ramdisk(int ctl_fd
, char *name
, uint64_t size
)
98 (void) strlcpy(ri
.ri_name
, name
, sizeof (ri
.ri_name
));
101 if (ioctl(ctl_fd
, RD_CREATE_DISK
, &ri
) == -1) {
102 die(gettext("couldn't create ramdisk \"%s\""), name
);
104 wait_until_dev_complete(name
);
106 (void) printf(RD_BLOCK_DEV_PFX
"%s\n", name
);
110 * Delete a named ramdisk.
113 delete_ramdisk(int ctl_fd
, char *name
)
117 (void) strlcpy(ri
.ri_name
, name
, sizeof (ri
.ri_name
));
119 if (ioctl(ctl_fd
, RD_DELETE_DISK
, &ri
) == -1) {
120 die(gettext("couldn't delete ramdisk \"%s\""), name
);
126 di_callback(di_node_t node
, di_minor_t minor
, void *arg
)
128 static boolean_t heading_done
= B_FALSE
;
129 boolean_t obp_ramdisk
;
131 char devnm
[MAXNAMELEN
];
133 char blkpath
[MAXPATHLEN
];
136 * Only consider block nodes bound to the ramdisk driver.
138 if (strcmp(di_driver_name(node
), RD_DRIVER_NAME
) == 0 &&
139 di_minor_spectype(minor
) == S_IFBLK
) {
141 * Determine whether this ramdisk is pseudo or OBP-created.
143 obp_ramdisk
= (di_nodeid(node
) == DI_PROM_NODEID
);
146 * If this is an OBP-created ramdisk use the node name, having
147 * first stripped the "ramdisk-" prefix. For pseudo ramdisks
148 * use the minor name, having first stripped any ",raw" suffix.
151 RD_STRIP_PREFIX(name
, di_node_name(node
));
152 (void) strlcpy(devnm
, name
, sizeof (devnm
));
154 (void) strlcpy(devnm
, di_minor_name(minor
),
156 RD_STRIP_SUFFIX(devnm
);
160 * Get the size of the ramdisk.
162 if (di_prop_lookup_int64(di_minor_devt(minor
), node
,
163 "Size", (int64_t **)&sizep
) == -1) {
164 die(gettext("couldn't obtain size of ramdisk"));
168 * Print information about the ramdisk. Prepend a heading
169 * if this is the first/only one.
172 (void) printf(HEADING
, FW
, FW
, gettext("Block Device"),
173 gettext("Size"), gettext("Removable"));
174 heading_done
= B_TRUE
;
176 (void) snprintf(blkpath
, sizeof (blkpath
),
177 RD_BLOCK_DEV_PFX
"%s", devnm
);
178 (void) printf(FORMAT
, FW
, FW
, blkpath
, *sizep
,
179 obp_ramdisk
? gettext("No") : gettext("Yes"));
182 return (DI_WALK_CONTINUE
);
186 * Print the list of all the ramdisks, their size, and whether they
187 * are removeable (i.e. non-OBP ramdisks).
195 * Create a snapshot of the device tree, then walk it looking
196 * for, and printing information about, ramdisk nodes.
198 if ((root
= di_init("/", DINFOCPYALL
)) == DI_NODE_NIL
) {
199 die(gettext("couldn't create device tree snapshot"));
202 if (di_walk_minor(root
, DDI_PSEUDO
, 0, NULL
, di_callback
) == -1) {
204 die(gettext("device tree walk failure"));
211 main(int argc
, char *argv
[])
222 static char rd_ctl
[] = "/dev/" RD_CTL_NAME
;
224 pname
= getpname(argv
[0]);
226 (void) setlocale(LC_ALL
, "");
227 (void) textdomain(TEXT_DOMAIN
);
229 while ((c
= getopt(argc
, argv
, "a:d:")) != EOF
) {
235 if (((argc
- optind
) <= 0) || (*argv
[optind
] == '-')) {
236 warn(gettext("<size> missing\n"));
240 size
= strtoll(argv
[optind
], &suffix
, 0);
241 if (strcmp(suffix
, "b") == 0) {
244 } else if (strcmp(suffix
, "k") == 0) {
247 } else if (strcmp(suffix
, "m") == 0) {
248 size
*= (1024 * 1024);
250 } else if (strcmp(suffix
, "g") == 0) {
251 size
*= (1024 * 1024 * 1024);
254 if (size
== 0 || *suffix
!= '\0') {
255 warn(gettext("Illegal <size> \"%s\"\n"),
271 if (errflag
|| (allocflag
&& deleteflag
) || (argc
- optind
) > 0) {
276 if (allocflag
|| deleteflag
) {
277 boolean_t nameok
= B_TRUE
;
281 * Strip off any leading "/dev/{r}ramdisk/" prefix.
283 if (strncmp(name
, RD_BLOCK_DEV_PFX
,
284 sizeof (RD_BLOCK_DEV_PFX
)-1) == 0) {
285 name
+= sizeof (RD_BLOCK_DEV_PFX
)-1;
286 } else if (strncmp(name
, RD_CHAR_DEV_PFX
,
287 sizeof (RD_CHAR_DEV_PFX
)-1) == 0) {
288 name
+= sizeof (RD_CHAR_DEV_PFX
)-1;
292 * Check that name isn't too long, and that it only contains
293 * valid characters, i.e. [a-zA-Z0-9_][a-zA-Z0-9_-]*
295 if (name
[0] == '-') { /* permit only within name */
298 for (p
= name
; *p
!= '\0'; p
++) {
299 if (!isalnum(*p
) && *p
!= '_' && *p
!= '-') {
305 if (!nameok
|| (p
- name
) > RD_NAME_LEN
) {
306 warn(gettext("illegal <name> \"%s\"\n"), name
);
313 * Now do the real work.
316 if (allocflag
|| deleteflag
)
319 openflag
|= O_RDONLY
;
320 ctl_fd
= open(rd_ctl
, openflag
);
322 if ((errno
== EPERM
) || (errno
== EACCES
)) {
323 die(gettext("you do not have permission to perform "
324 "that operation.\n"));
332 alloc_ramdisk(ctl_fd
, name
, size
);
333 } else if (deleteflag
) {
334 delete_ramdisk(ctl_fd
, name
);