1 /*        $NetBSD: devopen.c,v 1.11 2012/12/19 13:53:47 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 
36 static 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  */
48 static int
devparse(const char * fname,int * dev,int * ctlr,int * unit,int * lunit,int * part,char ** file)49 devparse(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 
135 int
devopen(struct open_file * f,const char * fname,char ** file)136 devopen(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