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