1/*	$NetBSD: devopen.c,v 1.10 2010/10/14 06:39:52 kiyohara Exp $	*/
2
3/*-
4 *  Copyright (c) 1993 John Brezak
5 *  All rights reserved.
6 *
7 *  Redistribution and use in source and binary forms, with or without
8 *  modification, are permitted provided that the following conditions
9 *  are met:
10 *  1. Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 *  2. Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 *  3. The name of the author may not be used to endorse or promote products
16 *     derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <lib/libsa/stand.h>
32#include <lib/libkern/libkern.h>
33#include <sys/param.h>
34#include <sys/reboot.h>
35
36static int devparse(const char *, int *, int *, int *, int *, int *, char **);
37
38
39/*
40 * Parse a device spec.
41 *   i.e.
42 *     /dev/disk/floppy
43 *     /dev/disk/ide/0/master/0_n
44 *     /dev/disk/ide/0/slave/0_n
45 *     /dev/disk/scsi/000/0_n
46 *     /dev/disk/scsi/030/0_n
47 */
48static int
49devparse(const char *fname, int *dev, int *ctlr, int *unit, int *lunit,
50	 int *part, char **file)
51{
52	int i;
53	char devdir[] = "/dev/disk/";
54	char floppy[] = "floppy";
55	char ide[] = "ide";
56	char scsi[] = "scsi";
57	char *p;
58
59	if (strncmp(fname, devdir, strlen(devdir)) != 0)
60		return EINVAL;
61	p = __UNCONST(fname) + strlen(devdir);
62
63	if (strncmp(p, floppy, strlen(floppy)) == 0) {
64		p += strlen(floppy);
65		for (i = 0; devsw[i].dv_name != NULL; i++)
66			if (strcmp(devsw[i].dv_name, "fd") == 0) {
67				*dev = i;
68				*ctlr = 0;
69				*unit = 1;
70				*lunit = 0;
71				break;
72			}
73	} else if (strncmp(p, ide, strlen(ide)) == 0) {
74		char master[] = "master";
75		char slave[] = "slave";
76
77		p += strlen(ide);
78		if (*p++ != '/' ||
79		    !isdigit(*p++) ||
80		    *p++ != '/')
81			return EINVAL;
82		*ctlr = *(p - 2) - '0';
83		if (strncmp(p, master, strlen(master)) == 0) {
84			*unit = 0;
85			p += strlen(master);
86		} else if (strncmp(p, slave, strlen(slave)) == 0) {
87			*unit = 1;
88			p += strlen(slave);
89		} else
90			return EINVAL;
91		if (*p++ != '/' ||
92		    !isdigit(*p++) ||
93		    *p++ != '_' ||
94		    !isdigit(*p++))
95			return EINVAL;
96		*lunit = *(p - 3) - '0';
97		*part = *(p - 1) - '0';
98		for (i = 0; devsw[i].dv_name != NULL; i++)
99			if (strcmp(devsw[i].dv_name, "wd") == 0) {
100				*dev = i;
101				break;
102			}
103		if (devsw[i].dv_name == NULL)
104			return EINVAL;
105	} else if (strncmp(p, scsi, strlen(scsi)) == 0) {
106		p += strlen(scsi);
107		if (*p++ != '/' ||
108		    !isdigit(*p++) ||
109		    !isdigit(*p++) ||
110		    !isdigit(*p++) ||
111		    *p++ != '/' ||
112		    !isdigit(*p++) ||
113		    *p++ != '_' ||
114		    !isdigit(*p++))
115			return EINVAL;
116		*ctlr = *(p - 7) - '0';
117		*unit = *(p - 6) - '0';
118		*lunit = *(p - 5) - '0';
119		*part = *(p - 1) - '0';
120		for (i = 0; devsw[i].dv_name != NULL; i++)
121			if (strcmp(devsw[i].dv_name, "sd") == 0) {
122				*dev = i;
123				break;
124			}
125		if (devsw[i].dv_name == NULL)
126			return EINVAL;
127	}
128
129	if (*p++ != ':')
130		return EINVAL;
131	*file = p;
132	return 0;
133}
134
135int
136devopen(struct open_file *f, const char *fname, char **file)
137{
138	int error;
139	int dev = 0, ctlr = 0, unit = 0, lunit = 0, part = 0;
140	struct devsw *dp = &devsw[0];
141	extern struct devsw pseudo_devsw;
142
143	**file = '\0';
144	error = devparse(fname, &dev, &ctlr, &unit, &lunit, &part, file);
145	if (error == 0) {
146		dp = &devsw[dev];
147		if (!dp->dv_open)
148			return ENODEV;
149	} else {
150		if (strcmp(fname, "in") == 0)
151			/* special case: kernel in memory */
152			dp = &pseudo_devsw;
153		else
154			return error;
155	}
156
157	f->f_dev = dp;
158	if ((error = (*dp->dv_open)(f, ctlr, unit, lunit, part)) == 0)
159		return 0;
160
161	printf("%s %s\n", fname, strerror(error));
162
163	return error;
164}
165