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