xref: /rk3399_ARM-atf/lib/debugfs/dev.c (revision 07a103180bd855957a64c0f922e85d7d9dd6de50)
10ca3913dSOlivier Deprez /*
2c56a85d0SHarrison Mutai  * Copyright (c) 2019-2025, Arm Limited. All rights reserved.
30ca3913dSOlivier Deprez  *
40ca3913dSOlivier Deprez  * SPDX-License-Identifier: BSD-3-Clause
50ca3913dSOlivier Deprez  */
60ca3913dSOlivier Deprez 
70ca3913dSOlivier Deprez #include <cdefs.h>
80ca3913dSOlivier Deprez #include <common/debug.h>
90ca3913dSOlivier Deprez #include <lib/debugfs.h>
100ca3913dSOlivier Deprez #include <string.h>
110ca3913dSOlivier Deprez 
120ca3913dSOlivier Deprez #include "dev.h"
130ca3913dSOlivier Deprez 
140ca3913dSOlivier Deprez #define NR_MOUNT_POINTS		4
150ca3913dSOlivier Deprez 
160ca3913dSOlivier Deprez struct mount_point {
170ca3913dSOlivier Deprez 	chan_t	*new;
180ca3913dSOlivier Deprez 	chan_t	*old;
190ca3913dSOlivier Deprez };
200ca3913dSOlivier Deprez 
210ca3913dSOlivier Deprez /* This array contains all the available channels of the filesystem.
220ca3913dSOlivier Deprez  * A file descriptor is the index of a specific channel in this array.
230ca3913dSOlivier Deprez  */
240ca3913dSOlivier Deprez static chan_t fdset[NR_CHANS];
250ca3913dSOlivier Deprez 
260ca3913dSOlivier Deprez /* This array contains all the available mount points of the filesystem. */
270ca3913dSOlivier Deprez static struct mount_point mount_points[NR_MOUNT_POINTS];
280ca3913dSOlivier Deprez 
290ca3913dSOlivier Deprez /* This variable stores the channel associated to the root directory. */
300ca3913dSOlivier Deprez static chan_t slash_channel;
310ca3913dSOlivier Deprez 
320ca3913dSOlivier Deprez /* This function creates a channel from a device index and registers
330ca3913dSOlivier Deprez  * it to fdset.
340ca3913dSOlivier Deprez  */
create_new_channel(unsigned char index)350ca3913dSOlivier Deprez static chan_t *create_new_channel(unsigned char index)
360ca3913dSOlivier Deprez {
370ca3913dSOlivier Deprez 	chan_t *channel = NULL;
380ca3913dSOlivier Deprez 	int i;
390ca3913dSOlivier Deprez 
400ca3913dSOlivier Deprez 	for (i = 0; i < NR_CHANS; i++) {
410ca3913dSOlivier Deprez 		if (fdset[i].index == NODEV) {
420ca3913dSOlivier Deprez 			channel = &fdset[i];
430ca3913dSOlivier Deprez 			channel->index = index;
440ca3913dSOlivier Deprez 			break;
450ca3913dSOlivier Deprez 		}
460ca3913dSOlivier Deprez 	}
470ca3913dSOlivier Deprez 
480ca3913dSOlivier Deprez 	return channel;
490ca3913dSOlivier Deprez }
500ca3913dSOlivier Deprez 
510ca3913dSOlivier Deprez /*******************************************************************************
520ca3913dSOlivier Deprez  * This function returns a pointer to an existing channel in fdset from a file
530ca3913dSOlivier Deprez  * descriptor.
540ca3913dSOlivier Deprez  ******************************************************************************/
fd_to_channel(int fd)550ca3913dSOlivier Deprez static chan_t *fd_to_channel(int fd)
560ca3913dSOlivier Deprez {
570ca3913dSOlivier Deprez 	if ((fd < 0) || (fd >= NR_CHANS) || (fdset[fd].index == NODEV)) {
580ca3913dSOlivier Deprez 		return NULL;
590ca3913dSOlivier Deprez 	}
600ca3913dSOlivier Deprez 
610ca3913dSOlivier Deprez 	return &fdset[fd];
620ca3913dSOlivier Deprez }
630ca3913dSOlivier Deprez 
640ca3913dSOlivier Deprez /*******************************************************************************
650ca3913dSOlivier Deprez  * This function returns a file descriptor from a channel.
660ca3913dSOlivier Deprez  * The caller must be sure that the channel is registered in fdset.
670ca3913dSOlivier Deprez  ******************************************************************************/
channel_to_fd(chan_t * channel)680ca3913dSOlivier Deprez static int channel_to_fd(chan_t *channel)
690ca3913dSOlivier Deprez {
700ca3913dSOlivier Deprez 	return (channel == NULL) ? -1 : (channel - fdset);
710ca3913dSOlivier Deprez }
720ca3913dSOlivier Deprez 
730ca3913dSOlivier Deprez /*******************************************************************************
740ca3913dSOlivier Deprez  * This function checks the validity of a mode.
750ca3913dSOlivier Deprez  ******************************************************************************/
is_valid_mode(int mode)760ca3913dSOlivier Deprez static bool is_valid_mode(int mode)
770ca3913dSOlivier Deprez {
780ca3913dSOlivier Deprez 	if ((mode & O_READ) && (mode & (O_WRITE | O_RDWR))) {
790ca3913dSOlivier Deprez 		return false;
800ca3913dSOlivier Deprez 	}
810ca3913dSOlivier Deprez 	if ((mode & O_WRITE) && (mode & (O_READ | O_RDWR))) {
820ca3913dSOlivier Deprez 		return false;
830ca3913dSOlivier Deprez 	}
840ca3913dSOlivier Deprez 	if ((mode & O_RDWR) && (mode & (O_READ | O_WRITE))) {
850ca3913dSOlivier Deprez 		return false;
860ca3913dSOlivier Deprez 	}
870ca3913dSOlivier Deprez 
880ca3913dSOlivier Deprez 	return true;
890ca3913dSOlivier Deprez }
900ca3913dSOlivier Deprez 
910ca3913dSOlivier Deprez /*******************************************************************************
920ca3913dSOlivier Deprez  * This function extracts the next part of the given path contained and puts it
930ca3913dSOlivier Deprez  * in token. It returns a pointer to the remainder of the path.
940ca3913dSOlivier Deprez  ******************************************************************************/
next(const char * path,char * token)950ca3913dSOlivier Deprez static const char *next(const char *path, char *token)
960ca3913dSOlivier Deprez {
970ca3913dSOlivier Deprez 	int index;
980ca3913dSOlivier Deprez 	const char *cursor;
990ca3913dSOlivier Deprez 
1000ca3913dSOlivier Deprez 	while (*path == '/') {
1010ca3913dSOlivier Deprez 		++path;
1020ca3913dSOlivier Deprez 	}
1030ca3913dSOlivier Deprez 
1040ca3913dSOlivier Deprez 	index = 0;
1050ca3913dSOlivier Deprez 	cursor = path;
1060ca3913dSOlivier Deprez 	if (*path != '\0') {
1070ca3913dSOlivier Deprez 		while (*cursor != '/' && *cursor != '\0') {
1080ca3913dSOlivier Deprez 			if (index == NAMELEN) {
1090ca3913dSOlivier Deprez 				return NULL;
1100ca3913dSOlivier Deprez 			}
1110ca3913dSOlivier Deprez 			token[index++] = *cursor++;
1120ca3913dSOlivier Deprez 		}
1130ca3913dSOlivier Deprez 	}
1140ca3913dSOlivier Deprez 	token[index] = '\0';
1150ca3913dSOlivier Deprez 
1160ca3913dSOlivier Deprez 	return cursor;
1170ca3913dSOlivier Deprez }
1180ca3913dSOlivier Deprez 
1190ca3913dSOlivier Deprez /*******************************************************************************
1200ca3913dSOlivier Deprez  * This function returns the driver index in devtab of the driver
1210ca3913dSOlivier Deprez  * identified by id.
1220ca3913dSOlivier Deprez  ******************************************************************************/
get_device_index(int id)1230ca3913dSOlivier Deprez static int get_device_index(int id)
1240ca3913dSOlivier Deprez {
1250ca3913dSOlivier Deprez 	int index;
1260ca3913dSOlivier Deprez 	dev_t * const *dp;
1270ca3913dSOlivier Deprez 
1280ca3913dSOlivier Deprez 	for (index = 0, dp = devtab; *dp && (*dp)->id != id; ++dp) {
1290ca3913dSOlivier Deprez 		index++;
1300ca3913dSOlivier Deprez 	}
1310ca3913dSOlivier Deprez 
1320ca3913dSOlivier Deprez 	if (*dp == NULL) {
1330ca3913dSOlivier Deprez 		return -1;
1340ca3913dSOlivier Deprez 	}
1350ca3913dSOlivier Deprez 
1360ca3913dSOlivier Deprez 	return index;
1370ca3913dSOlivier Deprez }
1380ca3913dSOlivier Deprez 
1390ca3913dSOlivier Deprez /*******************************************************************************
1400ca3913dSOlivier Deprez  * This function clears a given channel fields
1410ca3913dSOlivier Deprez  ******************************************************************************/
channel_clear(chan_t * channel)1420ca3913dSOlivier Deprez static void channel_clear(chan_t *channel)
1430ca3913dSOlivier Deprez {
1440ca3913dSOlivier Deprez 	channel->offset = 0;
1450ca3913dSOlivier Deprez 	channel->qid    = 0;
1460ca3913dSOlivier Deprez 	channel->index  = NODEV;
1470ca3913dSOlivier Deprez 	channel->dev    = 0;
1480ca3913dSOlivier Deprez 	channel->mode   = 0;
1490ca3913dSOlivier Deprez }
1500ca3913dSOlivier Deprez 
1510ca3913dSOlivier Deprez /*******************************************************************************
1520ca3913dSOlivier Deprez  * This function closes the channel pointed to by c.
1530ca3913dSOlivier Deprez  ******************************************************************************/
channel_close(chan_t * channel)1540ca3913dSOlivier Deprez void channel_close(chan_t *channel)
1550ca3913dSOlivier Deprez {
1560ca3913dSOlivier Deprez 	if (channel != NULL) {
1570ca3913dSOlivier Deprez 		channel_clear(channel);
1580ca3913dSOlivier Deprez 	}
1590ca3913dSOlivier Deprez }
1600ca3913dSOlivier Deprez 
1610ca3913dSOlivier Deprez /*******************************************************************************
1620ca3913dSOlivier Deprez  * This function copies data from src to dst after applying the offset of the
1630ca3913dSOlivier Deprez  * channel c. nbytes bytes are expected to be copied unless the data goes over
1640ca3913dSOlivier Deprez  * dst + len.
165*b1f53092SHarrison Mutai  * It returns the actual number of bytes that were copied, or -1 on error.
1660ca3913dSOlivier Deprez  ******************************************************************************/
buf_to_channel(chan_t * channel,void * dst,void * src,size_t nbytes,long len)167c56a85d0SHarrison Mutai int buf_to_channel(chan_t *channel, void *dst, void *src, size_t nbytes, long len)
1680ca3913dSOlivier Deprez {
1690ca3913dSOlivier Deprez 	const char *addr = src;
1700ca3913dSOlivier Deprez 
1710ca3913dSOlivier Deprez 	if ((channel == NULL) || (dst == NULL) || (src == NULL)) {
172*b1f53092SHarrison Mutai 		return -1;
1730ca3913dSOlivier Deprez 	}
1740ca3913dSOlivier Deprez 
1750ca3913dSOlivier Deprez 	if (channel->offset >= len) {
176*b1f53092SHarrison Mutai 		return -1;
1770ca3913dSOlivier Deprez 	}
1780ca3913dSOlivier Deprez 
1790ca3913dSOlivier Deprez 	if ((channel->offset + nbytes) > len) {
1800ca3913dSOlivier Deprez 		nbytes = len - channel->offset;
1810ca3913dSOlivier Deprez 	}
1820ca3913dSOlivier Deprez 
1830ca3913dSOlivier Deprez 	memcpy(dst, addr + channel->offset, nbytes);
1840ca3913dSOlivier Deprez 
1850ca3913dSOlivier Deprez 	channel->offset += nbytes;
1860ca3913dSOlivier Deprez 
1870ca3913dSOlivier Deprez 	return nbytes;
1880ca3913dSOlivier Deprez }
1890ca3913dSOlivier Deprez 
1900ca3913dSOlivier Deprez /*******************************************************************************
1910ca3913dSOlivier Deprez  * This function checks whether a channel (identified by its device index and
1920ca3913dSOlivier Deprez  * qid) is registered as a mount point.
1930ca3913dSOlivier Deprez  * Returns a pointer to the channel it is mounted to when found, NULL otherwise.
1940ca3913dSOlivier Deprez  ******************************************************************************/
mount_point_to_channel(int index,qid_t qid)1950ca3913dSOlivier Deprez static chan_t *mount_point_to_channel(int index, qid_t qid)
1960ca3913dSOlivier Deprez {
1970ca3913dSOlivier Deprez 	chan_t *channel;
1980ca3913dSOlivier Deprez 	struct mount_point *mp;
1990ca3913dSOlivier Deprez 
2000ca3913dSOlivier Deprez 	for (mp = mount_points; mp < &mount_points[NR_MOUNT_POINTS]; mp++) {
2010ca3913dSOlivier Deprez 		channel = mp->new;
2020ca3913dSOlivier Deprez 		if (channel == NULL) {
2030ca3913dSOlivier Deprez 			continue;
2040ca3913dSOlivier Deprez 		}
2050ca3913dSOlivier Deprez 
2060ca3913dSOlivier Deprez 		if ((channel->index == index) && (channel->qid == qid)) {
2070ca3913dSOlivier Deprez 			return mp->old;
2080ca3913dSOlivier Deprez 		}
2090ca3913dSOlivier Deprez 	}
2100ca3913dSOlivier Deprez 
2110ca3913dSOlivier Deprez 	return NULL;
2120ca3913dSOlivier Deprez }
2130ca3913dSOlivier Deprez 
2140ca3913dSOlivier Deprez /*******************************************************************************
2150ca3913dSOlivier Deprez  * This function calls the attach function of the driver identified by id.
2160ca3913dSOlivier Deprez  ******************************************************************************/
attach(int id,int dev)2170ca3913dSOlivier Deprez chan_t *attach(int id, int dev)
2180ca3913dSOlivier Deprez {
2190ca3913dSOlivier Deprez 	/* Get the devtab index for the driver identified by id */
2200ca3913dSOlivier Deprez 	int index = get_device_index(id);
2210ca3913dSOlivier Deprez 
2220ca3913dSOlivier Deprez 	if (index < 0) {
2230ca3913dSOlivier Deprez 		return NULL;
2240ca3913dSOlivier Deprez 	}
2250ca3913dSOlivier Deprez 
2260ca3913dSOlivier Deprez 	return devtab[index]->attach(id, dev);
2270ca3913dSOlivier Deprez }
2280ca3913dSOlivier Deprez 
2290ca3913dSOlivier Deprez /*******************************************************************************
2300ca3913dSOlivier Deprez  * This function is the default implementation of the driver attach function.
2310ca3913dSOlivier Deprez  * It creates a new channel and returns a pointer to it.
2320ca3913dSOlivier Deprez  ******************************************************************************/
devattach(int id,int dev)2330ca3913dSOlivier Deprez chan_t *devattach(int id, int dev)
2340ca3913dSOlivier Deprez {
2350ca3913dSOlivier Deprez 	chan_t *channel;
2360ca3913dSOlivier Deprez 	int index;
2370ca3913dSOlivier Deprez 
2380ca3913dSOlivier Deprez 	index = get_device_index(id);
2390ca3913dSOlivier Deprez 	if (index < 0) {
2400ca3913dSOlivier Deprez 		return NULL;
2410ca3913dSOlivier Deprez 	}
2420ca3913dSOlivier Deprez 
2430ca3913dSOlivier Deprez 	channel = create_new_channel(index);
2440ca3913dSOlivier Deprez 	if (channel == NULL) {
2450ca3913dSOlivier Deprez 		return NULL;
2460ca3913dSOlivier Deprez 	}
2470ca3913dSOlivier Deprez 
2480ca3913dSOlivier Deprez 	channel->dev = dev;
2490ca3913dSOlivier Deprez 	channel->qid = CHDIR;
2500ca3913dSOlivier Deprez 
2510ca3913dSOlivier Deprez 	return channel;
2520ca3913dSOlivier Deprez }
2530ca3913dSOlivier Deprez 
2540ca3913dSOlivier Deprez /*******************************************************************************
2550ca3913dSOlivier Deprez  * This function returns a channel given a path.
2560ca3913dSOlivier Deprez  * It goes through the filesystem, from the root namespace ('/') or from a
2570ca3913dSOlivier Deprez  * device namespace ('#'), switching channel on mount points.
2580ca3913dSOlivier Deprez  ******************************************************************************/
path_to_channel(const char * path,int mode)2590ca3913dSOlivier Deprez chan_t *path_to_channel(const char *path, int mode)
2600ca3913dSOlivier Deprez {
2610ca3913dSOlivier Deprez 	int i, n;
2620ca3913dSOlivier Deprez 	const char *path_next;
2630ca3913dSOlivier Deprez 	chan_t *mnt, *channel;
2640ca3913dSOlivier Deprez 	char elem[NAMELEN];
2650ca3913dSOlivier Deprez 
2660ca3913dSOlivier Deprez 	if (path == NULL) {
2670ca3913dSOlivier Deprez 		return NULL;
2680ca3913dSOlivier Deprez 	}
2690ca3913dSOlivier Deprez 
2700ca3913dSOlivier Deprez 	switch (path[0]) {
2710ca3913dSOlivier Deprez 	case '/':
2720ca3913dSOlivier Deprez 		channel = clone(&slash_channel, NULL);
2730ca3913dSOlivier Deprez 		path_next = path;
2740ca3913dSOlivier Deprez 		break;
2750ca3913dSOlivier Deprez 	case '#':
2760ca3913dSOlivier Deprez 		path_next = next(path + 1, elem);
2770ca3913dSOlivier Deprez 		if (path_next == NULL) {
2780ca3913dSOlivier Deprez 			goto noent;
2790ca3913dSOlivier Deprez 		}
2800ca3913dSOlivier Deprez 
2810ca3913dSOlivier Deprez 		n = 0;
2820ca3913dSOlivier Deprez 		for (i = 1; (elem[i] >= '0') && (elem[i] <= '9'); i++) {
2830ca3913dSOlivier Deprez 			n += elem[i] - '0';
2840ca3913dSOlivier Deprez 		}
2850ca3913dSOlivier Deprez 
2860ca3913dSOlivier Deprez 		if (elem[i] != '\0') {
2870ca3913dSOlivier Deprez 			goto noent;
2880ca3913dSOlivier Deprez 		}
2890ca3913dSOlivier Deprez 
2900ca3913dSOlivier Deprez 		channel = attach(elem[0], n);
2910ca3913dSOlivier Deprez 		break;
2920ca3913dSOlivier Deprez 	default:
2930ca3913dSOlivier Deprez 		return NULL;
2940ca3913dSOlivier Deprez 	}
2950ca3913dSOlivier Deprez 
2960ca3913dSOlivier Deprez 	if (channel == NULL) {
2970ca3913dSOlivier Deprez 		return NULL;
2980ca3913dSOlivier Deprez 	}
2990ca3913dSOlivier Deprez 
3000ca3913dSOlivier Deprez 	for (path_next = next(path_next, elem); *elem;
3010ca3913dSOlivier Deprez 			path_next = next(path_next, elem)) {
3020ca3913dSOlivier Deprez 		if ((channel->qid & CHDIR) == 0) {
3030ca3913dSOlivier Deprez 			goto notfound;
3040ca3913dSOlivier Deprez 		}
3050ca3913dSOlivier Deprez 
3060ca3913dSOlivier Deprez 		if (devtab[channel->index]->walk(channel, elem) < 0) {
3070ca3913dSOlivier Deprez 			channel_close(channel);
3080ca3913dSOlivier Deprez 			goto notfound;
3090ca3913dSOlivier Deprez 		}
3100ca3913dSOlivier Deprez 
3110ca3913dSOlivier Deprez 		mnt = mount_point_to_channel(channel->index, channel->qid);
3120ca3913dSOlivier Deprez 		if (mnt != NULL) {
3130ca3913dSOlivier Deprez 			clone(mnt, channel);
3140ca3913dSOlivier Deprez 		}
3150ca3913dSOlivier Deprez 	}
3160ca3913dSOlivier Deprez 
3170ca3913dSOlivier Deprez 	if (path_next == NULL) {
3180ca3913dSOlivier Deprez 		goto notfound;
3190ca3913dSOlivier Deprez 	}
3200ca3913dSOlivier Deprez 
3210ca3913dSOlivier Deprez 	/* TODO: check mode */
3220ca3913dSOlivier Deprez 	return channel;
3230ca3913dSOlivier Deprez 
3240ca3913dSOlivier Deprez notfound:
3250ca3913dSOlivier Deprez 	channel_close(channel);
3260ca3913dSOlivier Deprez noent:
3270ca3913dSOlivier Deprez 	return NULL;
3280ca3913dSOlivier Deprez }
3290ca3913dSOlivier Deprez 
3300ca3913dSOlivier Deprez /*******************************************************************************
3310ca3913dSOlivier Deprez  * This function calls the clone function of the driver associated to the
3320ca3913dSOlivier Deprez  * channel c.
3330ca3913dSOlivier Deprez  ******************************************************************************/
clone(chan_t * c,chan_t * nc)3340ca3913dSOlivier Deprez chan_t *clone(chan_t *c, chan_t *nc)
3350ca3913dSOlivier Deprez {
336b226c747SZelalem 	if (c->index == NODEV) {
337b226c747SZelalem 		return NULL;
338b226c747SZelalem 	}
339b226c747SZelalem 
3400ca3913dSOlivier Deprez 	return devtab[c->index]->clone(c, nc);
3410ca3913dSOlivier Deprez }
3420ca3913dSOlivier Deprez 
3430ca3913dSOlivier Deprez /*******************************************************************************
3440ca3913dSOlivier Deprez  * This function is the default implementation of the driver clone function.
3450ca3913dSOlivier Deprez  * It creates a new channel and returns a pointer to it.
3460ca3913dSOlivier Deprez  * It clones channel into new_channel.
3470ca3913dSOlivier Deprez  ******************************************************************************/
devclone(chan_t * channel,chan_t * new_channel)3480ca3913dSOlivier Deprez chan_t *devclone(chan_t *channel, chan_t *new_channel)
3490ca3913dSOlivier Deprez {
3500ca3913dSOlivier Deprez 	if (channel == NULL) {
3510ca3913dSOlivier Deprez 		return NULL;
3520ca3913dSOlivier Deprez 	}
3530ca3913dSOlivier Deprez 
3540ca3913dSOlivier Deprez 	if (new_channel == NULL) {
3550ca3913dSOlivier Deprez 		new_channel = create_new_channel(channel->index);
3560ca3913dSOlivier Deprez 		if (new_channel == NULL) {
3570ca3913dSOlivier Deprez 			return NULL;
3580ca3913dSOlivier Deprez 		}
3590ca3913dSOlivier Deprez 	}
3600ca3913dSOlivier Deprez 
3610ca3913dSOlivier Deprez 	new_channel->qid    = channel->qid;
3620ca3913dSOlivier Deprez 	new_channel->dev    = channel->dev;
3630ca3913dSOlivier Deprez 	new_channel->mode   = channel->mode;
3640ca3913dSOlivier Deprez 	new_channel->offset = channel->offset;
3650ca3913dSOlivier Deprez 	new_channel->index  = channel->index;
3660ca3913dSOlivier Deprez 
3670ca3913dSOlivier Deprez 	return new_channel;
3680ca3913dSOlivier Deprez }
3690ca3913dSOlivier Deprez 
3700ca3913dSOlivier Deprez /*******************************************************************************
3710ca3913dSOlivier Deprez  * This function is the default implementation of the driver walk function.
3720ca3913dSOlivier Deprez  * It goes through all the elements of tab using the gen function until a match
3730ca3913dSOlivier Deprez  * is found with name.
3740ca3913dSOlivier Deprez  * If a match is found, it copies the qid of the new directory.
3750ca3913dSOlivier Deprez  ******************************************************************************/
devwalk(chan_t * channel,const char * name,const dirtab_t * tab,int ntab,devgen_t * gen)3760ca3913dSOlivier Deprez int devwalk(chan_t *channel, const char *name, const dirtab_t *tab,
3770ca3913dSOlivier Deprez 	    int ntab, devgen_t *gen)
3780ca3913dSOlivier Deprez {
3790ca3913dSOlivier Deprez 	int i;
3800ca3913dSOlivier Deprez 	dir_t dir;
3810ca3913dSOlivier Deprez 
3820ca3913dSOlivier Deprez 	if ((channel == NULL) || (name == NULL) || (gen == NULL)) {
3830ca3913dSOlivier Deprez 		return -1;
3840ca3913dSOlivier Deprez 	}
3850ca3913dSOlivier Deprez 
3860ca3913dSOlivier Deprez 	if ((name[0] == '.') && (name[1] == '\0')) {
3870ca3913dSOlivier Deprez 		return 1;
3880ca3913dSOlivier Deprez 	}
3890ca3913dSOlivier Deprez 
3900ca3913dSOlivier Deprez 	for (i = 0; ; i++) {
3910ca3913dSOlivier Deprez 		switch ((*gen)(channel, tab, ntab, i, &dir)) {
3920ca3913dSOlivier Deprez 		case 0:
3930ca3913dSOlivier Deprez 			/* Intentional fall-through */
3940ca3913dSOlivier Deprez 		case -1:
3950ca3913dSOlivier Deprez 			return -1;
3960ca3913dSOlivier Deprez 		case 1:
3970ca3913dSOlivier Deprez 			if (strncmp(name, dir.name, NAMELEN) != 0) {
3980ca3913dSOlivier Deprez 				continue;
3990ca3913dSOlivier Deprez 			}
4000ca3913dSOlivier Deprez 			channel->qid = dir.qid;
4010ca3913dSOlivier Deprez 			return 1;
4020ca3913dSOlivier Deprez 		}
4030ca3913dSOlivier Deprez 	}
4040ca3913dSOlivier Deprez }
4050ca3913dSOlivier Deprez 
4060ca3913dSOlivier Deprez /*******************************************************************************
4070ca3913dSOlivier Deprez  * This is a helper function which exposes the content of a directory, element
4080ca3913dSOlivier Deprez  * by element. It is meant to be called until the end of the directory is
4090ca3913dSOlivier Deprez  * reached or an error occurs.
4100ca3913dSOlivier Deprez  * It returns -1 on error, 0 on end of directory and 1 when a new file is found.
4110ca3913dSOlivier Deprez  ******************************************************************************/
dirread(chan_t * channel,dir_t * dir,const dirtab_t * tab,int ntab,devgen_t * gen)4120ca3913dSOlivier Deprez int dirread(chan_t *channel, dir_t *dir, const dirtab_t *tab,
4130ca3913dSOlivier Deprez 	int ntab, devgen_t *gen)
4140ca3913dSOlivier Deprez {
4150ca3913dSOlivier Deprez 	int i, ret;
4160ca3913dSOlivier Deprez 
4170ca3913dSOlivier Deprez 	if ((channel == NULL) || (dir == NULL) || (gen == NULL)) {
4180ca3913dSOlivier Deprez 		return -1;
4190ca3913dSOlivier Deprez 	}
4200ca3913dSOlivier Deprez 
4210ca3913dSOlivier Deprez 	i = channel->offset/sizeof(dir_t);
4220ca3913dSOlivier Deprez 	ret = (*gen)(channel, tab, ntab, i, dir);
4230ca3913dSOlivier Deprez 	if (ret == 1) {
4240ca3913dSOlivier Deprez 		channel->offset += sizeof(dir_t);
4250ca3913dSOlivier Deprez 	}
4260ca3913dSOlivier Deprez 
4270ca3913dSOlivier Deprez 	return ret;
4280ca3913dSOlivier Deprez }
4290ca3913dSOlivier Deprez 
4300ca3913dSOlivier Deprez /*******************************************************************************
4310ca3913dSOlivier Deprez  * This function sets the elements of dir.
4320ca3913dSOlivier Deprez  ******************************************************************************/
make_dir_entry(chan_t * channel,dir_t * dir,const char * name,long length,qid_t qid,unsigned int mode)4330ca3913dSOlivier Deprez void make_dir_entry(chan_t *channel, dir_t *dir,
4340ca3913dSOlivier Deprez 	     const char *name, long length, qid_t qid, unsigned int mode)
4350ca3913dSOlivier Deprez {
4360ca3913dSOlivier Deprez 	if ((channel == NULL) || (dir == NULL) || (name == NULL)) {
4370ca3913dSOlivier Deprez 		return;
4380ca3913dSOlivier Deprez 	}
4390ca3913dSOlivier Deprez 
4400ca3913dSOlivier Deprez 	strlcpy(dir->name, name, sizeof(dir->name));
4410ca3913dSOlivier Deprez 	dir->length = length;
4420ca3913dSOlivier Deprez 	dir->qid = qid;
4430ca3913dSOlivier Deprez 	dir->mode = mode;
4440ca3913dSOlivier Deprez 
4450ca3913dSOlivier Deprez 	if ((qid & CHDIR) != 0) {
4460ca3913dSOlivier Deprez 		dir->mode |= O_DIR;
4470ca3913dSOlivier Deprez 	}
4480ca3913dSOlivier Deprez 
4490ca3913dSOlivier Deprez 	dir->index = channel->index;
4500ca3913dSOlivier Deprez 	dir->dev   = channel->dev;
4510ca3913dSOlivier Deprez }
4520ca3913dSOlivier Deprez 
4530ca3913dSOlivier Deprez /*******************************************************************************
4540ca3913dSOlivier Deprez  * This function is the default implementation of the internal driver gen
4550ca3913dSOlivier Deprez  * function.
4560ca3913dSOlivier Deprez  * It copies and formats the information of the nth element of tab into dir.
4570ca3913dSOlivier Deprez  ******************************************************************************/
devgen(chan_t * channel,const dirtab_t * tab,int ntab,int n,dir_t * dir)4580ca3913dSOlivier Deprez int devgen(chan_t *channel, const dirtab_t *tab, int ntab, int n, dir_t *dir)
4590ca3913dSOlivier Deprez {
4600ca3913dSOlivier Deprez 	const dirtab_t *dp;
4610ca3913dSOlivier Deprez 
4620ca3913dSOlivier Deprez 	if ((channel == NULL) || (dir == NULL) || (tab == NULL) ||
4630ca3913dSOlivier Deprez 			(n >= ntab)) {
4640ca3913dSOlivier Deprez 		return 0;
4650ca3913dSOlivier Deprez 	}
4660ca3913dSOlivier Deprez 
4670ca3913dSOlivier Deprez 	dp = &tab[n];
4680ca3913dSOlivier Deprez 	make_dir_entry(channel, dir, dp->name, dp->length, dp->qid, dp->perm);
4690ca3913dSOlivier Deprez 	return 1;
4700ca3913dSOlivier Deprez }
4710ca3913dSOlivier Deprez 
4720ca3913dSOlivier Deprez /*******************************************************************************
4730ca3913dSOlivier Deprez  * This function returns a file descriptor identifying the channel associated to
4740ca3913dSOlivier Deprez  * the given path.
4750ca3913dSOlivier Deprez  ******************************************************************************/
open(const char * path,int mode)4760ca3913dSOlivier Deprez int open(const char *path, int mode)
4770ca3913dSOlivier Deprez {
4780ca3913dSOlivier Deprez 	chan_t *channel;
4790ca3913dSOlivier Deprez 
4800ca3913dSOlivier Deprez 	if (path == NULL) {
4810ca3913dSOlivier Deprez 		return -1;
4820ca3913dSOlivier Deprez 	}
4830ca3913dSOlivier Deprez 
4840ca3913dSOlivier Deprez 	if (is_valid_mode(mode) == false) {
4850ca3913dSOlivier Deprez 		return -1;
4860ca3913dSOlivier Deprez 	}
4870ca3913dSOlivier Deprez 
4880ca3913dSOlivier Deprez 	channel = path_to_channel(path, mode);
4890ca3913dSOlivier Deprez 
4900ca3913dSOlivier Deprez 	return channel_to_fd(channel);
4910ca3913dSOlivier Deprez }
4920ca3913dSOlivier Deprez 
4930ca3913dSOlivier Deprez /*******************************************************************************
4940ca3913dSOlivier Deprez  * This function closes the channel identified by the file descriptor fd.
4950ca3913dSOlivier Deprez  ******************************************************************************/
close(int fd)4960ca3913dSOlivier Deprez int close(int fd)
4970ca3913dSOlivier Deprez {
4980ca3913dSOlivier Deprez 	chan_t *channel;
4990ca3913dSOlivier Deprez 
5000ca3913dSOlivier Deprez 	channel = fd_to_channel(fd);
5010ca3913dSOlivier Deprez 	if (channel == NULL) {
5020ca3913dSOlivier Deprez 		return -1;
5030ca3913dSOlivier Deprez 	}
5040ca3913dSOlivier Deprez 
5050ca3913dSOlivier Deprez 	channel_close(channel);
5060ca3913dSOlivier Deprez 	return 0;
5070ca3913dSOlivier Deprez }
5080ca3913dSOlivier Deprez 
5090ca3913dSOlivier Deprez /*******************************************************************************
5100ca3913dSOlivier Deprez  * This function is the default implementation of the driver stat function.
5110ca3913dSOlivier Deprez  * It goes through all the elements of tab using the gen function until a match
5120ca3913dSOlivier Deprez  * is found with file.
5130ca3913dSOlivier Deprez  * If a match is found, dir contains the information file.
5140ca3913dSOlivier Deprez  ******************************************************************************/
devstat(chan_t * dirc,const char * file,dir_t * dir,const dirtab_t * tab,int ntab,devgen_t * gen)5150ca3913dSOlivier Deprez int devstat(chan_t *dirc, const char *file, dir_t *dir,
5160ca3913dSOlivier Deprez 	    const dirtab_t *tab, int ntab, devgen_t *gen)
5170ca3913dSOlivier Deprez {
5180ca3913dSOlivier Deprez 	int i, r = 0;
5190ca3913dSOlivier Deprez 	chan_t *c, *mnt;
5200ca3913dSOlivier Deprez 
5210ca3913dSOlivier Deprez 	if ((dirc == NULL) || (dir == NULL) || (gen == NULL)) {
5220ca3913dSOlivier Deprez 		return -1;
5230ca3913dSOlivier Deprez 	}
5240ca3913dSOlivier Deprez 
5250ca3913dSOlivier Deprez 	c = path_to_channel(file, O_STAT);
5260ca3913dSOlivier Deprez 	if (c == NULL) {
5270ca3913dSOlivier Deprez 		return -1;
5280ca3913dSOlivier Deprez 	}
5290ca3913dSOlivier Deprez 
5300ca3913dSOlivier Deprez 	for (i = 0; ; i++) {
5310ca3913dSOlivier Deprez 		switch ((*gen)(dirc, tab, ntab, i, dir)) {
5320ca3913dSOlivier Deprez 		case 0:
5330ca3913dSOlivier Deprez 			/* Intentional fall-through */
5340ca3913dSOlivier Deprez 		case -1:
5350ca3913dSOlivier Deprez 			r = -1;
5360ca3913dSOlivier Deprez 			goto leave;
5370ca3913dSOlivier Deprez 		case 1:
5380ca3913dSOlivier Deprez 			mnt = mount_point_to_channel(dir->index, dir->qid);
5390ca3913dSOlivier Deprez 			if (mnt != NULL) {
5400ca3913dSOlivier Deprez 				dir->qid = mnt->qid;
5410ca3913dSOlivier Deprez 				dir->index = mnt->index;
5420ca3913dSOlivier Deprez 			}
5430ca3913dSOlivier Deprez 
5440ca3913dSOlivier Deprez 			if ((dir->qid != c->qid) || (dir->index != c->index)) {
5450ca3913dSOlivier Deprez 				continue;
5460ca3913dSOlivier Deprez 			}
5470ca3913dSOlivier Deprez 
5480ca3913dSOlivier Deprez 			goto leave;
5490ca3913dSOlivier Deprez 		}
5500ca3913dSOlivier Deprez 	}
5510ca3913dSOlivier Deprez 
5520ca3913dSOlivier Deprez leave:
5530ca3913dSOlivier Deprez 	channel_close(c);
5540ca3913dSOlivier Deprez 	return r;
5550ca3913dSOlivier Deprez }
5560ca3913dSOlivier Deprez 
5570ca3913dSOlivier Deprez /*******************************************************************************
5580ca3913dSOlivier Deprez  * This function calls the stat function of the driver associated to the parent
5590ca3913dSOlivier Deprez  * directory of the file in path.
5600ca3913dSOlivier Deprez  * The result is stored in dir.
5610ca3913dSOlivier Deprez  ******************************************************************************/
stat(const char * path,dir_t * dir)5620ca3913dSOlivier Deprez int stat(const char *path, dir_t *dir)
5630ca3913dSOlivier Deprez {
5640ca3913dSOlivier Deprez 	int r;
5650ca3913dSOlivier Deprez 	size_t len;
5660ca3913dSOlivier Deprez 	chan_t *channel;
5670ca3913dSOlivier Deprez 	char *p, dirname[PATHLEN];
5680ca3913dSOlivier Deprez 
5690ca3913dSOlivier Deprez 	if ((path == NULL) || (dir == NULL)) {
5700ca3913dSOlivier Deprez 		return -1;
5710ca3913dSOlivier Deprez 	}
5720ca3913dSOlivier Deprez 
5730ca3913dSOlivier Deprez 	len = strlen(path);
5740ca3913dSOlivier Deprez 	if ((len + 1) > sizeof(dirname)) {
5750ca3913dSOlivier Deprez 		return -1;
5760ca3913dSOlivier Deprez 	}
5770ca3913dSOlivier Deprez 
5780ca3913dSOlivier Deprez 	memcpy(dirname, path, len);
5790ca3913dSOlivier Deprez 	for (p = dirname + len; p > dirname; --p) {
5800ca3913dSOlivier Deprez 		if (*p != '/') {
5810ca3913dSOlivier Deprez 			break;
5820ca3913dSOlivier Deprez 		}
5830ca3913dSOlivier Deprez 	}
5840ca3913dSOlivier Deprez 
5850ca3913dSOlivier Deprez 	p = memrchr(dirname, '/', p - dirname);
5860ca3913dSOlivier Deprez 	if (p == NULL) {
5870ca3913dSOlivier Deprez 		return -1;
5880ca3913dSOlivier Deprez 	}
5890ca3913dSOlivier Deprez 
5900ca3913dSOlivier Deprez 	dirname[p - dirname + 1] = '\0';
5910ca3913dSOlivier Deprez 
5920ca3913dSOlivier Deprez 	channel = path_to_channel(dirname, O_STAT);
5930ca3913dSOlivier Deprez 	if (channel == NULL) {
5940ca3913dSOlivier Deprez 		return -1;
5950ca3913dSOlivier Deprez 	}
5960ca3913dSOlivier Deprez 
5970ca3913dSOlivier Deprez 	r = devtab[channel->index]->stat(channel, path, dir);
5980ca3913dSOlivier Deprez 	channel_close(channel);
5990ca3913dSOlivier Deprez 
6000ca3913dSOlivier Deprez 	return r;
6010ca3913dSOlivier Deprez }
6020ca3913dSOlivier Deprez 
6030ca3913dSOlivier Deprez /*******************************************************************************
6040ca3913dSOlivier Deprez  * This function calls the read function of the driver associated to fd.
6050ca3913dSOlivier Deprez  * It fills buf with at most n bytes.
6060ca3913dSOlivier Deprez  * It returns the number of bytes that were actually read.
6070ca3913dSOlivier Deprez  ******************************************************************************/
read(int fd,void * buf,int n)6080ca3913dSOlivier Deprez int read(int fd, void *buf, int n)
6090ca3913dSOlivier Deprez {
6100ca3913dSOlivier Deprez 	chan_t *channel;
6110ca3913dSOlivier Deprez 
6120ca3913dSOlivier Deprez 	if (buf == NULL) {
6130ca3913dSOlivier Deprez 		return -1;
6140ca3913dSOlivier Deprez 	}
6150ca3913dSOlivier Deprez 
6160ca3913dSOlivier Deprez 	channel = fd_to_channel(fd);
6170ca3913dSOlivier Deprez 	if (channel == NULL) {
6180ca3913dSOlivier Deprez 		return -1;
6190ca3913dSOlivier Deprez 	}
6200ca3913dSOlivier Deprez 
6210ca3913dSOlivier Deprez 	if (((channel->qid & CHDIR) != 0) && (n < sizeof(dir_t))) {
6220ca3913dSOlivier Deprez 		return -1;
6230ca3913dSOlivier Deprez 	}
6240ca3913dSOlivier Deprez 
6250ca3913dSOlivier Deprez 	return devtab[channel->index]->read(channel, buf, n);
6260ca3913dSOlivier Deprez }
6270ca3913dSOlivier Deprez 
6280ca3913dSOlivier Deprez /*******************************************************************************
6290ca3913dSOlivier Deprez  * This function calls the write function of the driver associated to fd.
6300ca3913dSOlivier Deprez  * It writes at most n bytes of buf.
6310ca3913dSOlivier Deprez  * It returns the number of bytes that were actually written.
6320ca3913dSOlivier Deprez  ******************************************************************************/
write(int fd,void * buf,int n)6330ca3913dSOlivier Deprez int write(int fd, void *buf, int n)
6340ca3913dSOlivier Deprez {
6350ca3913dSOlivier Deprez 	chan_t *channel;
6360ca3913dSOlivier Deprez 
6370ca3913dSOlivier Deprez 	if (buf == NULL) {
6380ca3913dSOlivier Deprez 		return -1;
6390ca3913dSOlivier Deprez 	}
6400ca3913dSOlivier Deprez 
6410ca3913dSOlivier Deprez 	channel = fd_to_channel(fd);
6420ca3913dSOlivier Deprez 	if (channel == NULL) {
6430ca3913dSOlivier Deprez 		return -1;
6440ca3913dSOlivier Deprez 	}
6450ca3913dSOlivier Deprez 
6460ca3913dSOlivier Deprez 	if ((channel->qid & CHDIR) != 0) {
6470ca3913dSOlivier Deprez 		return -1;
6480ca3913dSOlivier Deprez 	}
6490ca3913dSOlivier Deprez 
6500ca3913dSOlivier Deprez 	return devtab[channel->index]->write(channel, buf, n);
6510ca3913dSOlivier Deprez }
6520ca3913dSOlivier Deprez 
6530ca3913dSOlivier Deprez /*******************************************************************************
6540ca3913dSOlivier Deprez  * This function calls the seek function of the driver associated to fd.
6550ca3913dSOlivier Deprez  * It applies the offset off according to the strategy whence.
6560ca3913dSOlivier Deprez  ******************************************************************************/
seek(int fd,long off,int whence)6570ca3913dSOlivier Deprez int seek(int fd, long off, int whence)
6580ca3913dSOlivier Deprez {
6590ca3913dSOlivier Deprez 	chan_t *channel;
6600ca3913dSOlivier Deprez 
6610ca3913dSOlivier Deprez 	channel = fd_to_channel(fd);
6620ca3913dSOlivier Deprez 	if (channel == NULL) {
6630ca3913dSOlivier Deprez 		return -1;
6640ca3913dSOlivier Deprez 	}
6650ca3913dSOlivier Deprez 
6660ca3913dSOlivier Deprez 	if ((channel->qid & CHDIR) != 0) {
6670ca3913dSOlivier Deprez 		return -1;
6680ca3913dSOlivier Deprez 	}
6690ca3913dSOlivier Deprez 
6700ca3913dSOlivier Deprez 	return devtab[channel->index]->seek(channel, off, whence);
6710ca3913dSOlivier Deprez }
6720ca3913dSOlivier Deprez 
6730ca3913dSOlivier Deprez /*******************************************************************************
6740ca3913dSOlivier Deprez  * This function is the default error implementation of the driver mount
6750ca3913dSOlivier Deprez  * function.
6760ca3913dSOlivier Deprez  ******************************************************************************/
deverrmount(chan_t * channel,const char * spec)6770ca3913dSOlivier Deprez chan_t *deverrmount(chan_t *channel, const char *spec)
6780ca3913dSOlivier Deprez {
6790ca3913dSOlivier Deprez 	return NULL;
6800ca3913dSOlivier Deprez }
6810ca3913dSOlivier Deprez 
6820ca3913dSOlivier Deprez /*******************************************************************************
6830ca3913dSOlivier Deprez  * This function is the default error implementation of the driver write
6840ca3913dSOlivier Deprez  * function.
6850ca3913dSOlivier Deprez  ******************************************************************************/
deverrwrite(chan_t * channel,void * buf,int n)6860ca3913dSOlivier Deprez int deverrwrite(chan_t *channel, void *buf, int n)
6870ca3913dSOlivier Deprez {
6880ca3913dSOlivier Deprez 	return -1;
6890ca3913dSOlivier Deprez }
6900ca3913dSOlivier Deprez 
6910ca3913dSOlivier Deprez /*******************************************************************************
6920ca3913dSOlivier Deprez  * This function is the default error implementation of the driver seek
6930ca3913dSOlivier Deprez  * function.
6940ca3913dSOlivier Deprez  ******************************************************************************/
deverrseek(chan_t * channel,long off,int whence)6950ca3913dSOlivier Deprez int deverrseek(chan_t *channel, long off, int whence)
6960ca3913dSOlivier Deprez {
6970ca3913dSOlivier Deprez 	return -1;
6980ca3913dSOlivier Deprez }
6990ca3913dSOlivier Deprez 
7000ca3913dSOlivier Deprez /*******************************************************************************
7010ca3913dSOlivier Deprez  * This function is the default implementation of the driver seek function.
7020ca3913dSOlivier Deprez  * It applies the offset off according to the strategy whence to the channel c.
7030ca3913dSOlivier Deprez  ******************************************************************************/
devseek(chan_t * channel,long off,int whence)7040ca3913dSOlivier Deprez int devseek(chan_t *channel, long off, int whence)
7050ca3913dSOlivier Deprez {
7060ca3913dSOlivier Deprez 	switch (whence) {
7070ca3913dSOlivier Deprez 	case KSEEK_SET:
7080ca3913dSOlivier Deprez 		channel->offset = off;
7090ca3913dSOlivier Deprez 		break;
7100ca3913dSOlivier Deprez 	case KSEEK_CUR:
7110ca3913dSOlivier Deprez 		channel->offset += off;
7120ca3913dSOlivier Deprez 		break;
7130ca3913dSOlivier Deprez 	case KSEEK_END:
7140ca3913dSOlivier Deprez 		/* Not implemented */
7150ca3913dSOlivier Deprez 		return -1;
7160ca3913dSOlivier Deprez 	}
7170ca3913dSOlivier Deprez 
7180ca3913dSOlivier Deprez 	return 0;
7190ca3913dSOlivier Deprez }
7200ca3913dSOlivier Deprez 
7210ca3913dSOlivier Deprez /*******************************************************************************
7220ca3913dSOlivier Deprez  * This function registers the channel associated to the path new as a mount
7230ca3913dSOlivier Deprez  * point for the channel c.
7240ca3913dSOlivier Deprez  ******************************************************************************/
add_mount_point(chan_t * channel,const char * new)7250ca3913dSOlivier Deprez static int add_mount_point(chan_t *channel, const char *new)
7260ca3913dSOlivier Deprez {
7270ca3913dSOlivier Deprez 	int i;
7280ca3913dSOlivier Deprez 	chan_t *cn;
7290ca3913dSOlivier Deprez 	struct mount_point *mp;
7300ca3913dSOlivier Deprez 
7310ca3913dSOlivier Deprez 	if (new == NULL) {
7320ca3913dSOlivier Deprez 		goto err0;
7330ca3913dSOlivier Deprez 	}
7340ca3913dSOlivier Deprez 
7350ca3913dSOlivier Deprez 	cn = path_to_channel(new, O_READ);
7360ca3913dSOlivier Deprez 	if (cn == NULL) {
7370ca3913dSOlivier Deprez 		goto err0;
7380ca3913dSOlivier Deprez 	}
7390ca3913dSOlivier Deprez 
7400ca3913dSOlivier Deprez 	if ((cn->qid & CHDIR) == 0) {
7410ca3913dSOlivier Deprez 		goto err1;
7420ca3913dSOlivier Deprez 	}
7430ca3913dSOlivier Deprez 
7440ca3913dSOlivier Deprez 	for (i = NR_MOUNT_POINTS - 1; i >= 0; i--) {
7450ca3913dSOlivier Deprez 		mp = &mount_points[i];
7460ca3913dSOlivier Deprez 		if (mp->new == NULL) {
7470ca3913dSOlivier Deprez 			break;
7480ca3913dSOlivier Deprez 		}
7490ca3913dSOlivier Deprez 	}
7500ca3913dSOlivier Deprez 
7510ca3913dSOlivier Deprez 	if (i < 0) {
7520ca3913dSOlivier Deprez 		goto err1;
7530ca3913dSOlivier Deprez 	}
7540ca3913dSOlivier Deprez 
7550ca3913dSOlivier Deprez 	mp->new = cn;
7560ca3913dSOlivier Deprez 	mp->old = channel;
7570ca3913dSOlivier Deprez 
7580ca3913dSOlivier Deprez 	return 0;
7590ca3913dSOlivier Deprez 
7600ca3913dSOlivier Deprez err1:
7610ca3913dSOlivier Deprez 	channel_close(cn);
7620ca3913dSOlivier Deprez err0:
7630ca3913dSOlivier Deprez 	return -1;
7640ca3913dSOlivier Deprez }
7650ca3913dSOlivier Deprez 
7660ca3913dSOlivier Deprez /*******************************************************************************
7670ca3913dSOlivier Deprez  * This function registers the path new as a mount point for the path old.
7680ca3913dSOlivier Deprez  ******************************************************************************/
bind(const char * old,const char * new)7690ca3913dSOlivier Deprez int bind(const char *old, const char *new)
7700ca3913dSOlivier Deprez {
7710ca3913dSOlivier Deprez 	chan_t *channel;
7720ca3913dSOlivier Deprez 
7730ca3913dSOlivier Deprez 	channel = path_to_channel(old, O_BIND);
7740ca3913dSOlivier Deprez 	if (channel == NULL) {
7750ca3913dSOlivier Deprez 		return -1;
7760ca3913dSOlivier Deprez 	}
7770ca3913dSOlivier Deprez 
7780ca3913dSOlivier Deprez 	if (add_mount_point(channel, new) < 0) {
7790ca3913dSOlivier Deprez 		channel_close(channel);
7800ca3913dSOlivier Deprez 		return -1;
7810ca3913dSOlivier Deprez 	}
7820ca3913dSOlivier Deprez 
7830ca3913dSOlivier Deprez 	return 0;
7840ca3913dSOlivier Deprez }
7850ca3913dSOlivier Deprez 
7860ca3913dSOlivier Deprez /*******************************************************************************
7870ca3913dSOlivier Deprez  * This function calls the mount function of the driver associated to the path
7880ca3913dSOlivier Deprez  * srv.
7890ca3913dSOlivier Deprez  * It mounts the path srv on the path where.
7900ca3913dSOlivier Deprez  ******************************************************************************/
mount(const char * srv,const char * where,const char * spec)7910ca3913dSOlivier Deprez int mount(const char *srv, const char *where, const char *spec)
7920ca3913dSOlivier Deprez {
7930ca3913dSOlivier Deprez 	chan_t *channel, *mount_point_chan;
7940ca3913dSOlivier Deprez 	int ret;
7950ca3913dSOlivier Deprez 
7960ca3913dSOlivier Deprez 	channel = path_to_channel(srv, O_RDWR);
7970ca3913dSOlivier Deprez 	if (channel == NULL) {
7980ca3913dSOlivier Deprez 		goto err0;
7990ca3913dSOlivier Deprez 	}
8000ca3913dSOlivier Deprez 
8010ca3913dSOlivier Deprez 	mount_point_chan = devtab[channel->index]->mount(channel, spec);
8020ca3913dSOlivier Deprez 	if (mount_point_chan == NULL) {
8030ca3913dSOlivier Deprez 		goto err1;
8040ca3913dSOlivier Deprez 	}
8050ca3913dSOlivier Deprez 
8060ca3913dSOlivier Deprez 	ret = add_mount_point(mount_point_chan, where);
8070ca3913dSOlivier Deprez 	if (ret < 0) {
8080ca3913dSOlivier Deprez 		goto err2;
8090ca3913dSOlivier Deprez 	}
8100ca3913dSOlivier Deprez 
8110ca3913dSOlivier Deprez 	channel_close(channel);
8120ca3913dSOlivier Deprez 
8130ca3913dSOlivier Deprez 	return 0;
8140ca3913dSOlivier Deprez 
8150ca3913dSOlivier Deprez err2:
8160ca3913dSOlivier Deprez 	channel_close(mount_point_chan);
8170ca3913dSOlivier Deprez err1:
8180ca3913dSOlivier Deprez 	channel_close(channel);
8190ca3913dSOlivier Deprez err0:
8200ca3913dSOlivier Deprez 	return -1;
8210ca3913dSOlivier Deprez }
8220ca3913dSOlivier Deprez 
8230ca3913dSOlivier Deprez /*******************************************************************************
8240ca3913dSOlivier Deprez  * This function initializes the device environment.
8250ca3913dSOlivier Deprez  * It creates the '/' channel.
8260ca3913dSOlivier Deprez  * It links the device drivers to the physical drivers.
8270ca3913dSOlivier Deprez  ******************************************************************************/
debugfs_init(void)8280ca3913dSOlivier Deprez void debugfs_init(void)
8290ca3913dSOlivier Deprez {
8300ca3913dSOlivier Deprez 	chan_t *channel, *cloned_channel;
8310ca3913dSOlivier Deprez 
8320ca3913dSOlivier Deprez 	for (channel = fdset; channel < &fdset[NR_CHANS]; channel++) {
8330ca3913dSOlivier Deprez 		channel_clear(channel);
8340ca3913dSOlivier Deprez 	}
8350ca3913dSOlivier Deprez 
8360ca3913dSOlivier Deprez 	channel = devattach('/', 0);
8370ca3913dSOlivier Deprez 	if (channel == NULL) {
8380ca3913dSOlivier Deprez 		panic();
8390ca3913dSOlivier Deprez 	}
8400ca3913dSOlivier Deprez 
8410ca3913dSOlivier Deprez 	cloned_channel = clone(channel, &slash_channel);
8420ca3913dSOlivier Deprez 	if (cloned_channel == NULL) {
8430ca3913dSOlivier Deprez 		panic();
8440ca3913dSOlivier Deprez 	}
8450ca3913dSOlivier Deprez 
8460ca3913dSOlivier Deprez 	channel_close(channel);
8470ca3913dSOlivier Deprez 	devlink();
8480ca3913dSOlivier Deprez }
8490ca3913dSOlivier Deprez 
devpanic(const char * cause)8500ca3913dSOlivier Deprez __dead2 void devpanic(const char *cause)
8510ca3913dSOlivier Deprez {
8520ca3913dSOlivier Deprez 	panic();
8530ca3913dSOlivier Deprez }
854