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