xref: /rk3399_ARM-atf/lib/debugfs/dev.c (revision 0ca3913dd898ec0822d4984f8fd6eb86131f1088)
1*0ca3913dSOlivier Deprez /*
2*0ca3913dSOlivier Deprez  * Copyright (c) 2019, Arm Limited. All rights reserved.
3*0ca3913dSOlivier Deprez  *
4*0ca3913dSOlivier Deprez  * SPDX-License-Identifier: BSD-3-Clause
5*0ca3913dSOlivier Deprez  */
6*0ca3913dSOlivier Deprez 
7*0ca3913dSOlivier Deprez #include <cdefs.h>
8*0ca3913dSOlivier Deprez #include <common/debug.h>
9*0ca3913dSOlivier Deprez #include <lib/debugfs.h>
10*0ca3913dSOlivier Deprez #include <string.h>
11*0ca3913dSOlivier Deprez 
12*0ca3913dSOlivier Deprez #include "dev.h"
13*0ca3913dSOlivier Deprez 
14*0ca3913dSOlivier Deprez #define NR_MOUNT_POINTS		4
15*0ca3913dSOlivier Deprez 
16*0ca3913dSOlivier Deprez struct mount_point {
17*0ca3913dSOlivier Deprez 	chan_t	*new;
18*0ca3913dSOlivier Deprez 	chan_t	*old;
19*0ca3913dSOlivier Deprez };
20*0ca3913dSOlivier Deprez 
21*0ca3913dSOlivier Deprez /* This array contains all the available channels of the filesystem.
22*0ca3913dSOlivier Deprez  * A file descriptor is the index of a specific channel in this array.
23*0ca3913dSOlivier Deprez  */
24*0ca3913dSOlivier Deprez static chan_t fdset[NR_CHANS];
25*0ca3913dSOlivier Deprez 
26*0ca3913dSOlivier Deprez /* This array contains all the available mount points of the filesystem. */
27*0ca3913dSOlivier Deprez static struct mount_point mount_points[NR_MOUNT_POINTS];
28*0ca3913dSOlivier Deprez 
29*0ca3913dSOlivier Deprez /* This variable stores the channel associated to the root directory. */
30*0ca3913dSOlivier Deprez static chan_t slash_channel;
31*0ca3913dSOlivier Deprez 
32*0ca3913dSOlivier Deprez /* This function creates a channel from a device index and registers
33*0ca3913dSOlivier Deprez  * it to fdset.
34*0ca3913dSOlivier Deprez  */
35*0ca3913dSOlivier Deprez static chan_t *create_new_channel(unsigned char index)
36*0ca3913dSOlivier Deprez {
37*0ca3913dSOlivier Deprez 	chan_t *channel = NULL;
38*0ca3913dSOlivier Deprez 	int i;
39*0ca3913dSOlivier Deprez 
40*0ca3913dSOlivier Deprez 	for (i = 0; i < NR_CHANS; i++) {
41*0ca3913dSOlivier Deprez 		if (fdset[i].index == NODEV) {
42*0ca3913dSOlivier Deprez 			channel = &fdset[i];
43*0ca3913dSOlivier Deprez 			channel->index = index;
44*0ca3913dSOlivier Deprez 			break;
45*0ca3913dSOlivier Deprez 		}
46*0ca3913dSOlivier Deprez 	}
47*0ca3913dSOlivier Deprez 
48*0ca3913dSOlivier Deprez 	return channel;
49*0ca3913dSOlivier Deprez }
50*0ca3913dSOlivier Deprez 
51*0ca3913dSOlivier Deprez /*******************************************************************************
52*0ca3913dSOlivier Deprez  * This function returns a pointer to an existing channel in fdset from a file
53*0ca3913dSOlivier Deprez  * descriptor.
54*0ca3913dSOlivier Deprez  ******************************************************************************/
55*0ca3913dSOlivier Deprez static chan_t *fd_to_channel(int fd)
56*0ca3913dSOlivier Deprez {
57*0ca3913dSOlivier Deprez 	if ((fd < 0) || (fd >= NR_CHANS) || (fdset[fd].index == NODEV)) {
58*0ca3913dSOlivier Deprez 		return NULL;
59*0ca3913dSOlivier Deprez 	}
60*0ca3913dSOlivier Deprez 
61*0ca3913dSOlivier Deprez 	return &fdset[fd];
62*0ca3913dSOlivier Deprez }
63*0ca3913dSOlivier Deprez 
64*0ca3913dSOlivier Deprez /*******************************************************************************
65*0ca3913dSOlivier Deprez  * This function returns a file descriptor from a channel.
66*0ca3913dSOlivier Deprez  * The caller must be sure that the channel is registered in fdset.
67*0ca3913dSOlivier Deprez  ******************************************************************************/
68*0ca3913dSOlivier Deprez static int channel_to_fd(chan_t *channel)
69*0ca3913dSOlivier Deprez {
70*0ca3913dSOlivier Deprez 	return (channel == NULL) ? -1 : (channel - fdset);
71*0ca3913dSOlivier Deprez }
72*0ca3913dSOlivier Deprez 
73*0ca3913dSOlivier Deprez /*******************************************************************************
74*0ca3913dSOlivier Deprez  * This function checks the validity of a mode.
75*0ca3913dSOlivier Deprez  ******************************************************************************/
76*0ca3913dSOlivier Deprez static bool is_valid_mode(int mode)
77*0ca3913dSOlivier Deprez {
78*0ca3913dSOlivier Deprez 	if ((mode & O_READ) && (mode & (O_WRITE | O_RDWR))) {
79*0ca3913dSOlivier Deprez 		return false;
80*0ca3913dSOlivier Deprez 	}
81*0ca3913dSOlivier Deprez 	if ((mode & O_WRITE) && (mode & (O_READ | O_RDWR))) {
82*0ca3913dSOlivier Deprez 		return false;
83*0ca3913dSOlivier Deprez 	}
84*0ca3913dSOlivier Deprez 	if ((mode & O_RDWR) && (mode & (O_READ | O_WRITE))) {
85*0ca3913dSOlivier Deprez 		return false;
86*0ca3913dSOlivier Deprez 	}
87*0ca3913dSOlivier Deprez 
88*0ca3913dSOlivier Deprez 	return true;
89*0ca3913dSOlivier Deprez }
90*0ca3913dSOlivier Deprez 
91*0ca3913dSOlivier Deprez /*******************************************************************************
92*0ca3913dSOlivier Deprez  * This function extracts the next part of the given path contained and puts it
93*0ca3913dSOlivier Deprez  * in token. It returns a pointer to the remainder of the path.
94*0ca3913dSOlivier Deprez  ******************************************************************************/
95*0ca3913dSOlivier Deprez static const char *next(const char *path, char *token)
96*0ca3913dSOlivier Deprez {
97*0ca3913dSOlivier Deprez 	int index;
98*0ca3913dSOlivier Deprez 	const char *cursor;
99*0ca3913dSOlivier Deprez 
100*0ca3913dSOlivier Deprez 	while (*path == '/') {
101*0ca3913dSOlivier Deprez 		++path;
102*0ca3913dSOlivier Deprez 	}
103*0ca3913dSOlivier Deprez 
104*0ca3913dSOlivier Deprez 	index = 0;
105*0ca3913dSOlivier Deprez 	cursor = path;
106*0ca3913dSOlivier Deprez 	if (*path != '\0') {
107*0ca3913dSOlivier Deprez 		while (*cursor != '/' && *cursor != '\0') {
108*0ca3913dSOlivier Deprez 			if (index == NAMELEN) {
109*0ca3913dSOlivier Deprez 				return NULL;
110*0ca3913dSOlivier Deprez 			}
111*0ca3913dSOlivier Deprez 			token[index++] = *cursor++;
112*0ca3913dSOlivier Deprez 		}
113*0ca3913dSOlivier Deprez 	}
114*0ca3913dSOlivier Deprez 	token[index] = '\0';
115*0ca3913dSOlivier Deprez 
116*0ca3913dSOlivier Deprez 	return cursor;
117*0ca3913dSOlivier Deprez }
118*0ca3913dSOlivier Deprez 
119*0ca3913dSOlivier Deprez /*******************************************************************************
120*0ca3913dSOlivier Deprez  * This function returns the driver index in devtab of the driver
121*0ca3913dSOlivier Deprez  * identified by id.
122*0ca3913dSOlivier Deprez  ******************************************************************************/
123*0ca3913dSOlivier Deprez static int get_device_index(int id)
124*0ca3913dSOlivier Deprez {
125*0ca3913dSOlivier Deprez 	int index;
126*0ca3913dSOlivier Deprez 	dev_t * const *dp;
127*0ca3913dSOlivier Deprez 
128*0ca3913dSOlivier Deprez 	for (index = 0, dp = devtab; *dp && (*dp)->id != id; ++dp) {
129*0ca3913dSOlivier Deprez 		index++;
130*0ca3913dSOlivier Deprez 	}
131*0ca3913dSOlivier Deprez 
132*0ca3913dSOlivier Deprez 	if (*dp == NULL) {
133*0ca3913dSOlivier Deprez 		return -1;
134*0ca3913dSOlivier Deprez 	}
135*0ca3913dSOlivier Deprez 
136*0ca3913dSOlivier Deprez 	return index;
137*0ca3913dSOlivier Deprez }
138*0ca3913dSOlivier Deprez 
139*0ca3913dSOlivier Deprez /*******************************************************************************
140*0ca3913dSOlivier Deprez  * This function clears a given channel fields
141*0ca3913dSOlivier Deprez  ******************************************************************************/
142*0ca3913dSOlivier Deprez static void channel_clear(chan_t *channel)
143*0ca3913dSOlivier Deprez {
144*0ca3913dSOlivier Deprez 	channel->offset = 0;
145*0ca3913dSOlivier Deprez 	channel->qid    = 0;
146*0ca3913dSOlivier Deprez 	channel->index  = NODEV;
147*0ca3913dSOlivier Deprez 	channel->dev    = 0;
148*0ca3913dSOlivier Deprez 	channel->mode   = 0;
149*0ca3913dSOlivier Deprez }
150*0ca3913dSOlivier Deprez 
151*0ca3913dSOlivier Deprez /*******************************************************************************
152*0ca3913dSOlivier Deprez  * This function closes the channel pointed to by c.
153*0ca3913dSOlivier Deprez  ******************************************************************************/
154*0ca3913dSOlivier Deprez void channel_close(chan_t *channel)
155*0ca3913dSOlivier Deprez {
156*0ca3913dSOlivier Deprez 	if (channel != NULL) {
157*0ca3913dSOlivier Deprez 		channel_clear(channel);
158*0ca3913dSOlivier Deprez 	}
159*0ca3913dSOlivier Deprez }
160*0ca3913dSOlivier Deprez 
161*0ca3913dSOlivier Deprez /*******************************************************************************
162*0ca3913dSOlivier Deprez  * This function copies data from src to dst after applying the offset of the
163*0ca3913dSOlivier Deprez  * channel c. nbytes bytes are expected to be copied unless the data goes over
164*0ca3913dSOlivier Deprez  * dst + len.
165*0ca3913dSOlivier Deprez  * It returns the actual number of bytes that were copied.
166*0ca3913dSOlivier Deprez  ******************************************************************************/
167*0ca3913dSOlivier Deprez int buf_to_channel(chan_t *channel, void *dst, void *src, int nbytes, long len)
168*0ca3913dSOlivier Deprez {
169*0ca3913dSOlivier Deprez 	const char *addr = src;
170*0ca3913dSOlivier Deprez 
171*0ca3913dSOlivier Deprez 	if ((channel == NULL) || (dst == NULL) || (src == NULL)) {
172*0ca3913dSOlivier Deprez 		return 0;
173*0ca3913dSOlivier Deprez 	}
174*0ca3913dSOlivier Deprez 
175*0ca3913dSOlivier Deprez 	if (channel->offset >= len) {
176*0ca3913dSOlivier Deprez 		return 0;
177*0ca3913dSOlivier Deprez 	}
178*0ca3913dSOlivier Deprez 
179*0ca3913dSOlivier Deprez 	if ((channel->offset + nbytes) > len) {
180*0ca3913dSOlivier Deprez 		nbytes = len - channel->offset;
181*0ca3913dSOlivier Deprez 	}
182*0ca3913dSOlivier Deprez 
183*0ca3913dSOlivier Deprez 	memcpy(dst, addr + channel->offset, nbytes);
184*0ca3913dSOlivier Deprez 
185*0ca3913dSOlivier Deprez 	channel->offset += nbytes;
186*0ca3913dSOlivier Deprez 
187*0ca3913dSOlivier Deprez 	return nbytes;
188*0ca3913dSOlivier Deprez }
189*0ca3913dSOlivier Deprez 
190*0ca3913dSOlivier Deprez /*******************************************************************************
191*0ca3913dSOlivier Deprez  * This function checks whether a channel (identified by its device index and
192*0ca3913dSOlivier Deprez  * qid) is registered as a mount point.
193*0ca3913dSOlivier Deprez  * Returns a pointer to the channel it is mounted to when found, NULL otherwise.
194*0ca3913dSOlivier Deprez  ******************************************************************************/
195*0ca3913dSOlivier Deprez static chan_t *mount_point_to_channel(int index, qid_t qid)
196*0ca3913dSOlivier Deprez {
197*0ca3913dSOlivier Deprez 	chan_t *channel;
198*0ca3913dSOlivier Deprez 	struct mount_point *mp;
199*0ca3913dSOlivier Deprez 
200*0ca3913dSOlivier Deprez 	for (mp = mount_points; mp < &mount_points[NR_MOUNT_POINTS]; mp++) {
201*0ca3913dSOlivier Deprez 		channel = mp->new;
202*0ca3913dSOlivier Deprez 		if (channel == NULL) {
203*0ca3913dSOlivier Deprez 			continue;
204*0ca3913dSOlivier Deprez 		}
205*0ca3913dSOlivier Deprez 
206*0ca3913dSOlivier Deprez 		if ((channel->index == index) && (channel->qid == qid)) {
207*0ca3913dSOlivier Deprez 			return mp->old;
208*0ca3913dSOlivier Deprez 		}
209*0ca3913dSOlivier Deprez 	}
210*0ca3913dSOlivier Deprez 
211*0ca3913dSOlivier Deprez 	return NULL;
212*0ca3913dSOlivier Deprez }
213*0ca3913dSOlivier Deprez 
214*0ca3913dSOlivier Deprez /*******************************************************************************
215*0ca3913dSOlivier Deprez  * This function calls the attach function of the driver identified by id.
216*0ca3913dSOlivier Deprez  ******************************************************************************/
217*0ca3913dSOlivier Deprez chan_t *attach(int id, int dev)
218*0ca3913dSOlivier Deprez {
219*0ca3913dSOlivier Deprez 	/* Get the devtab index for the driver identified by id */
220*0ca3913dSOlivier Deprez 	int index = get_device_index(id);
221*0ca3913dSOlivier Deprez 
222*0ca3913dSOlivier Deprez 	if (index < 0) {
223*0ca3913dSOlivier Deprez 		return NULL;
224*0ca3913dSOlivier Deprez 	}
225*0ca3913dSOlivier Deprez 
226*0ca3913dSOlivier Deprez 	return devtab[index]->attach(id, dev);
227*0ca3913dSOlivier Deprez }
228*0ca3913dSOlivier Deprez 
229*0ca3913dSOlivier Deprez /*******************************************************************************
230*0ca3913dSOlivier Deprez  * This function is the default implementation of the driver attach function.
231*0ca3913dSOlivier Deprez  * It creates a new channel and returns a pointer to it.
232*0ca3913dSOlivier Deprez  ******************************************************************************/
233*0ca3913dSOlivier Deprez chan_t *devattach(int id, int dev)
234*0ca3913dSOlivier Deprez {
235*0ca3913dSOlivier Deprez 	chan_t *channel;
236*0ca3913dSOlivier Deprez 	int index;
237*0ca3913dSOlivier Deprez 
238*0ca3913dSOlivier Deprez 	index = get_device_index(id);
239*0ca3913dSOlivier Deprez 	if (index < 0) {
240*0ca3913dSOlivier Deprez 		return NULL;
241*0ca3913dSOlivier Deprez 	}
242*0ca3913dSOlivier Deprez 
243*0ca3913dSOlivier Deprez 	channel = create_new_channel(index);
244*0ca3913dSOlivier Deprez 	if (channel == NULL) {
245*0ca3913dSOlivier Deprez 		return NULL;
246*0ca3913dSOlivier Deprez 	}
247*0ca3913dSOlivier Deprez 
248*0ca3913dSOlivier Deprez 	channel->dev = dev;
249*0ca3913dSOlivier Deprez 	channel->qid = CHDIR;
250*0ca3913dSOlivier Deprez 
251*0ca3913dSOlivier Deprez 	return channel;
252*0ca3913dSOlivier Deprez }
253*0ca3913dSOlivier Deprez 
254*0ca3913dSOlivier Deprez /*******************************************************************************
255*0ca3913dSOlivier Deprez  * This function returns a channel given a path.
256*0ca3913dSOlivier Deprez  * It goes through the filesystem, from the root namespace ('/') or from a
257*0ca3913dSOlivier Deprez  * device namespace ('#'), switching channel on mount points.
258*0ca3913dSOlivier Deprez  ******************************************************************************/
259*0ca3913dSOlivier Deprez chan_t *path_to_channel(const char *path, int mode)
260*0ca3913dSOlivier Deprez {
261*0ca3913dSOlivier Deprez 	int i, n;
262*0ca3913dSOlivier Deprez 	const char *path_next;
263*0ca3913dSOlivier Deprez 	chan_t *mnt, *channel;
264*0ca3913dSOlivier Deprez 	char elem[NAMELEN];
265*0ca3913dSOlivier Deprez 
266*0ca3913dSOlivier Deprez 	if (path == NULL) {
267*0ca3913dSOlivier Deprez 		return NULL;
268*0ca3913dSOlivier Deprez 	}
269*0ca3913dSOlivier Deprez 
270*0ca3913dSOlivier Deprez 	switch (path[0]) {
271*0ca3913dSOlivier Deprez 	case '/':
272*0ca3913dSOlivier Deprez 		channel = clone(&slash_channel, NULL);
273*0ca3913dSOlivier Deprez 		path_next = path;
274*0ca3913dSOlivier Deprez 		break;
275*0ca3913dSOlivier Deprez 	case '#':
276*0ca3913dSOlivier Deprez 		path_next = next(path + 1, elem);
277*0ca3913dSOlivier Deprez 		if (path_next == NULL) {
278*0ca3913dSOlivier Deprez 			goto noent;
279*0ca3913dSOlivier Deprez 		}
280*0ca3913dSOlivier Deprez 
281*0ca3913dSOlivier Deprez 		n = 0;
282*0ca3913dSOlivier Deprez 		for (i = 1; (elem[i] >= '0') && (elem[i] <= '9'); i++) {
283*0ca3913dSOlivier Deprez 			n += elem[i] - '0';
284*0ca3913dSOlivier Deprez 		}
285*0ca3913dSOlivier Deprez 
286*0ca3913dSOlivier Deprez 		if (elem[i] != '\0') {
287*0ca3913dSOlivier Deprez 			goto noent;
288*0ca3913dSOlivier Deprez 		}
289*0ca3913dSOlivier Deprez 
290*0ca3913dSOlivier Deprez 		channel = attach(elem[0], n);
291*0ca3913dSOlivier Deprez 		break;
292*0ca3913dSOlivier Deprez 	default:
293*0ca3913dSOlivier Deprez 		return NULL;
294*0ca3913dSOlivier Deprez 	}
295*0ca3913dSOlivier Deprez 
296*0ca3913dSOlivier Deprez 	if (channel == NULL) {
297*0ca3913dSOlivier Deprez 		return NULL;
298*0ca3913dSOlivier Deprez 	}
299*0ca3913dSOlivier Deprez 
300*0ca3913dSOlivier Deprez 	for (path_next = next(path_next, elem); *elem;
301*0ca3913dSOlivier Deprez 			path_next = next(path_next, elem)) {
302*0ca3913dSOlivier Deprez 		if ((channel->qid & CHDIR) == 0) {
303*0ca3913dSOlivier Deprez 			goto notfound;
304*0ca3913dSOlivier Deprez 		}
305*0ca3913dSOlivier Deprez 
306*0ca3913dSOlivier Deprez 		if (devtab[channel->index]->walk(channel, elem) < 0) {
307*0ca3913dSOlivier Deprez 			channel_close(channel);
308*0ca3913dSOlivier Deprez 			goto notfound;
309*0ca3913dSOlivier Deprez 		}
310*0ca3913dSOlivier Deprez 
311*0ca3913dSOlivier Deprez 		mnt = mount_point_to_channel(channel->index, channel->qid);
312*0ca3913dSOlivier Deprez 		if (mnt != NULL) {
313*0ca3913dSOlivier Deprez 			clone(mnt, channel);
314*0ca3913dSOlivier Deprez 		}
315*0ca3913dSOlivier Deprez 	}
316*0ca3913dSOlivier Deprez 
317*0ca3913dSOlivier Deprez 	if (path_next == NULL) {
318*0ca3913dSOlivier Deprez 		goto notfound;
319*0ca3913dSOlivier Deprez 	}
320*0ca3913dSOlivier Deprez 
321*0ca3913dSOlivier Deprez 	/* TODO: check mode */
322*0ca3913dSOlivier Deprez 	return channel;
323*0ca3913dSOlivier Deprez 
324*0ca3913dSOlivier Deprez notfound:
325*0ca3913dSOlivier Deprez 	channel_close(channel);
326*0ca3913dSOlivier Deprez noent:
327*0ca3913dSOlivier Deprez 	return NULL;
328*0ca3913dSOlivier Deprez }
329*0ca3913dSOlivier Deprez 
330*0ca3913dSOlivier Deprez /*******************************************************************************
331*0ca3913dSOlivier Deprez  * This function calls the clone function of the driver associated to the
332*0ca3913dSOlivier Deprez  * channel c.
333*0ca3913dSOlivier Deprez  ******************************************************************************/
334*0ca3913dSOlivier Deprez chan_t *clone(chan_t *c, chan_t *nc)
335*0ca3913dSOlivier Deprez {
336*0ca3913dSOlivier Deprez 	return devtab[c->index]->clone(c, nc);
337*0ca3913dSOlivier Deprez }
338*0ca3913dSOlivier Deprez 
339*0ca3913dSOlivier Deprez /*******************************************************************************
340*0ca3913dSOlivier Deprez  * This function is the default implementation of the driver clone function.
341*0ca3913dSOlivier Deprez  * It creates a new channel and returns a pointer to it.
342*0ca3913dSOlivier Deprez  * It clones channel into new_channel.
343*0ca3913dSOlivier Deprez  ******************************************************************************/
344*0ca3913dSOlivier Deprez chan_t *devclone(chan_t *channel, chan_t *new_channel)
345*0ca3913dSOlivier Deprez {
346*0ca3913dSOlivier Deprez 	if (channel == NULL) {
347*0ca3913dSOlivier Deprez 		return NULL;
348*0ca3913dSOlivier Deprez 	}
349*0ca3913dSOlivier Deprez 
350*0ca3913dSOlivier Deprez 	if (new_channel == NULL) {
351*0ca3913dSOlivier Deprez 		new_channel = create_new_channel(channel->index);
352*0ca3913dSOlivier Deprez 		if (new_channel == NULL) {
353*0ca3913dSOlivier Deprez 			return NULL;
354*0ca3913dSOlivier Deprez 		}
355*0ca3913dSOlivier Deprez 	}
356*0ca3913dSOlivier Deprez 
357*0ca3913dSOlivier Deprez 	new_channel->qid    = channel->qid;
358*0ca3913dSOlivier Deprez 	new_channel->dev    = channel->dev;
359*0ca3913dSOlivier Deprez 	new_channel->mode   = channel->mode;
360*0ca3913dSOlivier Deprez 	new_channel->offset = channel->offset;
361*0ca3913dSOlivier Deprez 	new_channel->index  = channel->index;
362*0ca3913dSOlivier Deprez 
363*0ca3913dSOlivier Deprez 	return new_channel;
364*0ca3913dSOlivier Deprez }
365*0ca3913dSOlivier Deprez 
366*0ca3913dSOlivier Deprez /*******************************************************************************
367*0ca3913dSOlivier Deprez  * This function is the default implementation of the driver walk function.
368*0ca3913dSOlivier Deprez  * It goes through all the elements of tab using the gen function until a match
369*0ca3913dSOlivier Deprez  * is found with name.
370*0ca3913dSOlivier Deprez  * If a match is found, it copies the qid of the new directory.
371*0ca3913dSOlivier Deprez  ******************************************************************************/
372*0ca3913dSOlivier Deprez int devwalk(chan_t *channel, const char *name, const dirtab_t *tab,
373*0ca3913dSOlivier Deprez 	    int ntab, devgen_t *gen)
374*0ca3913dSOlivier Deprez {
375*0ca3913dSOlivier Deprez 	int i;
376*0ca3913dSOlivier Deprez 	dir_t dir;
377*0ca3913dSOlivier Deprez 
378*0ca3913dSOlivier Deprez 	if ((channel == NULL) || (name == NULL) || (gen == NULL)) {
379*0ca3913dSOlivier Deprez 		return -1;
380*0ca3913dSOlivier Deprez 	}
381*0ca3913dSOlivier Deprez 
382*0ca3913dSOlivier Deprez 	if ((name[0] == '.') && (name[1] == '\0')) {
383*0ca3913dSOlivier Deprez 		return 1;
384*0ca3913dSOlivier Deprez 	}
385*0ca3913dSOlivier Deprez 
386*0ca3913dSOlivier Deprez 	for (i = 0; ; i++) {
387*0ca3913dSOlivier Deprez 		switch ((*gen)(channel, tab, ntab, i, &dir)) {
388*0ca3913dSOlivier Deprez 		case 0:
389*0ca3913dSOlivier Deprez 			/* Intentional fall-through */
390*0ca3913dSOlivier Deprez 		case -1:
391*0ca3913dSOlivier Deprez 			return -1;
392*0ca3913dSOlivier Deprez 		case 1:
393*0ca3913dSOlivier Deprez 			if (strncmp(name, dir.name, NAMELEN) != 0) {
394*0ca3913dSOlivier Deprez 				continue;
395*0ca3913dSOlivier Deprez 			}
396*0ca3913dSOlivier Deprez 			channel->qid = dir.qid;
397*0ca3913dSOlivier Deprez 			return 1;
398*0ca3913dSOlivier Deprez 		}
399*0ca3913dSOlivier Deprez 	}
400*0ca3913dSOlivier Deprez }
401*0ca3913dSOlivier Deprez 
402*0ca3913dSOlivier Deprez /*******************************************************************************
403*0ca3913dSOlivier Deprez  * This is a helper function which exposes the content of a directory, element
404*0ca3913dSOlivier Deprez  * by element. It is meant to be called until the end of the directory is
405*0ca3913dSOlivier Deprez  * reached or an error occurs.
406*0ca3913dSOlivier Deprez  * It returns -1 on error, 0 on end of directory and 1 when a new file is found.
407*0ca3913dSOlivier Deprez  ******************************************************************************/
408*0ca3913dSOlivier Deprez int dirread(chan_t *channel, dir_t *dir, const dirtab_t *tab,
409*0ca3913dSOlivier Deprez 	int ntab, devgen_t *gen)
410*0ca3913dSOlivier Deprez {
411*0ca3913dSOlivier Deprez 	int i, ret;
412*0ca3913dSOlivier Deprez 
413*0ca3913dSOlivier Deprez 	if ((channel == NULL) || (dir == NULL) || (gen == NULL)) {
414*0ca3913dSOlivier Deprez 		return -1;
415*0ca3913dSOlivier Deprez 	}
416*0ca3913dSOlivier Deprez 
417*0ca3913dSOlivier Deprez 	i = channel->offset/sizeof(dir_t);
418*0ca3913dSOlivier Deprez 	ret = (*gen)(channel, tab, ntab, i, dir);
419*0ca3913dSOlivier Deprez 	if (ret == 1) {
420*0ca3913dSOlivier Deprez 		channel->offset += sizeof(dir_t);
421*0ca3913dSOlivier Deprez 	}
422*0ca3913dSOlivier Deprez 
423*0ca3913dSOlivier Deprez 	return ret;
424*0ca3913dSOlivier Deprez }
425*0ca3913dSOlivier Deprez 
426*0ca3913dSOlivier Deprez /*******************************************************************************
427*0ca3913dSOlivier Deprez  * This function sets the elements of dir.
428*0ca3913dSOlivier Deprez  ******************************************************************************/
429*0ca3913dSOlivier Deprez void make_dir_entry(chan_t *channel, dir_t *dir,
430*0ca3913dSOlivier Deprez 	     const char *name, long length, qid_t qid, unsigned int mode)
431*0ca3913dSOlivier Deprez {
432*0ca3913dSOlivier Deprez 	if ((channel == NULL) || (dir == NULL) || (name == NULL)) {
433*0ca3913dSOlivier Deprez 		return;
434*0ca3913dSOlivier Deprez 	}
435*0ca3913dSOlivier Deprez 
436*0ca3913dSOlivier Deprez 	strlcpy(dir->name, name, sizeof(dir->name));
437*0ca3913dSOlivier Deprez 	dir->length = length;
438*0ca3913dSOlivier Deprez 	dir->qid = qid;
439*0ca3913dSOlivier Deprez 	dir->mode = mode;
440*0ca3913dSOlivier Deprez 
441*0ca3913dSOlivier Deprez 	if ((qid & CHDIR) != 0) {
442*0ca3913dSOlivier Deprez 		dir->mode |= O_DIR;
443*0ca3913dSOlivier Deprez 	}
444*0ca3913dSOlivier Deprez 
445*0ca3913dSOlivier Deprez 	dir->index = channel->index;
446*0ca3913dSOlivier Deprez 	dir->dev   = channel->dev;
447*0ca3913dSOlivier Deprez }
448*0ca3913dSOlivier Deprez 
449*0ca3913dSOlivier Deprez /*******************************************************************************
450*0ca3913dSOlivier Deprez  * This function is the default implementation of the internal driver gen
451*0ca3913dSOlivier Deprez  * function.
452*0ca3913dSOlivier Deprez  * It copies and formats the information of the nth element of tab into dir.
453*0ca3913dSOlivier Deprez  ******************************************************************************/
454*0ca3913dSOlivier Deprez int devgen(chan_t *channel, const dirtab_t *tab, int ntab, int n, dir_t *dir)
455*0ca3913dSOlivier Deprez {
456*0ca3913dSOlivier Deprez 	const dirtab_t *dp;
457*0ca3913dSOlivier Deprez 
458*0ca3913dSOlivier Deprez 	if ((channel == NULL) || (dir == NULL) || (tab == NULL) ||
459*0ca3913dSOlivier Deprez 			(n >= ntab)) {
460*0ca3913dSOlivier Deprez 		return 0;
461*0ca3913dSOlivier Deprez 	}
462*0ca3913dSOlivier Deprez 
463*0ca3913dSOlivier Deprez 	dp = &tab[n];
464*0ca3913dSOlivier Deprez 	make_dir_entry(channel, dir, dp->name, dp->length, dp->qid, dp->perm);
465*0ca3913dSOlivier Deprez 	return 1;
466*0ca3913dSOlivier Deprez }
467*0ca3913dSOlivier Deprez 
468*0ca3913dSOlivier Deprez /*******************************************************************************
469*0ca3913dSOlivier Deprez  * This function returns a file descriptor identifying the channel associated to
470*0ca3913dSOlivier Deprez  * the given path.
471*0ca3913dSOlivier Deprez  ******************************************************************************/
472*0ca3913dSOlivier Deprez int open(const char *path, int mode)
473*0ca3913dSOlivier Deprez {
474*0ca3913dSOlivier Deprez 	chan_t *channel;
475*0ca3913dSOlivier Deprez 
476*0ca3913dSOlivier Deprez 	if (path == NULL) {
477*0ca3913dSOlivier Deprez 		return -1;
478*0ca3913dSOlivier Deprez 	}
479*0ca3913dSOlivier Deprez 
480*0ca3913dSOlivier Deprez 	if (is_valid_mode(mode) == false) {
481*0ca3913dSOlivier Deprez 		return -1;
482*0ca3913dSOlivier Deprez 	}
483*0ca3913dSOlivier Deprez 
484*0ca3913dSOlivier Deprez 	channel = path_to_channel(path, mode);
485*0ca3913dSOlivier Deprez 
486*0ca3913dSOlivier Deprez 	return channel_to_fd(channel);
487*0ca3913dSOlivier Deprez }
488*0ca3913dSOlivier Deprez 
489*0ca3913dSOlivier Deprez /*******************************************************************************
490*0ca3913dSOlivier Deprez  * This function closes the channel identified by the file descriptor fd.
491*0ca3913dSOlivier Deprez  ******************************************************************************/
492*0ca3913dSOlivier Deprez int close(int fd)
493*0ca3913dSOlivier Deprez {
494*0ca3913dSOlivier Deprez 	chan_t *channel;
495*0ca3913dSOlivier Deprez 
496*0ca3913dSOlivier Deprez 	channel = fd_to_channel(fd);
497*0ca3913dSOlivier Deprez 	if (channel == NULL) {
498*0ca3913dSOlivier Deprez 		return -1;
499*0ca3913dSOlivier Deprez 	}
500*0ca3913dSOlivier Deprez 
501*0ca3913dSOlivier Deprez 	channel_close(channel);
502*0ca3913dSOlivier Deprez 	return 0;
503*0ca3913dSOlivier Deprez }
504*0ca3913dSOlivier Deprez 
505*0ca3913dSOlivier Deprez /*******************************************************************************
506*0ca3913dSOlivier Deprez  * This function is the default implementation of the driver stat function.
507*0ca3913dSOlivier Deprez  * It goes through all the elements of tab using the gen function until a match
508*0ca3913dSOlivier Deprez  * is found with file.
509*0ca3913dSOlivier Deprez  * If a match is found, dir contains the information file.
510*0ca3913dSOlivier Deprez  ******************************************************************************/
511*0ca3913dSOlivier Deprez int devstat(chan_t *dirc, const char *file, dir_t *dir,
512*0ca3913dSOlivier Deprez 	    const dirtab_t *tab, int ntab, devgen_t *gen)
513*0ca3913dSOlivier Deprez {
514*0ca3913dSOlivier Deprez 	int i, r = 0;
515*0ca3913dSOlivier Deprez 	chan_t *c, *mnt;
516*0ca3913dSOlivier Deprez 
517*0ca3913dSOlivier Deprez 	if ((dirc == NULL) || (dir == NULL) || (gen == NULL)) {
518*0ca3913dSOlivier Deprez 		return -1;
519*0ca3913dSOlivier Deprez 	}
520*0ca3913dSOlivier Deprez 
521*0ca3913dSOlivier Deprez 	c = path_to_channel(file, O_STAT);
522*0ca3913dSOlivier Deprez 	if (c == NULL) {
523*0ca3913dSOlivier Deprez 		return -1;
524*0ca3913dSOlivier Deprez 	}
525*0ca3913dSOlivier Deprez 
526*0ca3913dSOlivier Deprez 	for (i = 0; ; i++) {
527*0ca3913dSOlivier Deprez 		switch ((*gen)(dirc, tab, ntab, i, dir)) {
528*0ca3913dSOlivier Deprez 		case 0:
529*0ca3913dSOlivier Deprez 			/* Intentional fall-through */
530*0ca3913dSOlivier Deprez 		case -1:
531*0ca3913dSOlivier Deprez 			r = -1;
532*0ca3913dSOlivier Deprez 			goto leave;
533*0ca3913dSOlivier Deprez 		case 1:
534*0ca3913dSOlivier Deprez 			mnt = mount_point_to_channel(dir->index, dir->qid);
535*0ca3913dSOlivier Deprez 			if (mnt != NULL) {
536*0ca3913dSOlivier Deprez 				dir->qid = mnt->qid;
537*0ca3913dSOlivier Deprez 				dir->index = mnt->index;
538*0ca3913dSOlivier Deprez 			}
539*0ca3913dSOlivier Deprez 
540*0ca3913dSOlivier Deprez 			if ((dir->qid != c->qid) || (dir->index != c->index)) {
541*0ca3913dSOlivier Deprez 				continue;
542*0ca3913dSOlivier Deprez 			}
543*0ca3913dSOlivier Deprez 
544*0ca3913dSOlivier Deprez 			goto leave;
545*0ca3913dSOlivier Deprez 		}
546*0ca3913dSOlivier Deprez 	}
547*0ca3913dSOlivier Deprez 
548*0ca3913dSOlivier Deprez leave:
549*0ca3913dSOlivier Deprez 	channel_close(c);
550*0ca3913dSOlivier Deprez 	return r;
551*0ca3913dSOlivier Deprez }
552*0ca3913dSOlivier Deprez 
553*0ca3913dSOlivier Deprez /*******************************************************************************
554*0ca3913dSOlivier Deprez  * This function calls the stat function of the driver associated to the parent
555*0ca3913dSOlivier Deprez  * directory of the file in path.
556*0ca3913dSOlivier Deprez  * The result is stored in dir.
557*0ca3913dSOlivier Deprez  ******************************************************************************/
558*0ca3913dSOlivier Deprez int stat(const char *path, dir_t *dir)
559*0ca3913dSOlivier Deprez {
560*0ca3913dSOlivier Deprez 	int r;
561*0ca3913dSOlivier Deprez 	size_t len;
562*0ca3913dSOlivier Deprez 	chan_t *channel;
563*0ca3913dSOlivier Deprez 	char *p, dirname[PATHLEN];
564*0ca3913dSOlivier Deprez 
565*0ca3913dSOlivier Deprez 	if ((path == NULL) || (dir == NULL)) {
566*0ca3913dSOlivier Deprez 		return -1;
567*0ca3913dSOlivier Deprez 	}
568*0ca3913dSOlivier Deprez 
569*0ca3913dSOlivier Deprez 	len = strlen(path);
570*0ca3913dSOlivier Deprez 	if ((len + 1) > sizeof(dirname)) {
571*0ca3913dSOlivier Deprez 		return -1;
572*0ca3913dSOlivier Deprez 	}
573*0ca3913dSOlivier Deprez 
574*0ca3913dSOlivier Deprez 	memcpy(dirname, path, len);
575*0ca3913dSOlivier Deprez 	for (p = dirname + len; p > dirname; --p) {
576*0ca3913dSOlivier Deprez 		if (*p != '/') {
577*0ca3913dSOlivier Deprez 			break;
578*0ca3913dSOlivier Deprez 		}
579*0ca3913dSOlivier Deprez 	}
580*0ca3913dSOlivier Deprez 
581*0ca3913dSOlivier Deprez 	p = memrchr(dirname, '/', p - dirname);
582*0ca3913dSOlivier Deprez 	if (p == NULL) {
583*0ca3913dSOlivier Deprez 		return -1;
584*0ca3913dSOlivier Deprez 	}
585*0ca3913dSOlivier Deprez 
586*0ca3913dSOlivier Deprez 	dirname[p - dirname + 1] = '\0';
587*0ca3913dSOlivier Deprez 
588*0ca3913dSOlivier Deprez 	channel = path_to_channel(dirname, O_STAT);
589*0ca3913dSOlivier Deprez 	if (channel == NULL) {
590*0ca3913dSOlivier Deprez 		return -1;
591*0ca3913dSOlivier Deprez 	}
592*0ca3913dSOlivier Deprez 
593*0ca3913dSOlivier Deprez 	r = devtab[channel->index]->stat(channel, path, dir);
594*0ca3913dSOlivier Deprez 	channel_close(channel);
595*0ca3913dSOlivier Deprez 
596*0ca3913dSOlivier Deprez 	return r;
597*0ca3913dSOlivier Deprez }
598*0ca3913dSOlivier Deprez 
599*0ca3913dSOlivier Deprez /*******************************************************************************
600*0ca3913dSOlivier Deprez  * This function calls the read function of the driver associated to fd.
601*0ca3913dSOlivier Deprez  * It fills buf with at most n bytes.
602*0ca3913dSOlivier Deprez  * It returns the number of bytes that were actually read.
603*0ca3913dSOlivier Deprez  ******************************************************************************/
604*0ca3913dSOlivier Deprez int read(int fd, void *buf, int n)
605*0ca3913dSOlivier Deprez {
606*0ca3913dSOlivier Deprez 	chan_t *channel;
607*0ca3913dSOlivier Deprez 
608*0ca3913dSOlivier Deprez 	if (buf == NULL) {
609*0ca3913dSOlivier Deprez 		return -1;
610*0ca3913dSOlivier Deprez 	}
611*0ca3913dSOlivier Deprez 
612*0ca3913dSOlivier Deprez 	channel = fd_to_channel(fd);
613*0ca3913dSOlivier Deprez 	if (channel == NULL) {
614*0ca3913dSOlivier Deprez 		return -1;
615*0ca3913dSOlivier Deprez 	}
616*0ca3913dSOlivier Deprez 
617*0ca3913dSOlivier Deprez 	if (((channel->qid & CHDIR) != 0) && (n < sizeof(dir_t))) {
618*0ca3913dSOlivier Deprez 		return -1;
619*0ca3913dSOlivier Deprez 	}
620*0ca3913dSOlivier Deprez 
621*0ca3913dSOlivier Deprez 	return devtab[channel->index]->read(channel, buf, n);
622*0ca3913dSOlivier Deprez }
623*0ca3913dSOlivier Deprez 
624*0ca3913dSOlivier Deprez /*******************************************************************************
625*0ca3913dSOlivier Deprez  * This function calls the write function of the driver associated to fd.
626*0ca3913dSOlivier Deprez  * It writes at most n bytes of buf.
627*0ca3913dSOlivier Deprez  * It returns the number of bytes that were actually written.
628*0ca3913dSOlivier Deprez  ******************************************************************************/
629*0ca3913dSOlivier Deprez int write(int fd, void *buf, int n)
630*0ca3913dSOlivier Deprez {
631*0ca3913dSOlivier Deprez 	chan_t *channel;
632*0ca3913dSOlivier Deprez 
633*0ca3913dSOlivier Deprez 	if (buf == NULL) {
634*0ca3913dSOlivier Deprez 		return -1;
635*0ca3913dSOlivier Deprez 	}
636*0ca3913dSOlivier Deprez 
637*0ca3913dSOlivier Deprez 	channel = fd_to_channel(fd);
638*0ca3913dSOlivier Deprez 	if (channel == NULL) {
639*0ca3913dSOlivier Deprez 		return -1;
640*0ca3913dSOlivier Deprez 	}
641*0ca3913dSOlivier Deprez 
642*0ca3913dSOlivier Deprez 	if ((channel->qid & CHDIR) != 0) {
643*0ca3913dSOlivier Deprez 		return -1;
644*0ca3913dSOlivier Deprez 	}
645*0ca3913dSOlivier Deprez 
646*0ca3913dSOlivier Deprez 	return devtab[channel->index]->write(channel, buf, n);
647*0ca3913dSOlivier Deprez }
648*0ca3913dSOlivier Deprez 
649*0ca3913dSOlivier Deprez /*******************************************************************************
650*0ca3913dSOlivier Deprez  * This function calls the seek function of the driver associated to fd.
651*0ca3913dSOlivier Deprez  * It applies the offset off according to the strategy whence.
652*0ca3913dSOlivier Deprez  ******************************************************************************/
653*0ca3913dSOlivier Deprez int seek(int fd, long off, int whence)
654*0ca3913dSOlivier Deprez {
655*0ca3913dSOlivier Deprez 	chan_t *channel;
656*0ca3913dSOlivier Deprez 
657*0ca3913dSOlivier Deprez 	channel = fd_to_channel(fd);
658*0ca3913dSOlivier Deprez 	if (channel == NULL) {
659*0ca3913dSOlivier Deprez 		return -1;
660*0ca3913dSOlivier Deprez 	}
661*0ca3913dSOlivier Deprez 
662*0ca3913dSOlivier Deprez 	if ((channel->qid & CHDIR) != 0) {
663*0ca3913dSOlivier Deprez 		return -1;
664*0ca3913dSOlivier Deprez 	}
665*0ca3913dSOlivier Deprez 
666*0ca3913dSOlivier Deprez 	return devtab[channel->index]->seek(channel, off, whence);
667*0ca3913dSOlivier Deprez }
668*0ca3913dSOlivier Deprez 
669*0ca3913dSOlivier Deprez /*******************************************************************************
670*0ca3913dSOlivier Deprez  * This function is the default error implementation of the driver mount
671*0ca3913dSOlivier Deprez  * function.
672*0ca3913dSOlivier Deprez  ******************************************************************************/
673*0ca3913dSOlivier Deprez chan_t *deverrmount(chan_t *channel, const char *spec)
674*0ca3913dSOlivier Deprez {
675*0ca3913dSOlivier Deprez 	return NULL;
676*0ca3913dSOlivier Deprez }
677*0ca3913dSOlivier Deprez 
678*0ca3913dSOlivier Deprez /*******************************************************************************
679*0ca3913dSOlivier Deprez  * This function is the default error implementation of the driver write
680*0ca3913dSOlivier Deprez  * function.
681*0ca3913dSOlivier Deprez  ******************************************************************************/
682*0ca3913dSOlivier Deprez int deverrwrite(chan_t *channel, void *buf, int n)
683*0ca3913dSOlivier Deprez {
684*0ca3913dSOlivier Deprez 	return -1;
685*0ca3913dSOlivier Deprez }
686*0ca3913dSOlivier Deprez 
687*0ca3913dSOlivier Deprez /*******************************************************************************
688*0ca3913dSOlivier Deprez  * This function is the default error implementation of the driver seek
689*0ca3913dSOlivier Deprez  * function.
690*0ca3913dSOlivier Deprez  ******************************************************************************/
691*0ca3913dSOlivier Deprez int deverrseek(chan_t *channel, long off, int whence)
692*0ca3913dSOlivier Deprez {
693*0ca3913dSOlivier Deprez 	return -1;
694*0ca3913dSOlivier Deprez }
695*0ca3913dSOlivier Deprez 
696*0ca3913dSOlivier Deprez /*******************************************************************************
697*0ca3913dSOlivier Deprez  * This function is the default implementation of the driver seek function.
698*0ca3913dSOlivier Deprez  * It applies the offset off according to the strategy whence to the channel c.
699*0ca3913dSOlivier Deprez  ******************************************************************************/
700*0ca3913dSOlivier Deprez int devseek(chan_t *channel, long off, int whence)
701*0ca3913dSOlivier Deprez {
702*0ca3913dSOlivier Deprez 	switch (whence) {
703*0ca3913dSOlivier Deprez 	case KSEEK_SET:
704*0ca3913dSOlivier Deprez 		channel->offset = off;
705*0ca3913dSOlivier Deprez 		break;
706*0ca3913dSOlivier Deprez 	case KSEEK_CUR:
707*0ca3913dSOlivier Deprez 		channel->offset += off;
708*0ca3913dSOlivier Deprez 		break;
709*0ca3913dSOlivier Deprez 	case KSEEK_END:
710*0ca3913dSOlivier Deprez 		/* Not implemented */
711*0ca3913dSOlivier Deprez 		return -1;
712*0ca3913dSOlivier Deprez 	}
713*0ca3913dSOlivier Deprez 
714*0ca3913dSOlivier Deprez 	return 0;
715*0ca3913dSOlivier Deprez }
716*0ca3913dSOlivier Deprez 
717*0ca3913dSOlivier Deprez /*******************************************************************************
718*0ca3913dSOlivier Deprez  * This function registers the channel associated to the path new as a mount
719*0ca3913dSOlivier Deprez  * point for the channel c.
720*0ca3913dSOlivier Deprez  ******************************************************************************/
721*0ca3913dSOlivier Deprez static int add_mount_point(chan_t *channel, const char *new)
722*0ca3913dSOlivier Deprez {
723*0ca3913dSOlivier Deprez 	int i;
724*0ca3913dSOlivier Deprez 	chan_t *cn;
725*0ca3913dSOlivier Deprez 	struct mount_point *mp;
726*0ca3913dSOlivier Deprez 
727*0ca3913dSOlivier Deprez 	if (new == NULL) {
728*0ca3913dSOlivier Deprez 		goto err0;
729*0ca3913dSOlivier Deprez 	}
730*0ca3913dSOlivier Deprez 
731*0ca3913dSOlivier Deprez 	cn = path_to_channel(new, O_READ);
732*0ca3913dSOlivier Deprez 	if (cn == NULL) {
733*0ca3913dSOlivier Deprez 		goto err0;
734*0ca3913dSOlivier Deprez 	}
735*0ca3913dSOlivier Deprez 
736*0ca3913dSOlivier Deprez 	if ((cn->qid & CHDIR) == 0) {
737*0ca3913dSOlivier Deprez 		goto err1;
738*0ca3913dSOlivier Deprez 	}
739*0ca3913dSOlivier Deprez 
740*0ca3913dSOlivier Deprez 	for (i = NR_MOUNT_POINTS - 1; i >= 0; i--) {
741*0ca3913dSOlivier Deprez 		mp = &mount_points[i];
742*0ca3913dSOlivier Deprez 		if (mp->new == NULL) {
743*0ca3913dSOlivier Deprez 			break;
744*0ca3913dSOlivier Deprez 		}
745*0ca3913dSOlivier Deprez 	}
746*0ca3913dSOlivier Deprez 
747*0ca3913dSOlivier Deprez 	if (i < 0) {
748*0ca3913dSOlivier Deprez 		goto err1;
749*0ca3913dSOlivier Deprez 	}
750*0ca3913dSOlivier Deprez 
751*0ca3913dSOlivier Deprez 	mp->new = cn;
752*0ca3913dSOlivier Deprez 	mp->old = channel;
753*0ca3913dSOlivier Deprez 
754*0ca3913dSOlivier Deprez 	return 0;
755*0ca3913dSOlivier Deprez 
756*0ca3913dSOlivier Deprez err1:
757*0ca3913dSOlivier Deprez 	channel_close(cn);
758*0ca3913dSOlivier Deprez err0:
759*0ca3913dSOlivier Deprez 	return -1;
760*0ca3913dSOlivier Deprez }
761*0ca3913dSOlivier Deprez 
762*0ca3913dSOlivier Deprez /*******************************************************************************
763*0ca3913dSOlivier Deprez  * This function registers the path new as a mount point for the path old.
764*0ca3913dSOlivier Deprez  ******************************************************************************/
765*0ca3913dSOlivier Deprez int bind(const char *old, const char *new)
766*0ca3913dSOlivier Deprez {
767*0ca3913dSOlivier Deprez 	chan_t *channel;
768*0ca3913dSOlivier Deprez 
769*0ca3913dSOlivier Deprez 	channel = path_to_channel(old, O_BIND);
770*0ca3913dSOlivier Deprez 	if (channel == NULL) {
771*0ca3913dSOlivier Deprez 		return -1;
772*0ca3913dSOlivier Deprez 	}
773*0ca3913dSOlivier Deprez 
774*0ca3913dSOlivier Deprez 	if (add_mount_point(channel, new) < 0) {
775*0ca3913dSOlivier Deprez 		channel_close(channel);
776*0ca3913dSOlivier Deprez 		return -1;
777*0ca3913dSOlivier Deprez 	}
778*0ca3913dSOlivier Deprez 
779*0ca3913dSOlivier Deprez 	return 0;
780*0ca3913dSOlivier Deprez }
781*0ca3913dSOlivier Deprez 
782*0ca3913dSOlivier Deprez /*******************************************************************************
783*0ca3913dSOlivier Deprez  * This function calls the mount function of the driver associated to the path
784*0ca3913dSOlivier Deprez  * srv.
785*0ca3913dSOlivier Deprez  * It mounts the path srv on the path where.
786*0ca3913dSOlivier Deprez  ******************************************************************************/
787*0ca3913dSOlivier Deprez int mount(const char *srv, const char *where, const char *spec)
788*0ca3913dSOlivier Deprez {
789*0ca3913dSOlivier Deprez 	chan_t *channel, *mount_point_chan;
790*0ca3913dSOlivier Deprez 	int ret;
791*0ca3913dSOlivier Deprez 
792*0ca3913dSOlivier Deprez 	channel = path_to_channel(srv, O_RDWR);
793*0ca3913dSOlivier Deprez 	if (channel == NULL) {
794*0ca3913dSOlivier Deprez 		goto err0;
795*0ca3913dSOlivier Deprez 	}
796*0ca3913dSOlivier Deprez 
797*0ca3913dSOlivier Deprez 	mount_point_chan = devtab[channel->index]->mount(channel, spec);
798*0ca3913dSOlivier Deprez 	if (mount_point_chan == NULL) {
799*0ca3913dSOlivier Deprez 		goto err1;
800*0ca3913dSOlivier Deprez 	}
801*0ca3913dSOlivier Deprez 
802*0ca3913dSOlivier Deprez 	ret = add_mount_point(mount_point_chan, where);
803*0ca3913dSOlivier Deprez 	if (ret < 0) {
804*0ca3913dSOlivier Deprez 		goto err2;
805*0ca3913dSOlivier Deprez 	}
806*0ca3913dSOlivier Deprez 
807*0ca3913dSOlivier Deprez 	channel_close(channel);
808*0ca3913dSOlivier Deprez 
809*0ca3913dSOlivier Deprez 	return 0;
810*0ca3913dSOlivier Deprez 
811*0ca3913dSOlivier Deprez err2:
812*0ca3913dSOlivier Deprez 	channel_close(mount_point_chan);
813*0ca3913dSOlivier Deprez err1:
814*0ca3913dSOlivier Deprez 	channel_close(channel);
815*0ca3913dSOlivier Deprez err0:
816*0ca3913dSOlivier Deprez 	return -1;
817*0ca3913dSOlivier Deprez }
818*0ca3913dSOlivier Deprez 
819*0ca3913dSOlivier Deprez /*******************************************************************************
820*0ca3913dSOlivier Deprez  * This function initializes the device environment.
821*0ca3913dSOlivier Deprez  * It creates the '/' channel.
822*0ca3913dSOlivier Deprez  * It links the device drivers to the physical drivers.
823*0ca3913dSOlivier Deprez  ******************************************************************************/
824*0ca3913dSOlivier Deprez void debugfs_init(void)
825*0ca3913dSOlivier Deprez {
826*0ca3913dSOlivier Deprez 	chan_t *channel, *cloned_channel;
827*0ca3913dSOlivier Deprez 
828*0ca3913dSOlivier Deprez 	for (channel = fdset; channel < &fdset[NR_CHANS]; channel++) {
829*0ca3913dSOlivier Deprez 		channel_clear(channel);
830*0ca3913dSOlivier Deprez 	}
831*0ca3913dSOlivier Deprez 
832*0ca3913dSOlivier Deprez 	channel = devattach('/', 0);
833*0ca3913dSOlivier Deprez 	if (channel == NULL) {
834*0ca3913dSOlivier Deprez 		panic();
835*0ca3913dSOlivier Deprez 	}
836*0ca3913dSOlivier Deprez 
837*0ca3913dSOlivier Deprez 	cloned_channel = clone(channel, &slash_channel);
838*0ca3913dSOlivier Deprez 	if (cloned_channel == NULL) {
839*0ca3913dSOlivier Deprez 		panic();
840*0ca3913dSOlivier Deprez 	}
841*0ca3913dSOlivier Deprez 
842*0ca3913dSOlivier Deprez 	channel_close(channel);
843*0ca3913dSOlivier Deprez 	devlink();
844*0ca3913dSOlivier Deprez }
845*0ca3913dSOlivier Deprez 
846*0ca3913dSOlivier Deprez __dead2 void devpanic(const char *cause)
847*0ca3913dSOlivier Deprez {
848*0ca3913dSOlivier Deprez 	panic();
849*0ca3913dSOlivier Deprez }
850