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