xref: /csrg-svn/sys/stand.att/sys.c (revision 49117)
1 /*-
2  * Copyright (c) 1982, 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  *
7  *	@(#)sys.c	7.15 (Berkeley) 05/04/91
8  */
9 
10 #include <sys/param.h>
11 #include <sys/reboot.h>
12 #include <ufs/dir.h>
13 #include <stand/saio.h>		/* used from machine/stand dir */
14 
15 ino_t	dlook();
16 
17 struct dirstuff {
18 	int loc;
19 	struct iob *io;
20 };
21 
22 struct iob iob[SOPEN_MAX];
23 
24 static
25 openi(n, io)
26 	register struct iob *io;
27 {
28 	register struct dinode *dp;
29 	int cc;
30 
31 	io->i_offset = 0;
32 	io->i_bn = fsbtodb(&io->i_fs, itod(&io->i_fs, n)) + io->i_boff;
33 	io->i_cc = io->i_fs.fs_bsize;
34 	io->i_ma = io->i_buf;
35 	cc = devread(io);
36 	dp = (struct dinode *)io->i_buf;
37 	io->i_ino = dp[itoo(&io->i_fs, n)];
38 	return (cc);
39 }
40 
41 static
42 find(path, file)
43 	register char *path;
44 	struct iob *file;
45 {
46 	register char *q;
47 	char *dir, c;
48 	int n;
49 
50 	if (path == NULL || *path == '\0') {
51 		printf("null path\n");
52 		return (0);
53 	}
54 
55 	if (openi((ino_t) ROOTINO, file) < 0) {
56 		printf("can't read root inode\n");
57 		return (0);
58 	}
59 	dir = path;
60 	while (*path) {
61 		while (*path == '/')
62 			path++;
63 		q = path;
64 		while(*q != '/' && *q != '\0')
65 			q++;
66 		c = *q;
67 		*q = '\0';
68 		if (q == path) path = "." ;	/* "/" means "/." */
69 
70 		if ((n = dlook(path, file, dir)) != 0) {
71 			if (c == '\0')
72 				break;
73 			if (openi(n, file) < 0)
74 				return (0);
75 			*q = c;
76 			path = q;
77 			continue;
78 		} else {
79 			printf("%s: not found\n", path);
80 			return (0);
81 		}
82 	}
83 	return (n);
84 }
85 
86 #define	NBUFS	4
87 static char	b[NBUFS][MAXBSIZE];
88 static daddr_t	blknos[NBUFS];
89 
90 static daddr_t
91 sbmap(io, bn)
92 	register struct iob *io;
93 	daddr_t bn;
94 {
95 	register struct dinode *ip;
96 	int i, j, sh;
97 	daddr_t nb, *bap;
98 
99 	ip = &io->i_ino;
100 	if (bn < 0) {
101 		printf("bn negative\n");
102 		return ((daddr_t)0);
103 	}
104 
105 	/* The first NDADDR blocks are direct blocks. */
106 	if(bn < NDADDR) {
107 		nb = ip->di_db[bn];
108 		return (nb);
109 	}
110 
111 	/* Determine the number of levels of indirection. */
112 	sh = 1;
113 	bn -= NDADDR;
114 	for (j = NIADDR; j > 0; j--) {
115 		sh *= NINDIR(&io->i_fs);
116 		if (bn < sh)
117 			break;
118 		bn -= sh;
119 	}
120 	if (j == 0) {
121 		printf("bn ovf %D\n", bn);
122 		return ((daddr_t)0);
123 	}
124 
125 	/* Get the first indirect block address. */
126 	nb = ip->di_ib[NIADDR - j];
127 	if (nb == 0) {
128 		printf("bn void %D\n",bn);
129 		return ((daddr_t)0);
130 	}
131 
132 	/* Get the indirect blocks. */
133 	for (; j <= NIADDR; j++) {
134 		if (blknos[j] != nb) {
135 			io->i_bn = fsbtodb(&io->i_fs, nb) + io->i_boff;
136 			io->i_ma = b[j];
137 			io->i_cc = io->i_fs.fs_bsize;
138 			if (devread(io) != io->i_fs.fs_bsize) {
139 				if (io->i_error)
140 					errno = io->i_error;
141 				printf("bn %D: read error\n", io->i_bn);
142 				return ((daddr_t)0);
143 			}
144 			blknos[j] = nb;
145 		}
146 		bap = (daddr_t *)b[j];
147 		sh /= NINDIR(&io->i_fs);
148 		i = (bn / sh) % NINDIR(&io->i_fs);
149 		nb = bap[i];
150 		if(nb == 0) {
151 			printf("bn void %D\n",bn);
152 			return ((daddr_t)0);
153 		}
154 	}
155 	return (nb);
156 }
157 
158 struct direct *
159 readdir(dirp)
160 	register struct dirstuff *dirp;
161 {
162 	register struct direct *dp;
163 	register struct iob *io;
164 	daddr_t lbn, d;
165 	int off;
166 
167 	io = dirp->io;
168 	for(;;) {
169 		if (dirp->loc >= io->i_ino.di_size)
170 			return (NULL);
171 		off = blkoff(&io->i_fs, dirp->loc);
172 		if (off == 0) {
173 			lbn = lblkno(&io->i_fs, dirp->loc);
174 			d = sbmap(io, lbn);
175 			if(d == 0)
176 				return (NULL);
177 			io->i_bn = fsbtodb(&io->i_fs, d) + io->i_boff;
178 			io->i_ma = io->i_buf;
179 			io->i_cc = dblksize(&io->i_fs, &io->i_ino, lbn);
180 			if (devread(io) < 0) {
181 				errno = io->i_error;
182 				printf("bn %D: directory read error\n",
183 					io->i_bn);
184 				return (NULL);
185 			}
186 		}
187 		dp = (struct direct *)(io->i_buf + off);
188 		dirp->loc += dp->d_reclen;
189 		if (dp->d_ino == 0)
190 			continue;
191 		return (dp);
192 	}
193 }
194 
195 static ino_t
196 dlook(s, io, dir)
197 	char *s;
198 	register struct iob *io;
199 	char *dir;
200 {
201 	register struct direct *dp;
202 	register struct dinode *ip;
203 	struct dirstuff dirp;
204 	int len;
205 
206 	if (s == NULL || *s == '\0')
207 		return (0);
208 	ip = &io->i_ino;
209 	if ((ip->di_mode&IFMT) != IFDIR) {
210 		printf("%s: not a directory\n", dir);
211 		return (0);
212 	}
213 	if (ip->di_size == 0) {
214 		printf("%s: zero length directory\n", dir);
215 		return (0);
216 	}
217 	len = strlen(s);
218 	dirp.loc = 0;
219 	dirp.io = io;
220 	for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
221 		if(dp->d_ino == 0)
222 			continue;
223 		if (dp->d_namlen == len && !strcmp(s, dp->d_name))
224 			return (dp->d_ino);
225 	}
226 	return (0);
227 }
228 
229 lseek(fdesc, addr, ptr)
230 	int fdesc, ptr;
231 	off_t addr;
232 {
233 	register struct iob *io;
234 
235 #ifndef SMALL
236 	if (ptr != L_SET) {
237 		printf("Seek not from beginning of file\n");
238 		errno = EOFFSET;
239 		return (-1);
240 	}
241 #endif
242 	fdesc -= 3;
243 #ifndef SMALL
244 	if (fdesc < 0 || fdesc >= SOPEN_MAX ||
245 	    ((io = &iob[fdesc])->i_flgs & F_ALLOC) == 0) {
246 		errno = EBADF;
247 		return (-1);
248 	}
249 #endif
250 	io->i_offset = addr;
251 	io->i_bn = addr / DEV_BSIZE;
252 	io->i_cc = 0;
253 	return (0);
254 }
255 
256 getc(fdesc)
257 	int fdesc;
258 {
259 	register struct iob *io;
260 	register struct fs *fs;
261 	register char *p;
262 	int c, lbn, off, size, diff;
263 
264 
265 #ifndef SMALL
266 	if (fdesc >= 0 && fdesc <= 2)
267 		return (getchar());
268 #endif
269 	fdesc -= 3;
270 	if (fdesc < 0 || fdesc >= SOPEN_MAX ||
271 	    ((io = &iob[fdesc])->i_flgs&F_ALLOC) == 0) {
272 		errno = EBADF;
273 		return (-1);
274 	}
275 	p = io->i_ma;
276 	if (io->i_cc <= 0) {
277 		if ((io->i_flgs & F_FILE) != 0) {
278 			diff = io->i_ino.di_size - io->i_offset;
279 			if (diff <= 0)
280 				return (-1);
281 			fs = &io->i_fs;
282 			lbn = lblkno(fs, io->i_offset);
283 			io->i_bn = fsbtodb(fs, sbmap(io, lbn)) + io->i_boff;
284 			off = blkoff(fs, io->i_offset);
285 			size = dblksize(fs, &io->i_ino, lbn);
286 		} else {
287 			io->i_bn = io->i_offset / DEV_BSIZE + io->i_boff;
288 			off = 0;
289 			size = DEV_BSIZE;
290 		}
291 		io->i_ma = io->i_buf;
292 		io->i_cc = size;
293 		if (devread(io) < 0) {
294 			errno = io->i_error;
295 			return (-1);
296 		}
297 		if ((io->i_flgs & F_FILE) != 0) {
298 			if (io->i_offset - off + size >= io->i_ino.di_size)
299 				io->i_cc = diff + off;
300 			io->i_cc -= off;
301 		}
302 		p = &io->i_buf[off];
303 	}
304 	io->i_cc--;
305 	io->i_offset++;
306 	c = (unsigned)*p++;
307 	io->i_ma = p;
308 	return (c);
309 }
310 
311 int	errno;
312 
313 read(fdesc, buf, count)
314 	int fdesc, count;
315 	char *buf;
316 {
317 	register i, size;
318 	register struct iob *file;
319 	register struct fs *fs;
320 	int lbn, off;
321 
322 	errno = 0;
323 #ifndef SMALL
324 	if (fdesc >= 0 && fdesc <= 2) {
325 		i = count;
326 		do {
327 			*buf = getchar();
328 		} while (--i && *buf++ != '\n');
329 		return (count - i);
330 	}
331 #endif
332 	fdesc -= 3;
333 	if (fdesc < 0 || fdesc >= SOPEN_MAX ||
334 	    ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) {
335 		errno = EBADF;
336 		return (-1);
337 	}
338 	if ((file->i_flgs&F_READ) == 0) {
339 		errno = EBADF;
340 		return (-1);
341 	}
342 #ifndef SMALL
343 	if ((file->i_flgs & F_FILE) == 0) {
344 		file->i_cc = count;
345 		file->i_ma = buf;
346 		file->i_bn = file->i_boff + (file->i_offset / DEV_BSIZE);
347 		i = devread(file);
348 		if (i < 0)
349 			errno = file->i_error;
350 		else
351 			file->i_offset += i;
352 		return (i);
353 	}
354 #endif
355 	if (file->i_offset+count > file->i_ino.di_size)
356 		count = file->i_ino.di_size - file->i_offset;
357 	if ((i = count) <= 0)
358 		return (0);
359 	/*
360 	 * While reading full blocks, do I/O into user buffer.
361 	 * Anything else uses getc().
362 	 */
363 	fs = &file->i_fs;
364 	while (i) {
365 		off = blkoff(fs, file->i_offset);
366 		lbn = lblkno(fs, file->i_offset);
367 		size = dblksize(fs, &file->i_ino, lbn);
368 #ifndef SMALL
369 		if (off == 0 && size <= i) {
370 			file->i_bn = fsbtodb(fs, sbmap(file, lbn)) +
371 			    file->i_boff;
372 			file->i_cc = size;
373 			file->i_ma = buf;
374 			if (devread(file) < 0) {
375 				errno = file->i_error;
376 				return (-1);
377 			}
378 			file->i_offset += size;
379 			file->i_cc = 0;
380 			buf += size;
381 			i -= size;
382 		} else {
383 #endif
384 			size -= off;
385 			if (size > i)
386 				size = i;
387 			i -= size;
388 			do {
389 				*buf++ = getc(fdesc+3);
390 			} while (--size);
391 #ifndef	SMALL
392 		}
393 #endif
394 	}
395 	return (count);
396 }
397 
398 #ifndef SMALL
399 write(fdesc, buf, count)
400 	int fdesc, count;
401 	char *buf;
402 {
403 	register i;
404 	register struct iob *file;
405 
406 	errno = 0;
407 	if (fdesc >= 0 && fdesc <= 2) {
408 		i = count;
409 		while (i--)
410 			putchar(*buf++);
411 		return (count);
412 	}
413 	fdesc -= 3;
414 	if (fdesc < 0 || fdesc >= SOPEN_MAX ||
415 	    ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) {
416 		errno = EBADF;
417 		return (-1);
418 	}
419 	if ((file->i_flgs&F_WRITE) == 0) {
420 		errno = EBADF;
421 		return (-1);
422 	}
423 	file->i_cc = count;
424 	file->i_ma = buf;
425 	file->i_bn = file->i_boff + (file->i_offset / DEV_BSIZE);
426 	i = devwrite(file);
427 	file->i_offset += count;
428 	if (i < 0)
429 		errno = file->i_error;
430 	return (i);
431 }
432 #endif
433 
434 int	openfirst = 1;
435 u_int	opendev;		/* last device opened */
436 extern u_int bootdev;
437 
438 open(str, how)
439 	char *str;
440 	int how;
441 {
442 	register char *t;
443 	register int cnt;
444 	register struct iob *file;
445 	int fdesc, args[8], *argp;
446 
447 	if (openfirst) {
448 		for (cnt = 0; cnt < SOPEN_MAX; cnt++)
449 			iob[cnt].i_flgs = 0;
450 		openfirst = 0;
451 	}
452 
453 	for (fdesc = 0;; fdesc++) {
454 		if (fdesc == SOPEN_MAX)
455 			_stop("No more file slots");
456 		if (iob[fdesc].i_flgs == 0) {
457 			file = &iob[fdesc];
458 			file->i_flgs |= F_ALLOC;
459 			file->i_adapt = file->i_ctlr = file->i_unit =
460 			    file->i_part = 0;
461 			break;
462 		}
463 	}
464 
465 	for (cnt = 0; cnt < sizeof(args)/sizeof(args[0]); args[cnt++] = 0);
466 #ifndef SMALL
467 	for (t = str; *t && *t != '/' && *t != ':' && *t != '('; ++t)
468 		if (isupper(*t))
469 			*t = tolower(*t);
470 	switch(*t) {
471 	case '(':	/* type(adapt, ctlr, drive, partition)file */
472 		if ((file->i_dev = getdev(str, t - str)) == -1)
473 			goto bad;
474 		for (argp = args + 4, cnt = 0; *t != ')'; ++cnt) {
475 			for (++t; isspace(*t); ++t);
476 			if (*t == ')')
477 				break;
478 			if (!isdigit(*t))
479 				goto badspec;
480 			*argp++ = atoi(t);
481 			for (++t; isdigit(*t); ++t);
482 			if (*t != ',' && *t != ')' || cnt == 4)
483 				goto badspec;
484 		}
485 		for (++t; isspace(*t); ++t);
486 		argp -= 4;
487 		file->i_adapt = *argp++;
488 		file->i_ctlr = *argp++;
489 		file->i_unit = *argp++;
490 		file->i_part = *argp;
491 		break;
492 	case ':':	/* [A-Za-z]*[0-9]*[A-Za-z]:file */
493 		for (t = str; *t != ':' && !isdigit(*t); ++t);
494 		if ((file->i_dev = getdev(str, t - str)) == -1)
495 			goto bad;
496 		if ((file->i_unit = getunit(t)) == -1)
497 			goto bad;
498 		for (; isdigit(*t); ++t);
499 		if (*t >= 'a' && *t <= 'h')
500 			file->i_part = *t++ - 'a';
501 		if (*t != ':') {
502 			errno = EOFFSET;
503 			goto badspec;
504 		}
505 		for (++t; isspace(*t); ++t);
506 		break;
507 	case '/':
508 	default:		/* default bootstrap unit and device */
509 #else
510 	{
511 #endif /* SMALL */
512 		file->i_dev = B_TYPE(bootdev);
513 		file->i_adapt = B_ADAPTOR(bootdev);
514 		file->i_ctlr = B_CONTROLLER(bootdev);
515 		file->i_unit = B_UNIT(bootdev);
516 		file->i_part = B_PARTITION(bootdev);
517 		t = str;
518 	}
519 
520 	opendev = MAKEBOOTDEV(file->i_dev, file->i_adapt, file->i_ctlr,
521 	    file->i_unit, file->i_part);
522 
523 	if (errno = devopen(file))
524 		goto bad;
525 
526 	if (*t == '\0') {
527 		file->i_flgs |= how + 1;
528 		file->i_cc = 0;
529 		file->i_offset = 0;
530 		return (fdesc+3);
531 	}
532 #ifndef SMALL
533 	else if (how != 0) {
534 		printf("Can't write files yet.. Sorry\n");
535 		errno = EIO;
536 		goto bad;
537 	}
538 #endif
539 	file->i_ma = (char *)(&file->i_fs);
540 	file->i_cc = SBSIZE;
541 	file->i_bn = SBOFF / DEV_BSIZE + file->i_boff;
542 	file->i_offset = 0;
543 	if (devread(file) < 0) {
544 		errno = file->i_error;
545 		printf("super block read error\n");
546 		goto bad;
547 	}
548 	if ((cnt = find(t, file)) == 0) {
549 		errno = ESRCH;
550 		goto bad;
551 	}
552 	if (openi(cnt, file) < 0) {
553 		errno = file->i_error;
554 		goto bad;
555 	}
556 	file->i_offset = 0;
557 	file->i_cc = 0;
558 	file->i_flgs |= F_FILE | (how+1);
559 	return (fdesc+3);
560 
561 #ifndef SMALL
562 badspec:
563 	printf("malformed device specification\nusage: device(adaptor, controller, drive, partition)file -or- <device><unit><partitionletter>:<file>\n");
564 #endif
565 bad:
566 	file->i_flgs = 0;
567 	return (-1);
568 }
569 
570 #ifndef SMALL
571 static
572 getdev(str, len)
573 	register char *str;
574 	int len;
575 {
576 	register struct devsw *dp;
577 	register int i;
578 	char savedch = str[len];
579 
580 	str[len] = '\0';
581 	for (dp = devsw, i = 0; i < ndevs; dp++, i++)
582 		if (dp->dv_name && strcmp(str, dp->dv_name) == 0) {
583 			str[len] = savedch;
584 			return (i);
585 		}
586 	printf("Unknown device\nKnown devices are:\n");
587 	for (dp = devsw, i = 0; i < ndevs; dp++, i++)
588 		if (dp->dv_name)
589 			printf(" %s", dp->dv_name);
590 	printf("\n");
591 	errno = ENXIO;
592 	return (-1);
593 }
594 
595 static
596 getunit(cp)
597 	register char *cp;
598 {
599 	int unit;
600 
601 	unit = atoi(cp);
602 	if ((u_int)unit > 255) {
603 		printf("minor device number out of range (0-255)\n");
604 		errno = EUNIT;
605 		return (-1);
606 	}
607 	return (unit);
608 }
609 #endif /* SMALL */
610 
611 close(fdesc)
612 	int fdesc;
613 {
614 #ifndef SMALL
615 	struct iob *file;
616 
617 	fdesc -= 3;
618 	if (fdesc < 0 || fdesc >= SOPEN_MAX ||
619 	    ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) {
620 		errno = EBADF;
621 		return (-1);
622 	}
623 	if ((file->i_flgs&F_FILE) == 0)
624 		devclose(file);
625 	file->i_flgs = 0;
626 #endif
627 	return (0);
628 }
629 
630 #ifndef SMALL
631 ioctl(fdesc, cmd, arg)
632 	int fdesc, cmd;
633 	char *arg;
634 {
635 	register struct iob *file;
636 	int error = 0;
637 
638 	fdesc -= 3;
639 	if (fdesc < 0 || fdesc >= SOPEN_MAX ||
640 	    ((file = &iob[fdesc])->i_flgs&F_ALLOC) == 0) {
641 		errno = EBADF;
642 		return (-1);
643 	}
644 	switch (cmd) {
645 
646 	case SAIOHDR:
647 		file->i_flgs |= F_HDR;
648 		break;
649 
650 	case SAIOCHECK:
651 		file->i_flgs |= F_CHECK;
652 		break;
653 
654 	case SAIOHCHECK:
655 		file->i_flgs |= F_HCHECK;
656 		break;
657 
658 	case SAIONOBAD:
659 		file->i_flgs |= F_NBSF;
660 		break;
661 
662 	case SAIODOBAD:
663 		file->i_flgs &= ~F_NBSF;
664 		break;
665 
666 	default:
667 		error = devioctl(file, cmd, arg);
668 		break;
669 	}
670 	if (error < 0)
671 		errno = file->i_error;
672 	return (error);
673 }
674 #endif /* SMALL */
675 
676 #ifndef i386
677 exit()
678 {
679 	_stop("Exit called");
680 }
681 #endif
682 
683 _stop(s)
684 	char *s;
685 {
686 	int i;
687 	static int stopped = 0;
688 
689 	if (!stopped) {
690 		stopped++;
691 		for (i = 0; i < SOPEN_MAX; i++)
692 			if (iob[i].i_flgs != 0)
693 				close(i);
694 	}
695 	printf("%s\n", s);
696 	_rtt();
697 }
698