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