xref: /freebsd/sys/fs/devfs/devfs_devs.c (revision 2cdbd5eec4e32beddb3adcca014dda56debc6f5b)
1 #define DEBUG 1
2 /*
3  * Copyright (c) 2000
4  *	Poul-Henning Kamp.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Neither the name of the University nor the names of its contributors
12  *    may be used to endorse or promote products derived from this software
13  *    without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36
28  *
29  * $FreeBSD$
30  */
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/dirent.h>
35 #include <sys/conf.h>
36 #include <sys/vnode.h>
37 #include <sys/malloc.h>
38 #include <sys/eventhandler.h>
39 #include <sys/ctype.h>
40 
41 #define DEVFS_INTERN
42 #include <fs/devfs/devfs.h>
43 
44 struct devfs_dirent *
45 devfs_newdirent(char *name, int namelen)
46 {
47 	int i;
48 	struct devfs_dirent *de;
49 	struct dirent d;
50 
51 	d.d_namlen = namelen;
52 	i = sizeof (*de) + GENERIC_DIRSIZ(&d);
53 	MALLOC(de, struct devfs_dirent *, i, M_DEVFS, M_WAITOK);
54 	bzero(de, i);
55 	de->de_dirent = (struct dirent *)(de + 1);
56 	de->de_dirent->d_namlen = namelen;
57 	de->de_dirent->d_reclen = GENERIC_DIRSIZ(&d);
58 	bcopy(name, de->de_dirent->d_name, namelen + 1);
59 	nanotime(&de->de_ctime);
60 	return (de);
61 }
62 
63 struct devfs_dir *
64 devfs_vmkdir(void)
65 {
66 	struct devfs_dir *dd;
67 	struct devfs_dirent *de;
68 
69 	MALLOC(dd, struct devfs_dir *, sizeof(*dd), M_DEVFS, M_WAITOK);
70 	bzero(dd, sizeof(*dd));
71 	TAILQ_INIT(&dd->dd_list);
72 
73 	de = devfs_newdirent(".", 1);
74 	de->de_dirent->d_type = DT_DIR;
75 	TAILQ_INSERT_TAIL(&dd->dd_list, de, de_list);
76 	de = TAILQ_FIRST(&dd->dd_list);
77 	de->de_mode = 0755;
78 	return (dd);
79 }
80 
81 void
82 devfs_delete(struct devfs_dir *dd, struct devfs_dirent *de)
83 {
84 
85 	if (de->de_symlink) {
86 		FREE(de->de_symlink, M_DEVFS);
87 		de->de_symlink = NULL;
88 	}
89 	if (de->de_vnode) {
90 		de->de_vnode->v_data = NULL;
91 		vdrop(de->de_vnode);
92 	}
93 	TAILQ_REMOVE(&dd->dd_list, de, de_list);
94 	FREE(de, M_DEVFS);
95 }
96 
97 void
98 devfs_purge(struct devfs_dir *dd)
99 {
100 	struct devfs_dirent *de;
101 
102 	for (;;) {
103 		de = TAILQ_FIRST(&dd->dd_list);
104 		if (de == NULL)
105 			break;
106 		devfs_delete(dd, de);
107 	}
108 	FREE(dd, M_DEVFS);
109 }
110 
111 
112 int
113 devfs_populate(struct devfs_mount *dm)
114 {
115 	int i, j;
116 	dev_t dev, pdev;
117 	struct devfs_dir *dd;
118 	struct devfs_dirent *de;
119 	char *q, *s;
120 
121 	while (dm->dm_generation != devfs_generation) {
122 		dm->dm_generation = devfs_generation;
123 		for (i = 0; i < NDEVINO; i++) {
124 			dev = devfs_inot[i];
125 			de = dm->dm_dirent[i];
126 			if (dev == NULL && de != NULL) {
127 #if 0
128 				printf("Del ino%d %s\n", i, de->de_dirent->d_name);
129 #endif
130 				dd = de->de_dir;
131 				dm->dm_dirent[i] = NULL;
132 				TAILQ_REMOVE(&dd->dd_list, de, de_list);
133 				if (de->de_vnode) {
134 					de->de_vnode->v_data = NULL;
135 					vdrop(de->de_vnode);
136 				}
137 				FREE(de, M_DEVFS);
138 				continue;
139 			}
140 			if (dev == NULL)
141 				continue;
142 			if (de != NULL)
143 				continue;
144 			dd = dm->dm_basedir;
145 			s = dev->si_name;
146 			for (q = s; *q != '/' && *q != '\0'; q++)
147 				continue;
148 			if (*q == '/') {
149 				continue;
150 			}
151 			de = devfs_newdirent(s, q - s);
152 			if (dev->si_flags & SI_ALIAS) {
153 				de->de_inode = dm->dm_inode++;
154 				de->de_uid = 0;
155 				de->de_gid = 0;
156 				de->de_mode = 0642;
157 				de->de_dirent->d_type = DT_LNK;
158 				pdev = dev->si_drv1;
159 				j = strlen(pdev->si_name) + 1;
160 				MALLOC(de->de_symlink, char *, j, M_DEVFS, M_WAITOK);
161 				bcopy(pdev->si_name, de->de_symlink, j);
162 			} else {
163 				de->de_inode = i;
164 				de->de_uid = dev->si_uid;
165 				de->de_gid = dev->si_gid;
166 				de->de_mode = dev->si_mode;
167 				de->de_dirent->d_type = DT_CHR;
168 				dm->dm_dirent[i] = de;
169 			}
170 			TAILQ_INSERT_TAIL(&dd->dd_list, de, de_list);
171 #if 0
172 			printf("Add ino%d %s\n", i, dev->si_name);
173 #endif
174 		}
175 	}
176 	return (0);
177 }
178 
179 dev_t devfs_inot[NDEVINO];
180 int devfs_nino = 3;
181 unsigned devfs_generation;
182 
183 static void
184 devfs_create(dev_t dev)
185 {
186 	if (dev->si_inode == 0 && devfs_nino < NDEVINO)
187 		dev->si_inode = devfs_nino++;
188 	if (dev->si_inode == 0) {
189 		printf("NDEVINO too small\n");
190 		return;
191 	}
192 	devfs_inot[dev->si_inode] = dev;
193 	devfs_generation++;
194 }
195 
196 static void
197 devfs_remove(dev_t dev)
198 {
199 	devfs_inot[dev->si_inode] = NULL;
200 	devfs_generation++;
201 }
202 
203 devfs_create_t *devfs_create_hook = devfs_create;
204 devfs_remove_t *devfs_remove_hook = devfs_remove;
205 
206 int
207 devfs_stdclone(char *name, char **namep, char *stem, int *unit)
208 {
209 	int u, i;
210 
211 	if (bcmp(stem, name, strlen(stem)) != 0)
212 		return (0);
213 	i = strlen(stem);
214 	if (!isdigit(name[i]))
215 		return (0);
216 	u = 0;
217 	while (isdigit(name[i])) {
218 		u *= 10;
219 		u += name[i++] - '0';
220 	}
221 	*unit = u;
222 	if (namep)
223 		*namep = &name[i];
224 	if (name[i])
225 		return (2);
226 	return (1);
227 }
228