devfs_devs.c revision 65132
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: head/sys/fs/devfs/devfs_devs.c 65132 2000-08-27 14:46:36Z phk $
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
44struct devfs_dirent *
45devfs_find(struct devfs_dirent *dd, const char *name, int namelen)
46{
47	struct devfs_dirent *de;
48
49	TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
50		if (namelen != de->de_dirent->d_namlen)
51			continue;
52		if (bcmp(name, de->de_dirent->d_name, namelen) != 0)
53			continue;
54		break;
55	}
56	return (de);
57}
58
59struct devfs_dirent *
60devfs_newdirent(char *name, int namelen)
61{
62	int i;
63	struct devfs_dirent *de;
64	struct dirent d;
65
66	d.d_namlen = namelen;
67	i = sizeof (*de) + GENERIC_DIRSIZ(&d);
68	MALLOC(de, struct devfs_dirent *, i, M_DEVFS, M_WAITOK);
69	bzero(de, i);
70	de->de_dirent = (struct dirent *)(de + 1);
71	de->de_dirent->d_namlen = namelen;
72	de->de_dirent->d_reclen = GENERIC_DIRSIZ(&d);
73	bcopy(name, de->de_dirent->d_name, namelen + 1);
74	nanotime(&de->de_ctime);
75	de->de_mtime = de->de_atime = de->de_ctime;
76	de->de_links = 1;
77	return (de);
78}
79
80struct devfs_dirent *
81devfs_vmkdir(char *name, int namelen, struct devfs_dirent *dotdot)
82{
83	struct devfs_dirent *dd;
84	struct devfs_dirent *de;
85
86	dd = devfs_newdirent(name, namelen);
87
88	TAILQ_INIT(&dd->de_dlist);
89
90	dd->de_dirent->d_type = DT_DIR;
91	dd->de_mode = 0755;
92	dd->de_links = 2;
93	dd->de_dir = dd;
94
95	de = devfs_newdirent(".", 1);
96	de->de_dirent->d_type = DT_DIR;
97	de->de_dir = dd;
98	de->de_flags |= DE_DOT;
99	TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
100
101	de = devfs_newdirent("..", 2);
102	de->de_dirent->d_type = DT_DIR;
103	if (dotdot == NULL)
104		de->de_dir = dd;
105	else
106		de->de_dir = dotdot;
107	de->de_flags |= DE_DOTDOT;
108	TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
109
110	return (dd);
111}
112
113static void
114devfs_delete(struct devfs_dirent *dd, struct devfs_dirent *de)
115{
116
117	if (de->de_symlink) {
118		FREE(de->de_symlink, M_DEVFS);
119		de->de_symlink = NULL;
120	}
121	if (de->de_vnode) {
122		de->de_vnode->v_data = NULL;
123		vdrop(de->de_vnode);
124	}
125	TAILQ_REMOVE(&dd->de_dlist, de, de_list);
126	FREE(de, M_DEVFS);
127}
128
129void
130devfs_purge(struct devfs_dirent *dd)
131{
132	struct devfs_dirent *de;
133
134	for (;;) {
135		de = TAILQ_FIRST(&dd->de_dlist);
136		if (de == NULL)
137			break;
138		devfs_delete(dd, de);
139	}
140	FREE(dd, M_DEVFS);
141}
142
143
144int
145devfs_populate(struct devfs_mount *dm)
146{
147	int i, j;
148	dev_t dev, pdev;
149	struct devfs_dirent *dd;
150	struct devfs_dirent *de;
151	char *q, *s;
152
153	while (dm->dm_generation != devfs_generation) {
154		dm->dm_generation = devfs_generation;
155		for (i = 0; i < NDEVINO; i++) {
156			dev = devfs_inot[i];
157			de = dm->dm_dirent[i];
158			if (dev == NULL && de == DE_DELETED) {
159				dm->dm_dirent[i] = NULL;
160				continue;
161			}
162			if (dev == NULL && de != NULL) {
163				dd = de->de_dir;
164				dm->dm_dirent[i] = NULL;
165				TAILQ_REMOVE(&dd->de_dlist, de, de_list);
166				if (de->de_vnode) {
167					de->de_vnode->v_data = NULL;
168					vdrop(de->de_vnode);
169				}
170				FREE(de, M_DEVFS);
171				continue;
172			}
173			if (dev == NULL)
174				continue;
175			if (de != NULL)
176				continue;
177			dd = dm->dm_basedir;
178			s = dev->si_name;
179			for (;;) {
180				for (q = s; *q != '/' && *q != '\0'; q++)
181					continue;
182				if (*q != '/')
183					break;
184				de = devfs_find(dd, s, q - s);
185				if (de == NULL) {
186					de = devfs_vmkdir(s, q - s, dd);
187					de->de_inode = dm->dm_inode++;
188					TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
189					dd->de_links++;
190				}
191				s = q + 1;
192				dd = de;
193			}
194			de = devfs_newdirent(s, q - s);
195			if (dev->si_flags & SI_ALIAS) {
196				de->de_inode = dm->dm_inode++;
197				de->de_uid = 0;
198				de->de_gid = 0;
199				de->de_mode = 0666;
200				de->de_dirent->d_type = DT_LNK;
201				pdev = dev->si_drv1;
202				j = strlen(pdev->si_name) + 1;
203				MALLOC(de->de_symlink, char *, j, M_DEVFS, M_WAITOK);
204				bcopy(pdev->si_name, de->de_symlink, j);
205			} else {
206				de->de_inode = i;
207				de->de_uid = dev->si_uid;
208				de->de_gid = dev->si_gid;
209				de->de_mode = dev->si_mode;
210				de->de_dirent->d_type = DT_CHR;
211			}
212			dm->dm_dirent[i] = de;
213			de->de_dir = dd;
214			TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
215#if 0
216			printf("Add ino%d %s\n", i, dev->si_name);
217#endif
218		}
219	}
220	return (0);
221}
222
223dev_t devfs_inot[NDEVINO];
224int devfs_nino = 3;
225unsigned devfs_generation;
226
227static void
228devfs_create(dev_t dev)
229{
230	if (dev->si_inode == 0 && devfs_nino < NDEVINO)
231		dev->si_inode = devfs_nino++;
232	if (dev->si_inode == 0) {
233		printf("NDEVINO too small\n");
234		return;
235	}
236	devfs_inot[dev->si_inode] = dev;
237	devfs_generation++;
238}
239
240static void
241devfs_remove(dev_t dev)
242{
243	devfs_inot[dev->si_inode] = NULL;
244	devfs_generation++;
245}
246
247devfs_create_t *devfs_create_hook = devfs_create;
248devfs_remove_t *devfs_remove_hook = devfs_remove;
249
250int
251devfs_stdclone(char *name, char **namep, char *stem, int *unit)
252{
253	int u, i;
254
255	if (bcmp(stem, name, strlen(stem)) != 0)
256		return (0);
257	i = strlen(stem);
258	if (!isdigit(name[i]))
259		return (0);
260	u = 0;
261	while (isdigit(name[i])) {
262		u *= 10;
263		u += name[i++] - '0';
264	}
265	*unit = u;
266	if (namep)
267		*namep = &name[i];
268	if (name[i])
269		return (2);
270	return (1);
271}
272