xref: /freebsd/sys/fs/devfs/devfs_devs.c (revision c32d0a1dcdc8b0d797a12a1e9249a06eb55d9912)
13f54a085SPoul-Henning Kamp #define DEBUG 1
23f54a085SPoul-Henning Kamp /*
33f54a085SPoul-Henning Kamp  * Copyright (c) 2000
43f54a085SPoul-Henning Kamp  *	Poul-Henning Kamp.  All rights reserved.
53f54a085SPoul-Henning Kamp  *
63f54a085SPoul-Henning Kamp  * Redistribution and use in source and binary forms, with or without
73f54a085SPoul-Henning Kamp  * modification, are permitted provided that the following conditions
83f54a085SPoul-Henning Kamp  * are met:
93f54a085SPoul-Henning Kamp  * 1. Redistributions of source code must retain the above copyright
103f54a085SPoul-Henning Kamp  *    notice, this list of conditions and the following disclaimer.
113f54a085SPoul-Henning Kamp  * 2. Neither the name of the University nor the names of its contributors
123f54a085SPoul-Henning Kamp  *    may be used to endorse or promote products derived from this software
133f54a085SPoul-Henning Kamp  *    without specific prior written permission.
143f54a085SPoul-Henning Kamp  *
153f54a085SPoul-Henning Kamp  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
163f54a085SPoul-Henning Kamp  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
173f54a085SPoul-Henning Kamp  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
183f54a085SPoul-Henning Kamp  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
193f54a085SPoul-Henning Kamp  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
203f54a085SPoul-Henning Kamp  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
213f54a085SPoul-Henning Kamp  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
223f54a085SPoul-Henning Kamp  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
233f54a085SPoul-Henning Kamp  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
243f54a085SPoul-Henning Kamp  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
253f54a085SPoul-Henning Kamp  * SUCH DAMAGE.
263f54a085SPoul-Henning Kamp  *
273f54a085SPoul-Henning Kamp  * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vfsops.c 1.36
283f54a085SPoul-Henning Kamp  *
293f54a085SPoul-Henning Kamp  * $FreeBSD$
303f54a085SPoul-Henning Kamp  */
313f54a085SPoul-Henning Kamp 
323f54a085SPoul-Henning Kamp #include <sys/param.h>
333f54a085SPoul-Henning Kamp #include <sys/systm.h>
343f54a085SPoul-Henning Kamp #include <sys/dirent.h>
353f54a085SPoul-Henning Kamp #include <sys/conf.h>
363f54a085SPoul-Henning Kamp #include <sys/vnode.h>
373f54a085SPoul-Henning Kamp #include <sys/malloc.h>
383f54a085SPoul-Henning Kamp #include <sys/eventhandler.h>
393f54a085SPoul-Henning Kamp #include <sys/ctype.h>
403f54a085SPoul-Henning Kamp 
413f54a085SPoul-Henning Kamp #define DEVFS_INTERN
423f54a085SPoul-Henning Kamp #include <fs/devfs/devfs.h>
433f54a085SPoul-Henning Kamp 
443f54a085SPoul-Henning Kamp struct devfs_dirent *
45c32d0a1dSPoul-Henning Kamp devfs_find(struct devfs_dirent *dd, const char *name, int namelen)
46c32d0a1dSPoul-Henning Kamp {
47c32d0a1dSPoul-Henning Kamp 	struct devfs_dirent *de;
48c32d0a1dSPoul-Henning Kamp 
49c32d0a1dSPoul-Henning Kamp 	TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
50c32d0a1dSPoul-Henning Kamp 		if (namelen != de->de_dirent->d_namlen)
51c32d0a1dSPoul-Henning Kamp 			continue;
52c32d0a1dSPoul-Henning Kamp 		if (bcmp(name, de->de_dirent->d_name, namelen) != 0)
53c32d0a1dSPoul-Henning Kamp 			continue;
54c32d0a1dSPoul-Henning Kamp 		break;
55c32d0a1dSPoul-Henning Kamp 	}
56c32d0a1dSPoul-Henning Kamp 	return (de);
57c32d0a1dSPoul-Henning Kamp }
58c32d0a1dSPoul-Henning Kamp 
59c32d0a1dSPoul-Henning Kamp struct devfs_dirent *
603f54a085SPoul-Henning Kamp devfs_newdirent(char *name, int namelen)
613f54a085SPoul-Henning Kamp {
623f54a085SPoul-Henning Kamp 	int i;
633f54a085SPoul-Henning Kamp 	struct devfs_dirent *de;
643f54a085SPoul-Henning Kamp 	struct dirent d;
653f54a085SPoul-Henning Kamp 
663f54a085SPoul-Henning Kamp 	d.d_namlen = namelen;
673f54a085SPoul-Henning Kamp 	i = sizeof (*de) + GENERIC_DIRSIZ(&d);
683f54a085SPoul-Henning Kamp 	MALLOC(de, struct devfs_dirent *, i, M_DEVFS, M_WAITOK);
693f54a085SPoul-Henning Kamp 	bzero(de, i);
703f54a085SPoul-Henning Kamp 	de->de_dirent = (struct dirent *)(de + 1);
713f54a085SPoul-Henning Kamp 	de->de_dirent->d_namlen = namelen;
723f54a085SPoul-Henning Kamp 	de->de_dirent->d_reclen = GENERIC_DIRSIZ(&d);
733f54a085SPoul-Henning Kamp 	bcopy(name, de->de_dirent->d_name, namelen + 1);
743f54a085SPoul-Henning Kamp 	nanotime(&de->de_ctime);
75a481b90bSPoul-Henning Kamp 	de->de_mtime = de->de_atime = de->de_ctime;
76a481b90bSPoul-Henning Kamp 	de->de_links = 1;
773f54a085SPoul-Henning Kamp 	return (de);
783f54a085SPoul-Henning Kamp }
793f54a085SPoul-Henning Kamp 
80a481b90bSPoul-Henning Kamp struct devfs_dirent *
81a481b90bSPoul-Henning Kamp devfs_vmkdir(char *name, int namelen, struct devfs_dirent *dotdot)
823f54a085SPoul-Henning Kamp {
83a481b90bSPoul-Henning Kamp 	struct devfs_dirent *dd;
843f54a085SPoul-Henning Kamp 	struct devfs_dirent *de;
853f54a085SPoul-Henning Kamp 
86a481b90bSPoul-Henning Kamp 	dd = devfs_newdirent(name, namelen);
87a481b90bSPoul-Henning Kamp 
88a481b90bSPoul-Henning Kamp 	TAILQ_INIT(&dd->de_dlist);
89a481b90bSPoul-Henning Kamp 
90a481b90bSPoul-Henning Kamp 	dd->de_dirent->d_type = DT_DIR;
91a481b90bSPoul-Henning Kamp 	dd->de_mode = 0755;
92a481b90bSPoul-Henning Kamp 	dd->de_links = 2;
93a481b90bSPoul-Henning Kamp 	dd->de_dir = dd;
943f54a085SPoul-Henning Kamp 
953f54a085SPoul-Henning Kamp 	de = devfs_newdirent(".", 1);
963f54a085SPoul-Henning Kamp 	de->de_dirent->d_type = DT_DIR;
97a481b90bSPoul-Henning Kamp 	de->de_dir = dd;
98a481b90bSPoul-Henning Kamp 	de->de_flags |= DE_DOT;
99a481b90bSPoul-Henning Kamp 	TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
100a481b90bSPoul-Henning Kamp 
101a481b90bSPoul-Henning Kamp 	de = devfs_newdirent("..", 2);
102a481b90bSPoul-Henning Kamp 	de->de_dirent->d_type = DT_DIR;
103a481b90bSPoul-Henning Kamp 	if (dotdot == NULL)
104a481b90bSPoul-Henning Kamp 		de->de_dir = dd;
105a481b90bSPoul-Henning Kamp 	else
106a481b90bSPoul-Henning Kamp 		de->de_dir = dotdot;
107a481b90bSPoul-Henning Kamp 	de->de_flags |= DE_DOTDOT;
108a481b90bSPoul-Henning Kamp 	TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
109a481b90bSPoul-Henning Kamp 
1103f54a085SPoul-Henning Kamp 	return (dd);
1113f54a085SPoul-Henning Kamp }
1123f54a085SPoul-Henning Kamp 
113a481b90bSPoul-Henning Kamp static void
114a481b90bSPoul-Henning Kamp devfs_delete(struct devfs_dirent *dd, struct devfs_dirent *de)
1153f54a085SPoul-Henning Kamp {
1163f54a085SPoul-Henning Kamp 
1173f54a085SPoul-Henning Kamp 	if (de->de_symlink) {
1183f54a085SPoul-Henning Kamp 		FREE(de->de_symlink, M_DEVFS);
1193f54a085SPoul-Henning Kamp 		de->de_symlink = NULL;
1203f54a085SPoul-Henning Kamp 	}
1213f54a085SPoul-Henning Kamp 	if (de->de_vnode) {
1223f54a085SPoul-Henning Kamp 		de->de_vnode->v_data = NULL;
1233f54a085SPoul-Henning Kamp 		vdrop(de->de_vnode);
1243f54a085SPoul-Henning Kamp 	}
125a481b90bSPoul-Henning Kamp 	TAILQ_REMOVE(&dd->de_dlist, de, de_list);
1263f54a085SPoul-Henning Kamp 	FREE(de, M_DEVFS);
1273f54a085SPoul-Henning Kamp }
1283f54a085SPoul-Henning Kamp 
1293f54a085SPoul-Henning Kamp void
130a481b90bSPoul-Henning Kamp devfs_purge(struct devfs_dirent *dd)
1313f54a085SPoul-Henning Kamp {
1323f54a085SPoul-Henning Kamp 	struct devfs_dirent *de;
1333f54a085SPoul-Henning Kamp 
1343f54a085SPoul-Henning Kamp 	for (;;) {
135a481b90bSPoul-Henning Kamp 		de = TAILQ_FIRST(&dd->de_dlist);
1363f54a085SPoul-Henning Kamp 		if (de == NULL)
1373f54a085SPoul-Henning Kamp 			break;
1383f54a085SPoul-Henning Kamp 		devfs_delete(dd, de);
1393f54a085SPoul-Henning Kamp 	}
1403f54a085SPoul-Henning Kamp 	FREE(dd, M_DEVFS);
1413f54a085SPoul-Henning Kamp }
1423f54a085SPoul-Henning Kamp 
1433f54a085SPoul-Henning Kamp 
1443f54a085SPoul-Henning Kamp int
1453f54a085SPoul-Henning Kamp devfs_populate(struct devfs_mount *dm)
1463f54a085SPoul-Henning Kamp {
1473f54a085SPoul-Henning Kamp 	int i, j;
1483f54a085SPoul-Henning Kamp 	dev_t dev, pdev;
149a481b90bSPoul-Henning Kamp 	struct devfs_dirent *dd;
1503f54a085SPoul-Henning Kamp 	struct devfs_dirent *de;
1513f54a085SPoul-Henning Kamp 	char *q, *s;
1523f54a085SPoul-Henning Kamp 
1533f54a085SPoul-Henning Kamp 	while (dm->dm_generation != devfs_generation) {
1543f54a085SPoul-Henning Kamp 		dm->dm_generation = devfs_generation;
1553f54a085SPoul-Henning Kamp 		for (i = 0; i < NDEVINO; i++) {
1563f54a085SPoul-Henning Kamp 			dev = devfs_inot[i];
1573f54a085SPoul-Henning Kamp 			de = dm->dm_dirent[i];
158a481b90bSPoul-Henning Kamp 			if (dev == NULL && de == DE_DELETED) {
159a481b90bSPoul-Henning Kamp 				dm->dm_dirent[i] = NULL;
160a481b90bSPoul-Henning Kamp 				continue;
161a481b90bSPoul-Henning Kamp 			}
1623f54a085SPoul-Henning Kamp 			if (dev == NULL && de != NULL) {
1633f54a085SPoul-Henning Kamp 				dd = de->de_dir;
1643f54a085SPoul-Henning Kamp 				dm->dm_dirent[i] = NULL;
165a481b90bSPoul-Henning Kamp 				TAILQ_REMOVE(&dd->de_dlist, de, de_list);
1663f54a085SPoul-Henning Kamp 				if (de->de_vnode) {
1673f54a085SPoul-Henning Kamp 					de->de_vnode->v_data = NULL;
1683f54a085SPoul-Henning Kamp 					vdrop(de->de_vnode);
1693f54a085SPoul-Henning Kamp 				}
1703f54a085SPoul-Henning Kamp 				FREE(de, M_DEVFS);
1713f54a085SPoul-Henning Kamp 				continue;
1723f54a085SPoul-Henning Kamp 			}
1733f54a085SPoul-Henning Kamp 			if (dev == NULL)
1743f54a085SPoul-Henning Kamp 				continue;
1753f54a085SPoul-Henning Kamp 			if (de != NULL)
1763f54a085SPoul-Henning Kamp 				continue;
1773f54a085SPoul-Henning Kamp 			dd = dm->dm_basedir;
1783f54a085SPoul-Henning Kamp 			s = dev->si_name;
179c32d0a1dSPoul-Henning Kamp 			for (;;) {
1803f54a085SPoul-Henning Kamp 				for (q = s; *q != '/' && *q != '\0'; q++)
1813f54a085SPoul-Henning Kamp 					continue;
182c32d0a1dSPoul-Henning Kamp 				if (*q != '/')
183c32d0a1dSPoul-Henning Kamp 					break;
184c32d0a1dSPoul-Henning Kamp 				de = devfs_find(dd, s, q - s);
185c32d0a1dSPoul-Henning Kamp 				if (de == NULL) {
186a481b90bSPoul-Henning Kamp 					de = devfs_vmkdir(s, q - s, dd);
187a481b90bSPoul-Henning Kamp 					de->de_inode = dm->dm_inode++;
188a481b90bSPoul-Henning Kamp 					TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
189a481b90bSPoul-Henning Kamp 					dd->de_links++;
190c32d0a1dSPoul-Henning Kamp 				}
191a481b90bSPoul-Henning Kamp 				s = q + 1;
192a481b90bSPoul-Henning Kamp 				dd = de;
1933f54a085SPoul-Henning Kamp 			}
1943f54a085SPoul-Henning Kamp 			de = devfs_newdirent(s, q - s);
1953f54a085SPoul-Henning Kamp 			if (dev->si_flags & SI_ALIAS) {
1963f54a085SPoul-Henning Kamp 				de->de_inode = dm->dm_inode++;
1973f54a085SPoul-Henning Kamp 				de->de_uid = 0;
1983f54a085SPoul-Henning Kamp 				de->de_gid = 0;
199a481b90bSPoul-Henning Kamp 				de->de_mode = 0666;
2003f54a085SPoul-Henning Kamp 				de->de_dirent->d_type = DT_LNK;
2013f54a085SPoul-Henning Kamp 				pdev = dev->si_drv1;
2023f54a085SPoul-Henning Kamp 				j = strlen(pdev->si_name) + 1;
2033f54a085SPoul-Henning Kamp 				MALLOC(de->de_symlink, char *, j, M_DEVFS, M_WAITOK);
2043f54a085SPoul-Henning Kamp 				bcopy(pdev->si_name, de->de_symlink, j);
2053f54a085SPoul-Henning Kamp 			} else {
2063f54a085SPoul-Henning Kamp 				de->de_inode = i;
2073f54a085SPoul-Henning Kamp 				de->de_uid = dev->si_uid;
2083f54a085SPoul-Henning Kamp 				de->de_gid = dev->si_gid;
2093f54a085SPoul-Henning Kamp 				de->de_mode = dev->si_mode;
2103f54a085SPoul-Henning Kamp 				de->de_dirent->d_type = DT_CHR;
2113f54a085SPoul-Henning Kamp 			}
212a481b90bSPoul-Henning Kamp 			dm->dm_dirent[i] = de;
213c32d0a1dSPoul-Henning Kamp 			de->de_dir = dd;
214a481b90bSPoul-Henning Kamp 			TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
2153f54a085SPoul-Henning Kamp #if 0
2163f54a085SPoul-Henning Kamp 			printf("Add ino%d %s\n", i, dev->si_name);
2173f54a085SPoul-Henning Kamp #endif
2183f54a085SPoul-Henning Kamp 		}
2193f54a085SPoul-Henning Kamp 	}
2203f54a085SPoul-Henning Kamp 	return (0);
2213f54a085SPoul-Henning Kamp }
2223f54a085SPoul-Henning Kamp 
2233f54a085SPoul-Henning Kamp dev_t devfs_inot[NDEVINO];
2243f54a085SPoul-Henning Kamp int devfs_nino = 3;
2253f54a085SPoul-Henning Kamp unsigned devfs_generation;
2263f54a085SPoul-Henning Kamp 
2273f54a085SPoul-Henning Kamp static void
2283f54a085SPoul-Henning Kamp devfs_create(dev_t dev)
2293f54a085SPoul-Henning Kamp {
2303f54a085SPoul-Henning Kamp 	if (dev->si_inode == 0 && devfs_nino < NDEVINO)
2313f54a085SPoul-Henning Kamp 		dev->si_inode = devfs_nino++;
2323f54a085SPoul-Henning Kamp 	if (dev->si_inode == 0) {
2333f54a085SPoul-Henning Kamp 		printf("NDEVINO too small\n");
2343f54a085SPoul-Henning Kamp 		return;
2353f54a085SPoul-Henning Kamp 	}
2363f54a085SPoul-Henning Kamp 	devfs_inot[dev->si_inode] = dev;
2373f54a085SPoul-Henning Kamp 	devfs_generation++;
2383f54a085SPoul-Henning Kamp }
2393f54a085SPoul-Henning Kamp 
2403f54a085SPoul-Henning Kamp static void
2413f54a085SPoul-Henning Kamp devfs_remove(dev_t dev)
2423f54a085SPoul-Henning Kamp {
2433f54a085SPoul-Henning Kamp 	devfs_inot[dev->si_inode] = NULL;
2443f54a085SPoul-Henning Kamp 	devfs_generation++;
2453f54a085SPoul-Henning Kamp }
2463f54a085SPoul-Henning Kamp 
2473f54a085SPoul-Henning Kamp devfs_create_t *devfs_create_hook = devfs_create;
2483f54a085SPoul-Henning Kamp devfs_remove_t *devfs_remove_hook = devfs_remove;
2493f54a085SPoul-Henning Kamp 
2503f54a085SPoul-Henning Kamp int
2513f54a085SPoul-Henning Kamp devfs_stdclone(char *name, char **namep, char *stem, int *unit)
2523f54a085SPoul-Henning Kamp {
2533f54a085SPoul-Henning Kamp 	int u, i;
2543f54a085SPoul-Henning Kamp 
2553f54a085SPoul-Henning Kamp 	if (bcmp(stem, name, strlen(stem)) != 0)
2563f54a085SPoul-Henning Kamp 		return (0);
2573f54a085SPoul-Henning Kamp 	i = strlen(stem);
2583f54a085SPoul-Henning Kamp 	if (!isdigit(name[i]))
2593f54a085SPoul-Henning Kamp 		return (0);
2603f54a085SPoul-Henning Kamp 	u = 0;
2613f54a085SPoul-Henning Kamp 	while (isdigit(name[i])) {
2623f54a085SPoul-Henning Kamp 		u *= 10;
2633f54a085SPoul-Henning Kamp 		u += name[i++] - '0';
2643f54a085SPoul-Henning Kamp 	}
2653f54a085SPoul-Henning Kamp 	*unit = u;
2663f54a085SPoul-Henning Kamp 	if (namep)
2673f54a085SPoul-Henning Kamp 		*namep = &name[i];
2683f54a085SPoul-Henning Kamp 	if (name[i])
2693f54a085SPoul-Henning Kamp 		return (2);
2703f54a085SPoul-Henning Kamp 	return (1);
2713f54a085SPoul-Henning Kamp }
272