Commit | Line | Data |
---|---|---|
8a8c3c41 KB |
1 | /*- |
2 | * Copyright (c) 1982, 1988 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * %sccs.include.proprietary.c% | |
6 | * | |
de95853c | 7 | * @(#)open.c 7.2 (Berkeley) %G% |
8a8c3c41 KB |
8 | */ |
9 | ||
10 | #include <sys/param.h> | |
11 | #include <sys/reboot.h> | |
12 | #include <ufs/dir.h> | |
13 | #include "saio.h" | |
14 | ||
15 | int firstopen; | |
16 | u_int opendev; /* last device opened */ | |
17 | extern u_int bootdev; | |
18 | ||
19 | struct dirstuff { | |
20 | int loc; | |
21 | struct iob *io; | |
22 | }; | |
23 | ||
24 | #ifndef SMALL | |
25 | static ino_t dlook __P((char *, struct iob *, char *)); | |
26 | static int find __P((char *, struct iob *)); | |
27 | static int getdev __P((char *, int)); | |
28 | static int getunit __P((char *)); | |
29 | static struct direct *readdir __P((struct dirstuff *)); | |
30 | static int openi __P((int, struct iob *)); | |
31 | #endif | |
32 | ||
33 | open(str, how) | |
34 | char *str; | |
35 | int how; | |
36 | { | |
37 | static int firstopen = 1; | |
38 | register struct iob *file; | |
39 | register char *t; | |
40 | register int cnt; | |
41 | int fdesc, args[8], *argp; | |
42 | ||
43 | if (firstopen) { | |
44 | for (cnt = 0; cnt < SOPEN_MAX; cnt++) | |
45 | iob[cnt].i_flgs = 0; | |
46 | firstopen = 0; | |
47 | } | |
48 | ||
49 | for (fdesc = 0;; fdesc++) { | |
50 | if (fdesc == SOPEN_MAX) | |
51 | _stop("No more file slots"); | |
52 | if (iob[fdesc].i_flgs == 0) { | |
53 | file = &iob[fdesc]; | |
54 | file->i_flgs |= F_ALLOC; | |
55 | file->i_adapt = file->i_ctlr = file->i_unit = | |
56 | file->i_part = 0; | |
57 | break; | |
58 | } | |
59 | } | |
60 | ||
61 | for (cnt = 0; cnt < sizeof(args)/sizeof(args[0]); args[cnt++] = 0); | |
62 | #ifndef SMALL | |
63 | for (t = str; *t && *t != '/' && *t != ':' && *t != '('; ++t) | |
64 | if (isupper(*t)) | |
65 | *t = tolower(*t); | |
66 | switch(*t) { | |
67 | case '(': /* type(adapt, ctlr, drive, partition)file */ | |
68 | if ((file->i_dev = getdev(str, t - str)) == -1) | |
69 | goto bad; | |
70 | for (argp = args + 4, cnt = 0; *t != ')'; ++cnt) { | |
71 | for (++t; isspace(*t); ++t); | |
72 | if (*t == ')') | |
73 | break; | |
74 | if (!isdigit(*t)) | |
75 | goto badspec; | |
76 | *argp++ = atoi(t); | |
77 | for (++t; isdigit(*t); ++t); | |
78 | if (*t != ',' && *t != ')' || cnt == 4) | |
79 | goto badspec; | |
80 | } | |
81 | for (++t; isspace(*t); ++t); | |
82 | argp -= 4; | |
83 | file->i_adapt = *argp++; | |
84 | file->i_ctlr = *argp++; | |
85 | file->i_unit = *argp++; | |
86 | file->i_part = *argp; | |
87 | break; | |
88 | case ':': /* [A-Za-z]*[0-9]*[A-Za-z]:file */ | |
89 | for (t = str; *t != ':' && !isdigit(*t); ++t); | |
90 | if ((file->i_dev = getdev(str, t - str)) == -1) | |
91 | goto bad; | |
92 | if ((file->i_unit = getunit(t)) == -1) | |
93 | goto bad; | |
94 | for (; isdigit(*t); ++t); | |
95 | if (*t >= 'a' && *t <= 'h') | |
96 | file->i_part = *t++ - 'a'; | |
97 | if (*t != ':') { | |
98 | errno = EOFFSET; | |
99 | goto badspec; | |
100 | } | |
101 | for (++t; isspace(*t); ++t); | |
102 | break; | |
103 | case '/': | |
104 | default: /* default bootstrap unit and device */ | |
105 | #else | |
106 | { | |
107 | #endif /* SMALL */ | |
108 | file->i_dev = B_TYPE(bootdev); | |
109 | file->i_adapt = B_ADAPTOR(bootdev); | |
110 | file->i_ctlr = B_CONTROLLER(bootdev); | |
111 | file->i_unit = B_UNIT(bootdev); | |
112 | file->i_part = B_PARTITION(bootdev); | |
113 | t = str; | |
114 | } | |
115 | ||
116 | opendev = MAKEBOOTDEV(file->i_dev, file->i_adapt, file->i_ctlr, | |
117 | file->i_unit, file->i_part); | |
118 | ||
119 | if (errno = devopen(file)) | |
120 | goto bad; | |
121 | ||
122 | if (*t == '\0') { | |
123 | file->i_flgs |= how + 1; | |
124 | file->i_cc = 0; | |
125 | file->i_offset = 0; | |
126 | return (fdesc+3); | |
127 | } | |
128 | #ifndef SMALL | |
129 | else if (how != 0) { | |
130 | printf("Can't write files yet.. Sorry\n"); | |
131 | errno = EIO; | |
132 | goto bad; | |
133 | } | |
134 | #endif | |
135 | file->i_ma = (char *)(&file->i_fs); | |
136 | file->i_cc = SBSIZE; | |
137 | file->i_bn = SBOFF / DEV_BSIZE + file->i_boff; | |
138 | file->i_offset = 0; | |
139 | if (devread(file) < 0) { | |
140 | errno = file->i_error; | |
141 | printf("super block read error\n"); | |
142 | goto bad; | |
143 | } | |
144 | if ((cnt = find(t, file)) == 0) { | |
145 | errno = ESRCH; | |
146 | goto bad; | |
147 | } | |
148 | if (openi(cnt, file) < 0) { | |
149 | errno = file->i_error; | |
150 | goto bad; | |
151 | } | |
152 | file->i_offset = 0; | |
153 | file->i_cc = 0; | |
154 | file->i_flgs |= F_FILE | (how+1); | |
155 | return (fdesc+3); | |
156 | ||
157 | #ifndef SMALL | |
158 | badspec: | |
159 | printf("malformed device specification\nusage: device(adaptor, controller, drive, partition)file -or- <device><unit><partitionletter>:<file>\n"); | |
160 | #endif | |
161 | bad: | |
162 | file->i_flgs = 0; | |
163 | return (-1); | |
164 | } | |
165 | ||
166 | #ifndef SMALL | |
167 | static | |
168 | getdev(str, len) | |
169 | register char *str; | |
170 | int len; | |
171 | { | |
172 | register struct devsw *dp; | |
173 | register int i; | |
174 | char savedch = str[len]; | |
175 | ||
176 | str[len] = '\0'; | |
177 | for (dp = devsw, i = 0; i < ndevs; dp++, i++) | |
178 | if (dp->dv_name && strcmp(str, dp->dv_name) == 0) { | |
179 | str[len] = savedch; | |
180 | return (i); | |
181 | } | |
182 | printf("Unknown device\nKnown devices are:\n"); | |
183 | for (dp = devsw, i = 0; i < ndevs; dp++, i++) | |
184 | if (dp->dv_name) | |
185 | printf(" %s", dp->dv_name); | |
186 | printf("\n"); | |
187 | errno = ENXIO; | |
188 | return (-1); | |
189 | } | |
190 | ||
191 | static | |
192 | getunit(cp) | |
193 | register char *cp; | |
194 | { | |
195 | int unit; | |
196 | ||
197 | unit = atoi(cp); | |
198 | if ((u_int)unit > 255) { | |
199 | printf("minor device number out of range (0-255)\n"); | |
200 | errno = EUNIT; | |
201 | return (-1); | |
202 | } | |
203 | return (unit); | |
204 | } | |
205 | #endif /* SMALL */ | |
206 | ||
207 | static | |
208 | find(path, file) | |
209 | register char *path; | |
210 | struct iob *file; | |
211 | { | |
212 | register char *q; | |
213 | char *dir, c; | |
214 | int n; | |
215 | ||
216 | if (path == NULL || *path == '\0') { | |
217 | printf("null path\n"); | |
218 | return (0); | |
219 | } | |
220 | ||
221 | if (openi((ino_t) ROOTINO, file) < 0) { | |
222 | printf("can't read root inode\n"); | |
223 | return (0); | |
224 | } | |
225 | dir = path; | |
226 | while (*path) { | |
227 | while (*path == '/') | |
228 | path++; | |
229 | q = path; | |
230 | while(*q != '/' && *q != '\0') | |
231 | q++; | |
232 | c = *q; | |
233 | *q = '\0'; | |
234 | if (q == path) path = "." ; /* "/" means "/." */ | |
235 | ||
236 | if ((n = dlook(path, file, dir)) != 0) { | |
237 | if (c == '\0') | |
238 | break; | |
239 | if (openi(n, file) < 0) | |
240 | return (0); | |
241 | *q = c; | |
242 | path = q; | |
243 | continue; | |
244 | } else { | |
245 | printf("%s: not found\n", path); | |
246 | return (0); | |
247 | } | |
248 | } | |
249 | return (n); | |
250 | } | |
251 | ||
252 | static ino_t | |
253 | dlook(s, io, dir) | |
254 | char *s; | |
255 | register struct iob *io; | |
256 | char *dir; | |
257 | { | |
258 | register struct direct *dp; | |
259 | register struct dinode *ip; | |
260 | struct dirstuff dirp; | |
261 | int len; | |
262 | ||
263 | if (s == NULL || *s == '\0') | |
264 | return (0); | |
265 | ip = &io->i_ino; | |
266 | if ((ip->di_mode&IFMT) != IFDIR) { | |
267 | printf("%s: not a directory\n", dir); | |
268 | return (0); | |
269 | } | |
270 | if (ip->di_size == 0) { | |
271 | printf("%s: zero length directory\n", dir); | |
272 | return (0); | |
273 | } | |
274 | len = strlen(s); | |
275 | dirp.loc = 0; | |
276 | dirp.io = io; | |
277 | for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) { | |
278 | if(dp->d_ino == 0) | |
279 | continue; | |
280 | if (dp->d_namlen == len && !strcmp(s, dp->d_name)) | |
281 | return (dp->d_ino); | |
282 | } | |
283 | return (0); | |
284 | } | |
285 | ||
286 | static struct direct * | |
287 | readdir(dirp) | |
288 | register struct dirstuff *dirp; | |
289 | { | |
290 | register struct direct *dp; | |
291 | register struct iob *io; | |
292 | daddr_t lbn, d; | |
293 | int off; | |
294 | ||
295 | io = dirp->io; | |
296 | for(;;) { | |
297 | if (dirp->loc >= io->i_ino.di_size) | |
298 | return (NULL); | |
299 | off = blkoff(&io->i_fs, dirp->loc); | |
300 | if (off == 0) { | |
301 | lbn = lblkno(&io->i_fs, dirp->loc); | |
302 | d = bmap(io, lbn); | |
303 | if(d == 0) | |
304 | return (NULL); | |
305 | io->i_bn = fsbtodb(&io->i_fs, d) + io->i_boff; | |
306 | io->i_ma = io->i_buf; | |
307 | io->i_cc = dblksize(&io->i_fs, &io->i_ino, lbn); | |
308 | if (devread(io) < 0) { | |
309 | errno = io->i_error; | |
de95853c | 310 | printf("bn %ld: directory read error\n", |
8a8c3c41 KB |
311 | io->i_bn); |
312 | return (NULL); | |
313 | } | |
314 | } | |
315 | dp = (struct direct *)(io->i_buf + off); | |
316 | dirp->loc += dp->d_reclen; | |
317 | if (dp->d_ino == 0) | |
318 | continue; | |
319 | return (dp); | |
320 | } | |
321 | } | |
322 | ||
323 | static | |
324 | openi(n, io) | |
325 | int n; | |
326 | register struct iob *io; | |
327 | { | |
328 | register struct dinode *dp; | |
329 | int cc; | |
330 | ||
331 | io->i_offset = 0; | |
332 | io->i_bn = fsbtodb(&io->i_fs, itod(&io->i_fs, n)) + io->i_boff; | |
333 | io->i_cc = io->i_fs.fs_bsize; | |
334 | io->i_ma = io->i_buf; | |
335 | cc = devread(io); | |
336 | dp = (struct dinode *)io->i_buf; | |
337 | io->i_ino = dp[itoo(&io->i_fs, n)]; | |
338 | return (cc); | |
339 | } | |
340 |