_h˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙ü˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙íA@“Œ:!íA“Œ:!¤H˜“Œ:! ¤“Œ:!1¤íł“Œ:!2345678:¤ÂL“Œ:!`abcdefh¤D “Œ:!uvw¤5“Œ:!x¤˘“Œ:!y¤źd•Œ:!z{|}~€‚¤D)”Œ:!•–—˜™š›¤nJ“Œ:!Ą˘Ł¤ĽŚ§Š¤N“Œ:!ľśˇ¤ę;“Œ:!¸šşťź˝žŔ˙AP“Œ:!ȤňǍ:!ÉĘËĚͤO“Œ:!ÎĎĐŃŇÓÔÖ¤V “Œ:!×ŘŮÚ˙APg:!ۤ4“Œ:!ÜÝŢßŕ˙A€“Œ:!ᤁŁ'“Œ:!âăäĺćçč꤁“Œ:!í¤y“Œ:!îďđńňóôö¤š“Œ:!÷ř¤4“Œ:!ůúűüýţ˙¤ “Œ:!˙A@“Œ:!¤“Œ:!¤!“Œ:!¤}“Œ:!¤Ľ“Œ:! ¤:! ¤Ź“Œ:!   ¤/“Œ:!¤"5“Œ:! !"#%¤$“Œ:!,-./0124¤$“Œ:!78¤(“Œ:!9:;<=>?A¤Ď“Œ:!BC¤š4‘Œ:!DEFGHIJL¤Ž “Œ:!STU¤V“Œ:!VWXYZ˙A0“Œ:![¤Ô“Œ:!\]˙A0“Œ:!^¤“Œ:!_`˙A0“Œ:!a¤D “Œ:!bcdeię!...toolsmm...proto.amisc.afsck.cbuild.cinit.cchangemem bootblok kernel mm fs initfsckMINIXPCIXC86e˙proto.256.ramÁ bę ¤ƒboot 55 63 d--777 2 1 bin d--755 2 1 getlf ---755 2 1 ../commands/bin/getlf sh ---755 2 1 ../commands/bin/sh sync ---755 2 1 ../commands/bin/sync $ dev d--755 2 1 ram b--640 2 1 1 0 640 mem b--640 2 1 1 1 640 kmem b--640 2 1 1 2 640 null b--666 2 1 1 3 0 fd0 b--666 2 1 2 0 360 fd1 b--666 2 1 2 1 360 at0 b--666 2 1 2 0 1200 at1 b--666 2 1 2 1 1200 hd0 b--600 2 1 3 0 32000 hd1 b--600 2 1 3 1 32000 hd2 b--600 2 1 3 2 32000 hd3 b--600 2 1 3 3 32000 hd4 b--600 2 1 3 4 4096 tty0 c--666 2 1 4 0 tty c--666 2 1 5 0 lp c--222 2 1 6 0 $ etc d--755 2 1 mount -u-755 0 1 ../commands/bin/mount umount -u-755 0 1 ../commands/bin/umount update ---755 2 1 ../commands/bin/update passwd ---644 2 1 passwd rc ---644 2 1 rc message ---644 2 1 message ttys ---644 2 1 ttys $ lib d--755 2 1 $ tmp d--777 2 1 $ user d--755 2 1 $ usr d--755 2 1 $ $ 0proto.256.usrÁ bę ¤ boot 360 127 d--755 1 1 ast d--755 8 3 .profile ---644 8 3 profile $ bin d--755 2 1 ar ---755 2 1 ../commands/bin/ar basename ---755 2 1 ../commands/bin/basename cat ---755 2 1 ../commands/bin/cat cp ---755 2 1 ../commands/bin/cp chmem ---755 2 1 ../commands/bin/chmem chmod ---755 2 1 ../commands/bin/chmod chown ---755 2 1 ../commands/bin/chown clr ---755 2 1 ../commands/bin/clr cmp ---755 2 1 ../commands/bin/cmp comm ---755 2 1 ../commands/bin/comm date ---755 2 1 ../commands/bin/date dd ---755 2 1 ../commands/bin/dd df -u-755 0 1 ../commands/bin/df dosread ---755 2 1 ../commands/bin/dosread echo ---755 2 1 ../commands/bin/echo grep ---755 2 1 ../commands/bin/grep head ---755 2 1 ../commands/bin/head kill ---755 2 1 ../commands/bin/kill ln ---755 2 1 ../commands/bin/ln login ---755 2 1 ../commands/bin/login lpr ---755 2 1 ../commands/bin/lpr ls ---755 2 1 ../commands/bin/ls mkdir -u-755 0 1 ../commands/bin/mkdir mined ---755 2 1 ../commands/bin/mined.256 make ---755 2 1 ../commands/bin/make mkfs ---755 2 1 ../commands/bin/mkfs mknod ---755 2 1 ../commands/bin/mknod mv ---755 2 1 ../commands/bin/mv od ---755 2 1 ../commands/bin/od passwd ---755 2 1 ../commands/bin/passwd pr ---755 2 1 ../commands/bin/pr pwd ---755 2 1 ../commands/bin/pwd rev ---755 2 1 ../commands/bin/rev rm ---755 2 1 ../commands/bin/rm rmdir ---755 2 1 ../commands/bin/rmdir size ---755 2 1 ../commands/bin/size sleep ---755 2 1 ../commands/bin/sleep sort ---755 2 1 ../commands/bin/sort split ---755 2 1 ../commands/bin/split stty ---755 2 1 ../commands/bin/stty su -u-755 0 1 ../commands/bin/su sum ---755 2 1 ../commands/bin/sum tail ---755 2 1 ../commands/bin/tail tee ---755 2 1 ../commands/bin/tee time ---755 2 1 ../commands/bin/time touch ---755 2 1 ../commands/bin/touch tr ---755 2 1 ../commands/bin/tr true ---755 2 1 ../commands/bin/true uniq ---755 2 1 ../commands/bin/uniq wc ---755 2 1 ../commands/bin/wc $ include d--755 2 1 blocksize.h ---644 2 1 ../include/blocksize.h errno.h ---644 2 1 ../include/errno.h sgtty.h ---644 2 1 ../include/sgtty.h signal.h ---644 2 1 ../include/signal.h stat.h ---644 2 1 ../include/stat.h setjmp.h ---644 2 1 ../include/setjmp.h stdio.h ---644 2 1 ../include/stdio.h $ lib d--755 2 1 $ $ proto.at.disk4! Ś ¤"boot 1200 255 d--777 1 1 kernel d--777 2 1 type.h ---644 2 1 ../kernel/type.h proc.h ---644 2 1 ../kernel/proc.h glo.h ---644 2 1 ../kernel/glo.h const.h ---644 2 1 ../kernel/const.h clock.c ---644 2 1 ../kernel/clock.c dmp.c ---644 2 1 ../kernel/dmp.c floppy.c ---644 2 1 ../kernel/floppy.c main.c ---644 2 1 ../kernel/main.c memory.c ---644 2 1 ../kernel/memory.c printer.c ---644 2 1 ../kernel/printer.c proc.c ---644 2 1 ../kernel/proc.c system.c ---644 2 1 ../kernel/system.c table.c ---644 2 1 ../kernel/table.c tty.c ---644 2 1 ../kernel/tty.c xt_wini.c ---644 2 1 ../kernel/xt_wini.c at_wini.c ---644 2 1 ../kernel/at_wini.c MINIX d--777 2 1 makefile ---644 2 1 ../kernel/MINIX/makefile klib88.s ---644 2 1 ../kernel/klib88.s mpx88.s ---644 2 1 ../kernel/mpx88.s $ PCIX d--777 2 1 makefile ---644 2 1 ../kernel/PCIX/makefile $ C86 d--777 2 1 make.bat ---644 2 1 ../kernel/C86/make.bat _link.bat ---644 2 1 ../kernel/C86/_link.bat linklist ---644 2 1 ../kernel/C86/linklist klib88.asm ---644 2 1 ../kernel/C86/klib88.asm mpx88.asm ---644 2 1 ../kernel/C86/mpx88.asm $ $ h d--777 2 1 signal.h ---644 2 1 ../h/signal.h stat.h ---644 2 1 ../h/stat.h sgtty.h ---644 2 1 ../h/sgtty.h error.h ---644 2 1 ../h/error.h callnr.h ---644 2 1 ../h/callnr.h com.h ---644 2 1 ../h/com.h const.h ---644 2 1 ../h/const.h type.h ---644 2 1 ../h/type.h $ fs d--755 2 1 type.h ---644 2 1 ../fs/type.h super.h ---644 2 1 ../fs/super.h path.c ---644 2 1 ../fs/path.c param.h ---644 2 1 ../fs/param.h inode.h ---644 2 1 ../fs/inode.h glo.h ---644 2 1 ../fs/glo.h fproc.h ---644 2 1 ../fs/fproc.h file.h ---644 2 1 ../fs/file.h dev.h ---644 2 1 ../fs/dev.h const.h ---644 2 1 ../fs/const.h cache.c ---644 2 1 ../fs/cache.c buf.h ---644 2 1 ../fs/buf.h device.c ---644 2 1 ../fs/device.c filedes.c ---644 2 1 ../fs/filedes.c inode.c ---644 2 1 ../fs/inode.c link.c ---644 2 1 ../fs/link.c main.c ---644 2 1 ../fs/main.c misc.c ---644 2 1 ../fs/misc.c mount.c ---644 2 1 ../fs/mount.c open.c ---644 2 1 ../fs/open.c pipe.c ---644 2 1 ../fs/pipe.c protect.c ---644 2 1 ../fs/protect.c putc.c ---644 2 1 ../fs/putc.c read.c ---644 2 1 ../fs/read.c stadir.c ---644 2 1 ../fs/stadir.c super.c ---644 2 1 ../fs/super.c table.c ---644 2 1 ../fs/table.c time.c ---644 2 1 ../fs/time.c utility.c ---644 2 1 ../fs/utility.c write.c ---644 2 1 ../fs/write.c MINIX d--777 2 1 makefile ---644 2 1 ../fs/MINIX/makefile $ PCIX d--777 2 1 makefile ---644 2 1 ../fs/PCIX/makefile $ C86 d--777 2 1 make.bat ---644 2 1 ../fs/C86/make.bat _link.bat ---644 2 1 ../fs/C86/_link.bat linklist ---644 2 1 ../fs/C86/linklist $ $ lib d--777 2 1 READ_ME ---644 2 1 ../lib/READ_ME run ---755 2 1 ../lib/run libsrc.a ---644 2 1 ../lib/libsrc.a cpp ---755 2 1 ../commands/bin/cpp cem ---755 2 1 ../commands/bin/cem cg ---755 2 1 ../commands/bin/cg opt ---755 2 1 ../commands/bin/opt crtso.s ---755 2 1 ../lib/MINIX/crtso.s end.s ---755 2 1 ../lib/MINIX/end.s head.s ---755 2 1 ../lib/MINIX/head.s libc.a ---755 2 1 ../commands/bin/libc.a MINIX d--777 2 1 crtso.s ---644 2 1 ../lib/MINIX/crtso.s end.s ---644 2 1 ../lib/MINIX/end.s head.s ---644 2 1 ../lib/MINIX/head.s setjmp.s ---644 2 1 ../lib/MINIX/setjmp.s $ PCIX d--777 2 1 crtso.s ---644 2 1 ../lib/PCIX/crtso.s end.s ---644 2 1 ../lib/PCIX/end.s head.s ---644 2 1 ../lib/PCIX/head.s setjmp.s ---644 2 1 ../lib/PCIX/setjmp.s $ C86 d--777 2 1 brksize.asm ---644 2 1 ../lib/C86/brksize.asm catchsig.asm ---644 2 1 ../lib/C86/catchsig.asm crtso.asm ---644 2 1 ../lib/C86/crtso.asm csv.asm ---644 2 1 ../lib/C86/csv.asm end.asm ---644 2 1 ../lib/C86/end.asm getutil.asm ---644 2 1 ../lib/C86/getutil.asm head.asm ---644 2 1 ../lib/C86/head.asm prologue.h ---644 2 1 ../lib/C86/prologue.h sendrec.asm ---644 2 1 ../lib/C86/sendrec.asm setjmp.asm ---644 2 1 ../lib/C86/setjmp.asm make.bat ---644 2 1 ../lib/C86/make.bat $ $ mm d--777 2 1 const.h ---644 2 1 ../mm/const.h glo.h ---644 2 1 ../mm/glo.h mproc.h ---644 2 1 ../mm/mproc.h param.h ---644 2 1 ../mm/param.h type.h ---644 2 1 ../mm/type.h alloc.c ---644 2 1 ../mm/alloc.c break.c ---644 2 1 ../mm/break.c exec.c ---644 2 1 ../mm/exec.c forkexit.c ---644 2 1 ../mm/forkexit.c getset.c ---644 2 1 ../mm/getset.c main.c ---644 2 1 ../mm/main.c putc.c ---644 2 1 ../mm/putc.c signal.c ---644 2 1 ../mm/signal.c table.c ---644 2 1 ../mm/table.c utility.c ---644 2 1 ../mm/utility.c MINIX d--777 2 1 makefile ---644 2 1 ../mm/MINIX/makefile $ PCIX d--777 2 1 makefile ---644 2 1 ../mm/PCIX/makefile $ C86 d--777 2 1 make.bat ---644 2 1 ../mm/C86/make.bat _link.bat ---644 2 1 ../mm/C86/_link.bat linklist - !"#$%&'()*+,-./0--644 2 1 ../mm/C86/linklist $ $ bin d--755 2 1 cat ---755 2 1 ../commands/bin/cat cc ---755 2 1 ../commands/bin/cc asld ---755 2 1 ../commands/bin/asld echo ---755 2 1 ../commands/bin/echo ls ---755 2 1 ../commands/bin/ls make ---755 2 1 ../commands/bin/make mkdir -u-755 0 1 ../commands/bin/mkdir mv ---755 2 1 ../commands/bin/mv pr ---755 2 1 ../commands/bin/pr rm ---755 2 1 ../commands/bin/rm rmdir -u-755 0 1 ../commands/bin/rmdir time ---755 2 1 ../commands/bin/time $ $ proto.at.disk5 !k‚ ¤y boot 1200 255 d--755 1 1 tools d--755 2 1 fsck.c ---644 2 1 fsck.c build.c ---644 2 1 build.c init.c ---644 2 1 init.c proto.ram ---644 2 1 proto.ram proto.usr ---644 2 1 proto.usr proto.user ---644 2 1 proto.user proto.disk5 ---644 2 1 proto.disk5 proto.disk6 ---644 2 1 proto.disk6 proto.disk7 ---644 2 1 proto.disk7 proto.disk8 ---644 2 1 proto.disk8 proto.disk9 ---644 2 1 proto.disk9 proto.at.ram ---644 2 1 proto.at.ram proto.at.usr ---644 2 1 proto.at.usr proto.at.disk4 ---644 2 1 proto.at.disk4 proto.at.disk5 ---644 2 1 proto.at.disk5 proto.256.ram ---644 2 1 proto.256.ram proto.256.usr ---644 2 1 proto.256.usr passwd ---644 2 1 passwd changemem ---644 2 1 changemem rc ---644 2 1 rc ttys ---644 2 1 ttys bootblok ---644 2 1 bootblok kernel ---644 2 1 ../kernel/kernel mm ---644 2 1 ../mm/mm fs ---644 2 1 ../fs/fs init ---644 2 1 init fsck ---644 2 1 fsck MINIX d--777 2 1 makefile ---644 2 1 MINIX/makefile bootblok.s ---644 2 1 bootblok.s fsck1.s ---644 2 1 fsck1.s $ PCIX d--777 2 1 makefile ---644 2 1 PCIX/makefile $ C86 d--777 2 1 dos2out.c ---644 2 1 C86/dos2out.c bootblok ---644 2 1 C86/bootblok bootblok.asm ---644 2 1 C86/bootblok.asm diskio.asm ---644 2 1 C86/diskio.asm fsck1.asm ---644 2 1 C86/fsck1.asm _bootblok.bat ---644 2 1 C86/_bootblok.bat _build.bat ---644 2 1 C86/_build.bat _dos2out.bat ---644 2 1 C86/_dos2out.bat _fsck.bat ---644 2 1 C86/_fsck.bat _image.bat ---644 2 1 C86/_image.bat _init.bat ---644 2 1 C86/_init.bat _mkfs.bat ---644 2 1 C86/_mkfs.bat make.bat ---644 2 1 C86/make.bat $ $ bin d--755 2 1 cat ---755 2 1 ../commands/bin/cat cc ---755 2 1 ../commands/bin/cc asld ---755 2 1 ../commands/bin/asld echo ---755 2 1 ../commands/bin/echo ls ---755 2 1 ../commands/bin/ls make ---755 2 1 ../commands/bin/make mkdir -u-755 0 1 ../commands/bin/mkdir mv ---755 2 1 ../commands/bin/mv pr ---755 2 1 ../commands/bin/pr rm ---755 2 1 ../commands/bin/rm rmdir -u-755 0 1 ../commands/bin/rmdir time ---755 2 1 ../commands/bin/time $ lib d--755 2 1 cpp ---755 2 1 ../commands/bin/cpp cem ---755 2 1 ../commands/bin/cem cg ---755 2 1 ../commands/bin/cg opt ---755 2 1 ../commands/bin/opt crtso.s ---755 2 1 ../lib/MINIX/crtso.s end.s ---755 2 1 ../lib/MINIX/end.s head.s ---755 2 1 ../lib/MINIX/head.s libc.a ---755 2 1 ../commands/bin/libc.a $ $ 2proto.at.disk6!†Ľ ¤ńboot 1200 255 d--755 1 1 include d--777 2 1 blocksize.h ---644 2 1 ../include/blocksize.h ctype.h ---644 2 1 ../include/ctype.h errno.h ---644 2 1 ../include/errno.h grp.h ---644 2 1 ../include/grp.h lib.h ---644 2 1 ../include/lib.h pwd.h ---644 2 1 ../include/pwd.h regexp.h ---644 2 1 ../include/regexp.h setjmp.h ---644 2 1 ../include/setjmp.h sgtty.h ---644 2 1 ../include/sgtty.h signal.h ---644 2 1 ../include/signal.h stat.h ---644 2 1 ../include/stat.h stdio.h ---644 2 1 ../include/stdio.h $ commands d--755 2 1 ar.c ---644 2 1 ../commands/ar.c basename.c ---644 2 1 ../commands/basename.c cat.c ---644 2 1 ../commands/cat.c cc.c ---644 2 1 ../commands/cc.c chmem.c ---644 2 1 ../commands/chmem.c chmod.c ---644 2 1 ../commands/chmod.c chown.c ---644 2 1 ../commands/chown.c clr.c ---644 2 1 ../commands/clr.c cmp.c ---644 2 1 ../commands/cmp.c comm.c ---644 2 1 ../commands/comm.c cp.c ---644 2 1 ../commands/cp.c date.c ---644 2 1 ../commands/date.c dd.c ---644 2 1 ../commands/dd.c df.c ---644 2 1 ../commands/df.c dosread.c ---644 2 1 ../commands/dosread.c echo.c ---644 2 1 ../commands/echo.c fdisk.c ---644 2 1 ../commands/fdisk.c getlf.c ---644 2 1 ../commands/getlf.c grep.c ---644 2 1 ../commands/grep.c gres.c ---644 2 1 ../commands/gres.c head.c ---644 2 1 ../commands/head.c kill.c ---644 2 1 ../commands/kill.c libpack.c ---644 2 1 ../commands/libpack.c libupack.c ---644 2 1 ../commands/libupack.c ln.c ---644 2 1 ../commands/ln.c login.c ---644 2 1 ../commands/login.c lpr.c ---644 2 1 ../commands/lpr.c ls.c ---644 2 1 ../commands/ls.c mkdir.c ---644 2 1 ../commands/mkdir.c mkfs.c ---644 2 1 ../commands/mkfs.c mknod.c ---644 2 1 ../commands/mknod.c mount.c ---644 2 1 ../commands/mount.c mv.c ---644 2 1 ../commands/mv.c od.c ---644 2 1 ../commands/od.c passwd.c ---644 2 1 ../commands/passwd.c pr.c ---644 2 1 ../commands/pr.c pwd.c ---644 2 1 ../commands/pwd.c rev.c ---644 2 1 ../commands/rev.c rm.c ---644 2 1 ../commands/rm.c rmdir.c ---644 2 1 ../commands/rmdir.c roff.c ---644 2 1 ../commands/roff.c run ---644 2 1 ../commands/run shar.c ---644 2 1 ../commands/shar.c size.c ---644 2 1 ../commands/size.c sleep.c ---644 2 1 ../commands/sleep.c sort.c ---644 2 1 ../commands/sort.c split.c ---644 2 1 ../commands/split.c stty.c ---644 2 1 ../commands/stty.c su.c ---644 2 1 ../commands/su.c sum.c ---644 2 1 ../commands/sum.c sync.c ---644 2 1 ../commands/sync.c tail.c ---644 2 1 ../commands/tail.c tar.c ---644 2 1 ../commands/tar.c tee.c ---644 2 1 ../commands/tee.c time.c ---644 2 1 ../commands/time.c touch.c ---644 2 1 ../commands/touch.c tr.c ---644 2 1 ../commands/tr.c umount.c ---644 2 1 ../commands/umount.c uniq.c ---644 2 1 ../commands/uniq.c update.c ---644 2 1 ../commands/update.c wc.c ---644 2 1 ../commands/wc.c cal.c ---644 2 1 ../commands/cal.c cpdir.c ---644 2 1 ../commands/cpdir.c diff.c ---644 2 1 ../commands/diff.c du.c ---644 2 1 ../commands/du.c expr.c ---644 2 1 ../commands/expr.c find.c ---644 2 1 ../commands/find.c make.c ---644 2 1 ../commands/make.c more.c ---644 2 1 ../commands/more.c fix.c ---644 2 1 ../commands/fix.c printenv.c ---644 2 1 ../commands/printenv.c readfs.c ---644 2 1 ../commands/readfs.c test.c ---644 2 1 ../commands/test.c uudecode.c ---644 2 1 ../commands/uudecode.c uuencode.c ---644 2 1 ../commands/uuencode.c mined d--755 2 1 mined.h ---644 2 1 ../commands/mined/mined.h mined1.c ---644 2 1 ../commands/mined/mined1.c mined2.c ---644 2 1 ../commands/mined/mined2.c makefile ---644 2 1 ../commands/mined/makefile $ sh d--755 2 1 sh.h ---644 2 1 ../commands/sh/sh.h sh1.c ---644 2 1 ../commands/sh/sh1.c sh2.c ---644 2 1 ../commands/sh/sh2.c sh3.c ---644 2 1 ../commands/sh/sh3.c sh4.c ---644 2 1 ../commands/sh/sh4.c sh5.c ---644 2 1 ../commands/sh/sh5.c sh6.c ---644 2 1 ../commands/sh/sh6.c makefile ---644 2 1 ../commands/sh/makefile $ bin d--777 2 1 $ MINIX d--777 2 1 makefile ---644 2 1 ../commands/MINIX/makefile $ PCIX d--777 2 1 makefile ---644 2 1 ../commands/PCIX/makefile $ C86 d--777 2 1 make.bat ---644 2 1 ../commands/C86/make.bat $ $ bin d--755 2 1 cat ---755 2 1 ../commands/bin/cat cc ---755 2 1 ../commands/bin/cc asld ---755 2 1 ../commands/bin/asld echo ---755 2 1 ../commands/bin/echo ls ---755 2 1 ../commands/bin/ls make ---755 2 1 ../commands/bin/make mkdir -u-755 0 1 ../commands/bin/mkdir mv ---755 2 1 ../commands/bin/mv pr ---755 2 1 ../commands/bin/pr rm ---755 2 1 ../commands/bin/rm rmdir -u-755 0 1 ../commands/bin/rmdir time ---755 2 1 ../commands/bin/time $ lib d--755 2 1 cpp ---755 2 1 ../commands/bin/cpp cem ---755 2 1 ../commands/bin/cem cg ---755 2 1 ../commands/bin/cg opt ---755 2 1 ../commands/bin/opt crtso.s ---755 2 1 ../lib/MINIX/crtso.s end.s ---755 2 1 ../lib/MINIX/end.s head.s ---755 2 1 ../lib/MINIX/head.s libc.a ---755 2 1 ../commands/bin/libc.a $ $ 2proto.at.ram!𠤁Śboot 116 95 d--777 2 1 bin d--755 2 1 cp ---755 2 1 ../commands/bin/cp getlf ---755 2 1 ../commands/bin/getlf sh ---755 2 1 ../commands/bin/sh sync ---755 2 1 ../commands/bin/sync $ dev d--755 2 1 ram b--640 2 1 1 0 640 mem b--640 2 1 1 1 640 kmem b--640 2 1 1 2 640 null b--666 2 1 1 3 0 fd0 b--666 2 1 2 0 360 fd1 b--666 2 1 2 1 360 at0 b--666 2 1 2 0 1200 at1 b--666 2 1 2 1 1200 hd0 b--600 2 1 3 0 32000 hd1 b--600 2 1 3 1 32000 hd2 b--600 2 1 3 2 32000 hd3 b--600 2 1 3 3 32000 hd4 b--600 2 1 3 4 4096 tty0 c--666 2 1 4 0 tty c--666 2 1 5 0 lp c--222 2 1 6 0 $ etc d--755 2 1 mount -u-755 0 1 ../commands/bin/mount umount -u-755 0 1 ../commands/bin/umount update ---755 2 1 ../commands/bin/update passwd ---644 2 1 passwd rc ---644 2 1 rc message ---644 2 1 message ttys ---644 2 1 ttys $ lib d--755 2 1 $ tmp d--777 2 1 $ user d--755 2 1 $ usr d--755 2 1 $ $ proto.at.usr!Z˙ ¤boot 1200 255 d--755 1 1 ast d--755 8 3 .profile ---644 8 3 profile $ bin d--755 2 1 ar ---755 2 1 ../commands/bin/ar asld ---755 2 1 ../commands/bin/asld basename ---755 2 1 ../commands/bin/basename cal ---755 2 1 ../commands/bin/cal cat ---755 2 1 ../commands/bin/cat cc ---755 2 1 ../commands/bin/cc chmem ---755 2 1 ../commands/bin/chmem chmod ---755 2 1 ../commands/bin/chmod chown ---755 2 1 ../commands/bin/chown clr ---755 2 1 ../commands/bin/clr cmp ---755 2 1 ../commands/bin/cmp comm ---755 2 1 ../commands/bin/comm cpdir ---755 2 1 ../commands/bin/cpdir date ---755 2 1 ../commands/bin/date dd ---755 2 1 ../commands/bin/dd df -u-755 0 1 ../commands/bin/df diff ---755 2 1 ../commands/bin/diff dosread ---755 2 1 ../commands/bin/dosread du ---755 2 1 ../commands/bin/du echo ---755 2 1 ../commands/bin/echo expr ---755 2 1 ../commands/bin/expr fdisk ---755 2 1 ../commands/bin/fdisk find ---755 2 1 ../commands/bin/find fix ---755 2 1 ../commands/bin/fix grep ---755 2 1 ../commands/bin/grep gres ---755 2 1 ../commands/bin/gres head ---755 2 1 ../commands/bin/head kill ---755 2 1 ../commands/bin/kill libpack ---755 2 1 ../commands/bin/libpack libupack ---755 2 1 ../commands/bin/libupack ln ---755 2 1 ../commands/bin/ln login ---755 2 1 ../commands/bin/login lpr ---755 2 1 ../commands/bin/lpr ls ---755 2 1 ../commands/bin/ls make ---755 2 1 ../commands/bin/make mined ---755 2 1 ../commands/bin/mined mkdir -u-755 0 1 ../commands/bin/mkdir mkfs ---755 2 1 ../commands/bin/mkfs mknod ---755 2 1 ../commands/bin/mknod more ---755 2 1 ../commands/bin/more mv -u-755 0 1 ../commands/bin/mv od ---755 2 1 ../commands/bin/od passwd -u-755 0 1 ../commands/bin/passwd pr ---755 2 1 ../commands/bin/pr printenv ---755 2 1 ../commands/bin/printenv pwd ---755 2 1 ../commands/bin/pwd readfs ---755 2 1 ../commands/bin/readfs rev ---755 2 1 ../commands/bin/rev rm ---755 2 1 ../commands/bin/rm rmdir -u-755 0 1 ../commands/bin/rmdir roff ---755 2 1 ../commands/bin/roff shar ---755 2 1 ../commands/bin/shar size ---755 2 1 ../commands/bin/size sleep ---755 2 1 ../commands/bin/sleep sort ---755 2 1 ../commands/bin/sort split ---755 2 1 ../commands/bin/split stty ---755 2 1 ../commands/bin/stty su -u-755 0 1 ../commands/bin/su sum ---755 2 1 ../commands/bin/sum tail ---755 2 1 ../commands/bin/tail tar ---755 2 1 ../commands/bin/tar tee ---755 2 1 ../commands/bin/tee test ---755 2 1 ../commands/bin/test time ---755 2 1 ../commands/bin/time touch ---755 2 1 ../commands/bin/touch tr ---755 2 1 ../commands/bin/tr true ---755 2 1 ../commands/bin/true uniq ---755 2 1 ../commands/bin/uniq uudecode ---755 2 1 ../commands/bin/uudecode uuencode ---755 2 1 ../commands/bin/uuencode wc ---755 2 1 ../commands/bin/wc $ include d--755 2 1 blocksize.h ---644 2 1 ../include/blocksize.h errno.h ---644 2 1 ../include/errno.h sgtty.h ---644 2 1 ../include/sgtty.h signal.h ---644 2 1 ../include/signal.h stat.h ---644 2 1 ../include/stat.h setjmp.h ---644 2 1 ../include/setjmp.h stdio.h ---644 2 1 ../include/stdio.h $ lib d--755 2 1 cpp ---755 2 1 ../commands/bin/cpp cem ---755 2 1 ../commands/bin/cem cg ---755 2 1 ../commands/bin/cg opt ---755 2 1 ../commands/bin/opt crtso.s ---755 2 1 ../lib/MINIX/crtso.s end.s ---755 2 1 ../lib/MINIX/end.s head.s ---755 2 1 ../lib/MINIX/head.s libc.a ---755 2 1 ../commands/bin/libc.a $ test d--777 2 1 test0 -u-755 0 1 ../test/test0 test1 -u-755 0 1 ../test/test1 test2 -u-755 0 1 ../test/test2 test3 -u-755 0 1 ../test/test3 test4 -u-755 0 1 ../test/test4 test5 -u-755 0 1 ../test/test5 test6 -u-755 0 1 ../test/test6 test7 -u-755 0 1 ../test/test7 test8 -u-755 0 1 ../test/test8 test9 -u-755 0 1 ../test/test9 test10 -u-755 0 1 ../test/test10 t10a -u-755 0 1 ../test/t10a test11 -u-755 0 1 ../test/test11 t11a -u-755 0 1 ../test/t11a t11b -u-755 0 1 ../test/t11b test0.c ---644 2 1 ../test/test0.c test1.c ---644 2 1 ../test/test1.c test2.c ---644 2 1 ../test/test2.c test3.c ---644 2 1 ../test/test3.c test4.c ---644 2 1 ../test/test4.c test5.c ---644 2 1 ../test/test5.c test6.c ---644 2 1 ../test/test6.c test7.c ---644 2 1 ../test/test7.c test8.c ---644 2 1 ../test/test8.c test9.c ---644 2 1 ../test/test9.c test10.c ---644 2 1 ../test/test10.c t10a.c ---644 2 1 ../test/t10a.c test11.c ---644 2 1 ../test/test11.c t11a.c ---644 2 1 ../test/t11a.c t11b.c ---644 2 1 ../test/t11b.c run ---755 2 1 ../test/run MINIX d--755 2 1 ../test/MINIX makefile ---644 2 1 ../test/MINIX/makefile $ PCIX d--755 2 1 ../test/PCIX makefile ---644 2 1 ../test/PCIX/makefile $ $ doc d--755 2 1 READ_ME ---644 2 1 ../doc/READ_ME man_pages ---644 2 1 ../doc/man_pages $ $ proto.disk5 !°m ¤Łboot 360 95 d--777 1 1 kernel d--777 2 1 type.h ---644 2 1 ../kernel/type.h proc.h ---644 2 1 ../kernel/proc.h glo.h ---644 2 1 ../kernel/glo.h const.h ---644 2 1 ../kernel/const.h clock.c ---644 2 1 ../kernel/clock.c dmp.c ---644 2 1 ../kernel/dmp.c floppy.c ---644 2 1 ../kernel/floppy.c main.c ---644 2 1 ../kernel/main.c memory.c ---644 2 1 ../kernel/memory.c printer.c ---644 2 1 ../kernel/printer.c proc.c ---644 2 1 ../kernel/proc.c system.c ---644 2 1 ../kernel/system.c table.c ---644 2 1 ../kernel/table.c tty.c ---644 2 1 ../kernel/tty.c xt_wini.c ---644 2 1 ../kernel/xt_wini.c at_wini.c ---644 2 1 ../kernel/at_wini.c MINIX d--777 2 1 makefile ---644 2 1 ../kernel/MINIX/makefile klib88.s ---644 2 1 ../kernel/klib88.s mpx88.s ---644 2 1 ../kernel/mpx88.s $ PCIX d--777 2 1 makefile ---644 2 1 ../kernel/PCIX/makefile $ C86 d--777 2 1 make.bat ---644 2 1 ../kernel/C86/make.bat _link.bat ---644 2 1 ../kernel/C86/_link.bat linklist ---644 2 1 ../kernel/C86/linklist klib88.asm ---644 2 1 ../kernel/C86/klib88.asm mpx88.asm ---644 2 1 ../kernel/C86/mpx88.asm $ $ h d--777 2 1 signal.h ---644 2 1 ../h/signal.h stat.h ---644 2 1 ../h/stat.h sgtty.h ---644 2 1 ../h/sgtty.h error.h ---644 2 1 ../h/error.h callnr.h ---644 2 1 ../h/callnr.h com.h ---644 2 1 ../h/com.h const.h ---644 2 1 ../h/const.h type.h ---644 2 1 ../h/type.h $ $ 1proto.disk6 !6Q ¤N boot 360 255 d--755 1 1 fs d--755 2 1 type.h ---644 2 1 ../fs/type.h super.h ---644 2 1 ../fs/super.h path.c ---644 2 1 ../fs/path.c param.h ---644 2 1 ../fs/param.h inode.h ---644 2 1 ../fs/inode.h glo.h ---644 2 1 ../fs/glo.h fproc.h ---644 2 1 ../fs/fproc.h file.h ---644 2 1 ../fs/file.h dev.h ---644 2 1 ../fs/dev.h const.h ---644 2 1 ../fs/const.h cache.c ---644 2 1 ../fs/cache.c buf.h ---644 2 1 ../fs/buf.h device.c ---644 2 1 ../fs/device.c filedes.c ---644 2 1 ../fs/filedes.c inode.c ---644 2 1 ../fs/inode.c link.c ---644 2 1 ../fs/link.c main.c ---644 2 1 ../fs/main.c misc.c ---644 2 1 ../fs/misc.c mount.c ---644 2 1 ../fs/mount.c open.c ---644 2 1 ../fs/open.c pipe.c ---644 2 1 ../fs/pipe.c protect.c ---644 2 1 ../fs/protect.c putc.c ---644 2 1 ../fs/putc.c read.c ---644 2 1 ../fs/read.c stadir.c ---644 2 1 ../fs/stadir.c super.c ---644 2 1 ../fs/super.c table.c ---644 2 1 ../fs/table.c time.c ---644 2 1 ../fs/time.c utility.c ---644 2 1 ../fs/utility.c write.c ---644 2 1 ../fs/write.c MINIX d--777 2 1 makefile ---644 2 1 ../fs/MINIX/makefile $ PCIX d--777 2 1 makefile ---644 2 1 ../fs/PCIX/makefile $ C86 d--777 2 1 make.bat ---644 2 1 ../fs/C86/make.bat _link.bat ---644 2 1 ../fs/C86/_link.bat linklist ---644 2 1 ../fs/C86/linklist $ $ lib d--777 2 1 READ_ME ---644 2 1 ../lib/READ_ME run ---755 2 1 ../lib/run libsrc.a ---644 2 1 ../lib/libsrc.a MINIX d--777 2 1 crtso.s ---644 2 1 ../lib/MINIX/crtso.s end.s ---644 2 1 ../lib/MINIX/end.s head.s ---644 2 1 ../lib/MINIX/head.s setjmp.s ---644 2 1 ../lib/MINIX/setjmp.s $ PCIX d--777 2 1 crtso.s ---644 2 1 ../lib/PCIX/crtso.s end.s ---644 2 1 ../lib/PCIX/end.s head.s ---644 2 1 ../lib/PCIX/head.s setjmp.s ---644 2 1 ../lib/PCIX/setjmp.s $ C86 d--777 2 1 brksize.asm ---644 2 1 ../lib/C86/brksize.asm catchsig.asm ---644 2 1 ../lib/C86/catchsig.asm crtso.asm ---644 2 1 ../lib/C86/crtso.asm csv.asm ---644 2 1 ../lib/C86/csv.asm end.asm ---644 2 1 ../lib/C86/end.asm getutil.asm ---644 2 1 ../lib/C86/getutil.asm head.asm ---644 2 1 ../lib/C86/head.asm prologue.h ---644 2 1 ../lib/C86/prologue.h sendrec.asm ---644 2 1 ../lib/C86/sendrec.asm setjmp.asm ---644 2 1 ../lib/C86/setjmp.asm make.bat ---644 2 1 ../lib/C86/make.bat $ $ $ proto.disk7 !S‚ ¤boot 360 95 d--755 1 1 tools d--755 2 1 proto.a ---644 2 1 proto.a misc.a ---644 2 1 misc.a fsck.c ---644 2 1 fsck.c build.c ---644 2 1 build.c init.c ---644 2 1 init.c changemem ---644 2 1 changemem bootblok ---644 2 1 bootblok kernel ---644 2 1 ../kernel/kernel mm ---644 2 1 ../mm/mm fs ---644 2 1 ../fs/fs init ---644 2 1 init fsck ---644 2 1 fsck MINIX d--777 2 1 makefile ---644 2 1 MINIX/makefile bootblok.s ---644 2 1 bootblok.s fsck1.s ---644 2 1 fsck1.s $ PCIX d--777 2 1 makefile ---644 2 1 PCIX/makefile $ C86 d--777 2 1 dos2out.c ---644 2 1 C86/dos2out.c bootblok ---644 2 1 C86/bootblok bootblok.asm ---644 2 1 C86/bootblok.asm diskio.asm ---644 2 1 C86/diskio.asm fsck1.asm ---644 2 1 C86/fsck1.asm batfiles.a ---644 2 1 C86/batfiles.a $ $ mm d--777 2 1 const.h ---644 2 1 ../mm/const.h glo.h ---644 2 1 ../mm/glo.h mproc.h ---644 2 1 ../mm/mproc.h param.h ---644 2 1 ../mm/param.h type.h ---644 2 1 ../mm/type.h alloc.c ---644 2 1 ../mm/alloc.c break.c ---644 2 1 ../mm/break.c exec.c ---644 2 1 ../mm/exec.c forkexit.c ---644 2 1 ../mm/forkexit.c getset.c ---644 2 1 ../mm/getset.c main.c ---644 2 1 ../mm/main.c putc.c ---644 2 1 ../mm/putc.c signal.c ---644 2 1 ../mm/signal.c table.c ---644 2 1 ../mm/table.c utility.c ---644 2 1 ../mm/utility.c MINIX d--777 2 1 makefile ---644 2 1 ../mm/MINIX/makefile $ PCIX d--777 2 1 makefile ---644 2 1 ../mm/PCIX/makefile $ C86 d--777 2 1 batch.a ---644 2 1 ../mm/C86/batch.a $ $ $ proto.disk8 !Ą} ¤boot 360 95 d--755 1 1 commands d--755 2 1 ar.c ---644 2 1 ../commands/ar.c basename.c ---644 2 1 ../commands/basename.c cat.c ---644 2 1 ../commands/cat.c cc.c ---644 2 1 ../commands/cc.c chmem.c ---644 2 1 ../commands/chmem.c chmod.c ---644 2 1 ../commands/chmod.c chown.c ---644 2 1 ../commands/chown.c clr.c ---644 2 1 ../commands/clr.c cmp.c ---644 2 1 ../commands/cmp.c comm.c ---644 2 1 ../commands/comm.c cp.c ---644 2 1 ../commands/cp.c date.c ---644 2 1 ../commands/date.c dd.c ---644 2 1 ../commands/dd.c df.c ---644 2 1 ../commands/df.c dosread.c ---644 2 1 ../commands/dosread.c echo.c ---644 2 1 ../commands/echo.c getlf.c ---644 2 1 ../commands/getlf.c grep.c ---644 2 1 ../commands/grep.c gres.c ---644 2 1 ../commands/gres.c head.c ---644 2 1 ../commands/head.c kill.c ---644 2 1 ../commands/kill.c libpack.c ---644 2 1 ../commands/libpack.c libupack.c ---644 2 1 ../commands/libupack.c ln.c ---644 2 1 ../commands/ln.c login.c ---644 2 1 ../commands/login.c lpr.c ---644 2 1 ../commands/lpr.c ls.c ---644 2 1 ../commands/ls.c mkdir.c ---644 2 1 ../commands/mkdir.c mkfs.c ---644 2 1 ../commands/mkfs.c mknod.c ---644 2 1 ../commands/mknod.c mount.c ---644 2 1 ../commands/mount.c mv.c ---644 2 1 ../commands/mv.c od.c ---644 2 1 ../commands/od.c passwd.c ---644 2 1 ../commands/passwd.c pr.c ---644 2 1 ../commands/pr.c pwd.c ---644 2 1 ../commands/pwd.c rev.c ---644 2 1 ../commands/rev.c rm.c ---644 2 1 ../commands/rm.c rmdir.c ---644 2 1 ../commands/rmdir.c roff.c ---644 2 1 ../commands/roff.c run ---644 2 1 ../commands/run shar.c ---644 2 1 ../commands/shar.c size.c ---644 2 1 ../commands/size.c sleep.c ---644 2 1 ../commands/sleep.c sort.c ---644 2 1 ../commands/sort.c split.c ---644 2 1 ../commands/split.c stty.c ---644 2 1 ../commands/stty.c su.c ---644 2 1 ../commands/su.c sum.c ---644 2 1 ../commands/sum.c sync.c ---644 2 1 ../commands/sync.c tail.c ---644 2 1 ../commands/tail.c tar.c ---644 2 1 ../commands/tar.c tee.c ---644 2 1 ../commands/tee.c time.c ---644 2 1 ../commands/time.c touch.c ---644 2 1 ../commands/touch.c tr.c ---644 2 1 ../commands/tr.c umount.c ---644 2 1 ../commands/umount.c uniq.c ---644 2 1 ../commands/uniq.c update.c ---644 2 1 ../commands/update.c wc.c ---644 2 1 ../commands/wc.c bin d--777 2 1 $ MINIX d--777 2 1 makefile ---644 2 1 ../commands/MINIX/makefile $ PCIX d--777 2 1 makefile ---644 2 1 ../commands/PCIX/makefile $ C86 d--777 2 1 make.bat ---644 2 1 ../commands/C86/make.bat $ $ include d--777 2 1 blocksize.h ---644 2 1 ../include/blocksize.h ctype.h ---644 2 1 ../include/ctype.h errno.h ---644 2 1 ../include/errno.h grp.h ---644 2 1 ../include/grp.h lib.h ---644 2 1 ../include/lib.h pwd.h ---644 2 1 ../include/pwd.h regexp.h ---644 2 1 ../include/regexp.h setjmp.h ---644 2 1 ../include/setjmp.h sgtty.h ---644 2 1 ../include/sgtty.h signal.h ---644 2 1 ../include/signal.h stat.h ---644 2 1 ../include/stat.h stdio.h ---644 2 1 ../include/stdio.h $ $ $proto.disk9 !zŽ ¤ćboot 360 95 d--755 1 1 commands d--755 2 1 cal.c ---644 2 1 ../commands/cal.c cpdir.c ---644 2 1 ../commands/cpdir.c diff.c ---644 2 1 ../commands/diff.c du.c ---644 2 1 ../commands/du.c expr.c ---644 2 1 ../commands/expr.c find.c ---644 2 1 ../commands/find.c make.c ---644 2 1 ../commands/make.c more.c ---644 2 1 ../commands/more.c fdisk.c ---644 2 1 ../commands/fdisk.c fix.c ---644 2 1 ../commands/fix.c printenv.c ---644 2 1 ../commands/printenv.c readfs.c ---644 2 1 ../commands/readfs.c test.c ---644 2 1 ../commands/test.c uudecode.c ---644 2 1 ../commands/uudecode.c uuencode.c ---644 2 1 ../commands/uuencode.c mined d--755 2 1 mined.h ---644 2 1 ../commands/mined/mined.h mined1.c ---644 2 1 ../commands/mined/mined1.c mined2.c ---644 2 1 ../commands/mined/mined2.c makefile ---644 2 1 ../commands/mined/makefile $ sh d--755 2 1 sh.h ---644 2 1 ../commands/sh/sh.h sh1.c ---644 2 1 ../commands/sh/sh1.c sh2.c ---644 2 1 ../commands/sh/sh2.c sh3.c ---644 2 1 ../commands/sh/sh3.c sh4.c ---644 2 1 ../commands/sh/sh4.c sh5.c ---644 2 1 ../commands/sh/sh5.c sh6.c ---644 2 1 ../commands/sh/sh6.c makefile ---644 2 1 ../commands/sh/makefile $ $ $ proto.ramÁ bę ¤Űboot 240 95 d--777 2 1 bin d--755 2 1 cat ---755 2 1 ../commands/bin/cat cc ---755 2 1 ../commands/bin/cc cp ---755 2 1 ../commands/bin/cp getlf ---755 2 1 ../commands/bin/getlf kill ---755 2 1 ../commands/bin/kill ls ---755 2 1 ../commands/bin/ls mkdir -u-755 0 1 ../commands/bin/mkdir mined ---755 2 1 ../commands/bin/mined rm ---755 2 1 ../commands/bin/rm sh ---755 2 1 ../commands/bin/sh sync ---755 2 1 ../commands/bin/sync $ dev d--755 2 1 ram b--640 2 1 1 0 640 mem b--640 2 1 1 1 640 kmem b--640 2 1 1 2 640 null b--666 2 1 1 3 0 fd0 b--666 2 1 2 0 360 fd1 b--666 2 1 2 1 360 at0 b--666 2 1 2 0 1200 at1 b--666 2 1 2 1 1200 hd0 b--600 2 1 3 0 0 hd1 b--600 2 1 3 1 0 hd2 b--600 2 1 3 2 0 hd3 b--600 2 1 3 3 0 hd4 b--600 2 1 3 4 0 tty0 c--666 2 1 4 0 tty c--666 2 1 5 0 lp c--222 2 1 6 0 $ etc d--755 2 1 mount -u-755 0 1 ../commands/bin/mount umount -u-755 0 1 ../commands/bin/umount update ---755 2 1 ../commands/bin/update passwd ---644 2 1 passwd rc ---644 2 1 rc message ---644 2 1 message ttys ---644 2 1 ttys $ lib d--755 2 1 cpp ---755 2 1 ../commands/bin/cpp cem ---755 2 1 ../commands/bin/cem $ tmp d--777 2 1 $ user d--755 2 1 $ usr d--755 2 1 $ $ bproto.user!]œ ¤ boot 360 127 d--755 1 1 ast d--755 8 3 .profile ---644 8 3 profile $ bin d--755 2 1 cal ---755 2 1 ../commands/bin/cal cpdir ---755 2 1 ../commands/bin/cpdir diff ---755 2 1 ../commands/bin/diff du ---755 2 1 ../commands/bin/du expr ---755 2 1 ../commands/bin/expr find ---755 2 1 ../commands/bin/find gres ---755 2 1 ../commands/bin/gres libpack ---755 2 1 ../commands/bin/libpack libupack ---755 2 1 ../commands/bin/libupack more ---755 2 1 ../commands/bin/more fdisk ---755 2 1 ../commands/bin/fdisk fix ---755 2 1 ../commands/bin/fix passwd -u-755 0 1 ../commands/bin/passwd printenv ---755 2 1 ../commands/bin/printenv readfs ---755 2 1 ../commands/bin/readfs rev ---755 2 1 ../commands/bin/rev roff ---755 2 1 ../commands/bin/roff shar ---755 2 1 ../commands/bin/shar tar ---755 2 1 ../commands/bin/tar test ---755 2 1 ../commands/bin/test uudecode ---755 2 1 ../commands/bin/uudecode uuencode ---755 2 1 ../commands/bin/uuencode $ test d--777 2 1 test0 -u-755 0 1 ../test/test0 test1 -u-755 0 1 ../test/test1 test2 -u-755 0 1 ../test/test2 test3 -u-755 0 1 ../test/test3 test4 -u-755 0 1 ../test/test4 test5 -u-755 0 1 ../test/test5 test6 -u-755 0 1 ../test/test6 test7 -u-755 0 1 ../test/test7 test8 -u-755 0 1 ../test/test8 test9 -u-755 0 1 ../test/test9 test10 -u-755 0 1 ../test/test10 t10a -u-755 0 1 ../test/t10a test11 -u-755 0 1 ../test/test11 t11a -u-755 0 1 ../test/t11a t11b -u-755 0 1 ../test/t11b test0.c ---644 2 1 ../test/test0.c test1.c ---644 2 1 ../test/test1.c test2.c ---644 2 1 ../test/test2.c test3.c ---644 2 1 ../test/test3.c test4.c ---644 2 1 ../test/test4.c test5.c ---644 2 1 ../test/test5.c test6.c ---644 2 1 ../test/test6.c test7.c ---644 2 1 ../test/test7.c test8.c ---644 2 1 ../test/test8.c test9.c ---644 2 1 ../test/test9.c test10.c ---644 2 1 ../test/test10.c t10a.c ---644 2 1 ../test/t10a.c test11.c ---644 2 1 ../test/test11.c t11a.c ---644 2 1 ../test/t11a.c t11b.c ---644 2 1 ../test/t11b.c run ---755 2 1 ../test/run MINIX d--755 2 1 makefile ---644 2 1 ../test/MINIX/makefile $ PCIX d--755 2 1 makefile ---644 2 1 ../test/PCIX/makefile $ $ doc d--755 2 1 READ_ME ---644 2 1 ../doc/READ_ME man_pages ---644 2 1 ../doc/man_pages $ $ proto.usr!!˙ ¤ňboot 360 95 d--755 1 1 ast d--755 8 3 .profile ---644 8 3 profile $ bin d--755 2 1 ar ---755 2 1 ../commands/bin/ar asld ---755 2 1 ../commands/bin/asld basename ---755 2 1 ../commands/bin/basename chmem ---755 2 1 ../commands/bin/chmem chmod ---755 2 1 ../commands/bin/chmod chown ---755 2 1 ../commands/bin/chown clr ---755 2 1 ../commands/bin/clr cmp ---755 2 1 ../commands/bin/cmp comm ---755 2 1 ../commands/bin/comm date ---755 2 1 ../commands/bin/date dd ---755 2 1 ../commands/bin/dd df -u-755 0 1 ../commands/bin/df dosread ---755 2 1 ../commands/bin/dosread echo ---755 2 1 ../commands/bin/echo grep ---755 2 1 ../commands/bin/grep head ---755 2 1 ../commands/bin/head ln ---755 2 1 ../commands/bin/ln login ---755 2 1 ../commands/bin/login lpr ---755 2 1 ../commands/bin/lpr make ---755 2 1 ../commands/bin/make mkfs ---755 2 1 ../commands/bin/mkfs mknod ---755 2 1 ../commands/bin/mknod mv -u-755 0 1 ../commands/bin/mv od ---755 2 1 ../commands/bin/od pr ---755 2 1 ../commands/bin/pr pwd ---755 2 1 ../commands/bin/pwd rmdir -u-755 0 1 ../commands/bin/rmdir size ---755 2 1 ../commands/bin/size sleep ---755 2 1 ../commands/bin/sleep sort ---755 2 1 ../commands/bin/sort split ---755 2 1 ../commands/bin/split stty ---755 2 1 ../commands/bin/stty su -u-755 0 1 ../commands/bin/su sum ---755 2 1 ../commands/bin/sum tail ---755 2 1 ../commands/bin/tail tee ---755 2 1 ../commands/bin/tee time ---755 2 1 ../commands/bin/time touch ---755 2 1 ../commands/bin/touch tr ---755 2 1 ../commands/bin/tr true ---755 2 1 ../commands/bin/true uniq ---755 2 1 ../commands/bin/uniq wc ---755 2 1 ../commands/bin/wc $ include d--755 2 1 blocksize.h ---644 2 1 ../include/blocksize.h errno.h ---644 2 1 ../include/errno.h sgtty.h ---644 2 1 ../include/sgtty.h signal.h ---644 2 1 ../include/signal.h stat.h ---644 2 1 ../include/stat.h setjmp.h ---644 2 1 ../include/setjmp.h stdio.h ---644 2 1 ../include/stdio.h $ lib d--755 2 1 cg ---755 2 1 ../commands/bin/cg opt ---755 2 1 ../commands/bin/opt crtso.s ---755 2 1 ../lib/MINIX/crtso.s end.s ---755 2 1 ../lib/MINIX/end.s head.s ---755 2 1 ../lib/MINIX/head.s libc.a ---755 2 1 ../commands/bin/libc.a $ $ e˙passwdÁ bę ¤Groot::0:0::/: daemon:*:1:1::/etc: bin:*:2:2::/bin: ast::8:3::/usr/ast: rcÁ bę ¤›/bin/getlf "Please insert /usr diskette in drive 0. Then hit RETURN." /etc/mount /dev/fd0 /usr /usr/bin/date -q > BITSHIFT] |= 1 << ((b) & BITMASK)) #define clrbit(w, b) (w[(b) >> BITSHIFT] &= ~(1 << ((b) & BITMASK))) #define bitset(w, b) (w[(b) >> BITSHIFT] & (1 << ((b) & BITMASK))) int drive, partition, cylsiz, tracksiz; int virgin = 1; /* MUST be initialized to put it in data seg */ int floptrk = 9; /* MUST be initialized to put it in data seg */ int zone_ct = 360; int inode_ct = 95; struct dsb { inode_nr s_ninodes; /* # inodes on the minor device */ zone_nr s_nzones; /* total dev size, incl. bit maps etc */ unsigned short s_imap_blocks; /* # of blocks used by inode bit map */ unsigned short s_zmap_blocks; /* # of blocks used by zone bit map */ zone_nr s_firstdatazone; /* number of first data zone */ short s_log_zone_size; /* log2 of blocks/zone */ file_pos s_maxsize; /* maximum file size on this device */ int s_magic; /* magic number for super blocks */ } sb; #define STICKY_BIT 01000 /* not defined anywhere else */ /* ztob gives the block address of a zone * btoa gives the byte address of a block */ #define ztob(z) ((block_nr) (z) << sb.s_log_zone_size) #define btoa(b) ((long) (b) * BLOCK_SIZE) #define SCALE ((int) ztob(1)) /* # blocks in a zone */ #define FIRST sb.s_firstdatazone /* as the name says */ /* # blocks of each type */ #define N_SUPER 1 #define N_IMAP (sb.s_imap_blocks) #define N_ZMAP (sb.s_zmap_blocks) #define N_ILIST ((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK) #define N_DATA (sb.s_nzones - FIRST + 1) /* block address of each type */ #define BLK_SUPER (SUPER_BLOCK) #define BLK_IMAP (BLK_SUPER + N_SUPER) #define BLK_ZMAP (BLK_IMAP + N_IMAP) #define BLK_ILIST (BLK_ZMAP + N_ZMAP) #define BLK_FIRST ztob(FIRST) #define ZONE_SIZE ((int) ztob(BLOCK_SIZE)) #define NLEVEL (NR_ZONE_NUMS - NR_DZONE_NUM + 1) /* byte address of a zone/of an inode */ #define zaddr(z) btoa(ztob(z)) #define inoaddr(i) ((long) (i - 1) * INODE_SIZE + btoa(BLK_ILIST)) #define INDCHUNK (CINDIR * ZONE_NUM_SIZE) #define DIRCHUNK (CDIRECT * DIR_ENTRY_SIZE) char *prog, *device; /* program name (fsck), device name */ int firstcnterr; /* is this the first inode ref cnt error? */ unsigned *imap, *spec_imap; /* inode bit maps */ unsigned *zmap, *spec_zmap; /* zone bit maps */ unsigned *dirmap; /* directory (inode) bit map */ char *rwbuf; /* one block buffer cache */ char rwbuf1[BLOCK_SIZE]; /* in case of a DMA-overrun under DOS .. */ char rwbuf2[BLOCK_SIZE]; /* .. an other buffer can be used */ char nullbuf[BLOCK_SIZE]; /* null buffer */ links *count; /* inode count */ dir_struct nulldir; /* empty directory entry */ block_nr thisblk; /* block that is now in the buffer */ int changed; /* has the diskette been written to? */ struct stack { dir_struct *st_dir; struct stack *st_next; char st_presence; } *top; extern long lseek(); #ifdef DOS #define atol(s) atoi(s) /* kludge for C86 (no atol(s) in library) */ #else long atol(); #endif #ifdef STANDALONE extern end; /* last variable */ int *brk; /* the ``break'' (end of data space) */ #else int dev; /* file descriptor of the device */ #endif #define DOT 1 #define DOTDOT 2 /* counters for each type of inode/zone */ int nfreeinode, nregular, ndirectory, nblkspec, ncharspec, nbadinode; int nfreezone, ztype[NLEVEL]; int repair, automatic, listing, listsuper, makefs; /* flags */ int firstlist; /* has the listing header been printed? */ unsigned part_offset; /* sector offset for this partition */ char answer[] = {"Answer questions with y or n. Then hit RETURN"}; union types { int *u_char; /* %c */ int *u_int; /* %d */ unsigned *u_unsigned; /* %u */ long *u_long; /* %D */ char **u_charp; /* %s */ }; #ifndef STANDALONE # ifdef DOS # include "/lib/c86/stdio.h" # endif #else /*STANDALONE*/ /* Print the given character. */ putchar(c){ if (c == '\n') putc('\r'); putc(c); } /* Get a character from the user and echo it. */ getchar(){ register c; if ((c = getc() & 0xFF) == '\r') c = '\n'; putchar(c); return(c); } #endif /*STANDALONE*/ /* Print the number n. */ printnum(n, base, sign, width, pad) long n; int base, sign; int width, pad; { register short i, mod; char a[MAXWIDTH]; register char *p = a; if (sign) if (n < 0) { n = -n; width--; } else sign = 0; do { /* mod = n % base; n /= base */ mod = 0; for (i = 0; i < 32; i++) { mod <<= 1; if (n < 0) mod++; n <<= 1; if (mod >= base) { mod -= base; n++; } } *p++ = "0123456789ABCDEF"[mod]; width--; } while (n); while (width-- > 0) putchar(pad); if (sign) *p++ = '-'; while (p > a) putchar(*--p); } /* Print the character c. */ printchar(c, mode){ if (mode == 0 || (isprint(c) && c != '\\')) { putchar(c); return(1); } else { putchar('\\'); switch (c) { case '\0': putchar('0'); break; case '\b': putchar('b'); break; case '\n': putchar('n'); break; case '\r': putchar('r'); break; case '\t': putchar('t'); break; case '\f': putchar('f'); break; case '\\': putchar('\\'); break; default: printnum((long) (c & 0xFF), 8, 0, 3, '0'); return(4); } return(2); } } /* Print the arguments pointer to by `arg' according to format. */ doprnt(for9;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_mat, argp) char *format; union types argp; { register char *fmt, *s; register short width, pad, mode; for (fmt = format; *fmt != 0; fmt++) switch(*fmt) { case '\n': putchar('\r'); default: putchar(*fmt); break; case '%': if (*++fmt == '-') fmt++; pad = *fmt == '0' ? '0' : ' '; width = 0; while (isdigit(*fmt)) { width *= 10; width += *fmt++ - '0'; } if (*fmt == 'l' && islower(*++fmt)) *fmt = toupper(*fmt); mode = isupper(*fmt); switch (*fmt) { case 'c': case 'C': prc(nextarg(char)); break; case 'b': prn(unsigned, 2, 0); break; case 'B': prn(long, 2, 0); break; case 'o': prn(unsigned, 8, 0); break; case 'O': prn(long, 8, 0); break; case 'd': prn(int, 10, 1); break; case 'D': prn(long, 10, 1); break; case 'u': prn(unsigned, 10, 0); break; case 'U': prn(long, 10, 0); break; case 'x': prn(unsigned, 16, 0); break; case 'X': prn(long, 16, 0); break; case 's': case 'S': s = nextarg(charp); while (*s) prc(*s++); break; case '\0': break; default: putchar(*fmt); } while (width-- > 0) putchar(pad); } } /* Print the arguments according to fmt. */ printf(fmt, args) char *fmt; { doprnt(fmt, &args); } /* Initialize the variables used by this program. */ initvars(){ register level; #ifdef STANDALONE brk = &end; #endif nregular = ndirectory = nblkspec = ncharspec = nbadinode = 0; for (level = 0; level < NLEVEL; level++) ztype[level] = 0; changed = 0; firstlist = 1; firstcnterr = 1; thisblk = NO_BLOCK; } /* Copy n bytes. */ copy(p, q, n) register char *p, *q; register int n; { do *q++ = *p++; while (--n); } /* Print the string `s' and exit. */ fatal(s) char *s; { printf("%s\n", s); printf("fatal\n"); exit(-1); } /* Test for end of line. */ eoln(c) { return(c < 0 || c == '\n' || c == '\r'); } /* Ask a question and get the answer unless automatic is set. */ yes(question) char *question; { register c, answer; if (!repair) { printf("\n"); return(0); } printf("%s? ", question); if (automatic) { printf("yes\n"); return(1); } if ((c = answer = getchar()) == 'q' || c == 'Q') exit(1); while (!eoln(c)) c = getchar(); return !(answer == 'n' || answer == 'N'); } /* Convert string to integer. Representation is octal. */ atoo(s) char *s; { register n = 0; while ('0' <= *s && *s < '8') { n *= 8; n += *s++ - '0'; } return(n); } /* If repairing the file system, print a prompt and get a string from the user. */ input(buf, size) char *buf; { register char *p = buf; printf("\n"); if (repair) { printf("--> "); while (--size) { *p = getchar(); if (eoln(*p)) { *p = 0; return(p > buf); } p++; } *p = 0; while (!eoln(getchar())) ; return(1); } return(0); } /* Allocate some memory and zero it. */ char *alloc(nelem, elsize) unsigned nelem, elsize; { char *p; #ifdef STANDALONE register *r; p = (char *) brk; brk += nelem * ((elsize + sizeof(int) - 1) / sizeof(int)); for (r = (int *) p; r < brk; r++) *r = 0; return(p); #else extern char *calloc(); if ((p = calloc(nelem, elsize)) == 0) fatal("out of memory"); return(p); #endif } #ifndef STANDALONE /* Deallocate previously allocated memory. */ dealloc(p) char *p; { free(p); } #endif /* Print the name in a directory entry. */ printname(s) char *s; { register n = NAME_SIZE; do { if (*s == 0) break; printf("%c", isprint(*s) ? *s : '?'); s++; } while (--n); } /* Print the pathname given by a linked list pointed to by `sp'. The * names are in reverse order. */ printrec(sp) struct stack *sp; { if (sp->st_next != 0) { printrec(sp->st_next); printf("/"); printname(sp->st_dir->d_name); } } /* Print the current pathname. */ printpath(mode, nlcr){ if (top->st_next == 0) printf("/"); else printrec(top); switch (mode) { case 1: printf(" (ino = %u, ", top->st_dir->d_inum); break; case 2: printf(" (ino = %u)", top->st_dir->d_inum); break; } if (nlcr) printf("\n"); } #ifndef STANDALONE # ifndef DOS /* don't need to open devices under DOS */ /* Open the device. */ devopen(){ if ((dev = open(device, repair ? 2 : 0)) < 0) { perror(device); fatal(""); } } /* Close the device. */ devclose(){ if (close(dev) != 0) { perror("close"); fatal(""); } } # else /*DOS*/ devopen(){} /* dummies */ devclose(){} sync(){} # endif #endif #ifdef DOS # ifndef STANDALONE # define STANDALONE /* DOS will need the diskio routine */ # define TMP /* remember standalone wasn't defined */ # endif #endif #ifdef STANDALONE disktype() { register retry = 3, error, dir=READING; /* test whether at or pc diskette. Note logical sectors * count from 0 and bios counts from 1. */ tracksiz=15; cylsiz=30; reset_diskette(); do error = diskio(dir, 14, rwbuf, 1); while ( ((error & 0xFF00) != 0) && (retry--)); if ((error & 0xFF00)!=0) { /* not an AT-diskette */ tracksiz=9; cylsiz=18; retry=3; reset_diskette(); do error = diskio(dir, 8, rwbuf, 1); while ( ((error & 0xFF00) != 0) && (retry--)); if ((error & 0xFF00)!=0) fatal ("can't determine diskette-type"); } } # ifdef TMP # undef TMP # undef STANDALONE # endif #endif /* Read or write a block. * Note that under STANDALONE or DOS only the * A-drive (drive 0) can be used */ devio(bno, dir) block_nr bno; { long lastone; long offset = btoa(bno); register error; if (dir == READING && bno == thisblk) return; thisblk = bno; #ifdef DOS # ifndef STANDALONE # define STANDALONE /* DOS will need the diskio routine */ # define TMP /* remember standalone wasn't defined */ # endif #endif #ifdef STANDALONE { register sector = offset >> SECT_SHIFT, retry = 3; lastone = sector + part_offset + (BLOCK_SIZE>>SECT_SHIFT); if (lastone > 65535) { printf("Fsck cannot read beyond sector 65535\n"); exit(1); } error = diskio(dir, sector+part_offset, rwbuf, BLOCK_SIZE>>SECT_SHIFT); if ((error & 0xFF00) == 0) return; reset_diskette(); do { printf("error 0x%x %s block %D, retry\n", error, dir == READING ? "reading" : "writing", (long) bno); error = diskio(dir, sector+part_offset, rwbuf, BLOCK_SIZE >> SECT_SHIFT); if ((error & 0xFF00) == 0) return; } while (--retry != 0); } # ifdef TMP # undef TMP # undef STANDALONE # endif #else /*STANDALONE*/ { extern read(), write(), errno; lseek(dev, offset, 0); if (dir == READING) if (read(dev,rwbuf,BLOCK_SIZE) == BLOCK_SIZE) return; else error = errno; else if (write(dev,rwbuf,BLOCK_SIZE) == BLOCK_SIZE) return; else error = errno; } #endif /*STANDALONE*/ printf("%s: can't %s block %D (error = 0x%x)\n", prog, dir == READING ? "read" : "write", (long) bno, error); fatal(""); } /* Read `size' bytes from the disk starting at byte `offset'. */ devread(offset, buf, size) long offset; char *buf; { devio((block_nr) (offset / BLOCK_SIZE), READING); copy(&rwbuf[offset % BLOCK_SIZE], buf, size); } /* Write `size' bytes to the disk starting at byte `offset'. */ devwrite(offset, buf, size) long offset; char *buf; { if (!repair) fatal("internal error (devwrite)"); if (size != BLOCK_SIZE) devio((block_nr) (offset / BLOCK_SIZE), READING); copy(buf, &rwbuf[offset % BLOCK_SIZE], size); devio((block_nr) (offset / BLOCK_SIZE), WRITING); changed = 1; } /* Print a string with either a singular or a plural pronoun. */ pr(fmt, cnt, s, p) char *fmt, *s, *p; { printf(fmt, cnt, cnt == 1 ? s : p); } #ifndef STANDALONE /* Convert string to number. */ bit_nr getnumber(s) char *s; { register bit_nr n = 0; if (s == 0) return(NO_BIT); while (*s != 0) { if (!isdigit(*s)) return(NO_BIT); n *= 10; n += *s++ - '0'; } return(n); } /* See if the list pointed to by `argv' contains numbers. */ char **getlist(argv, type) char ***argv, *type; { register char **list = *argv; register empty = 1; while (getnumber(**argv) != NO_BIT) { (*argv)++; empty = 0; } if (empty) { printf("warning: no %s numbers given\n", type); return(0); } return(list); } #endif /*STANDALONE*/ /* Make a listing of the super block. If `repair' is set, ask the user * for changes. */ lsuper(){ char buf[80]; long atol(); do { printf("ninodes = %u", sb.s_ninodes); if (input(buf, 80)) sb.s_ninodes = atol(buf); printf("nzones = %u", sb.s_nzones); if (input(buf, 80)) sb.s_nzones = atol(buf); printf("imap_blocks = %u", sb.s_imap_blocks); if (input(buf, 80)) sb.s_imap_blocks = atol(buf); printf("zmap_blocks = %u", sb.s_zmap_blocks); if (input(buf, 80)) sb.s_zmap_blocks = atol(buf); printf("firstdatazone = %u", sb.s_firstdatazone); if (input(buf, 80)) sb.s_firstdatazone = atol(buf); printf("log_zone_size = %u", sb.s_log_zone_size); if (input(buf, 80)) sb.s_log_zone_size = atol(buf); printf("maxsize = %U", sb.s_maxsize); if (input(buf, 80)) sb.s_maxsize = atol(buf); if (yes("ok now")) { devwrite(btoa(BLK_SUPER), (char *) &sb, sizeof(sb)); return; } } while (yes("Do you want to try again")); if (repair) exit(0); } /* Add an empty root directory to the file system. */ makedev(){ register long position = BLK_IMAP * BLOCK_SIZE; register int n = N_IMAP + N_ZMAP + N_ILIST; static dir_struct rootdir[] = { { 1, "." }, { 1, ".." } }; static d_inode inode = { I_DIRECTORY | 0755, 0, sizeof(rootdir), 0, 0, 2 }; devio((block_nr) sb.s_nzones - 1, WRITING); nullbuf[0] = 1 << (ROOT_INODE - 1); /* corrupt nullbuf */ do { devwrite(position, nullbuf, BLOCK_SIZE); nullbuf[0] = 0; /* nullbuf restored */ position += BLOCK_SIZE; } while (--n); #ifndef STANDALONE time(&inode.i_modtime); #endif inode.i_zone[0] = FIRST; devwrite(inoaddr(ROOT_INODE), (char *) &inode, INODE_SIZE); devwrite(zaddr(FIRST), nullbuf, BLOCK_SIZE); devwrite(zaddr(FIRST), (char *) rootdir, sizeof(rootdir)); } /* Get the contents for the super block from the user. Make him some * suggestions. */ mkfs(){ char buf[80]; long atol(); printf("Hit RETURN key to select default values\n\n"); sb.s_nzones = zone_ct; printf("# zones (default: %d) ", zone_ct); if (input(buf, 80)) sb.s_nzones = atol(buf); sb.s_log_zone_size = 0; printf("log zonesize (default: %d) ", sb.s_log_zone_size); if (input(buf, 80)) sb.s_log_zone_size = atol(buf); sb.s_ninodes = inode_ct; printf("#inodes (default: %u) ", sb.s_ninodes); if (input(buf, 80)) sb.s_ninodes = atol(buf); sb.s_imap_blocks = (sb.s_ninodes + (1<> BITMAPSHIFT; sb.s_zmap_blocks = (sb.s_nzones + (1<> BITMAPSHIFT; sb.s_firstdatazone = (BLK_ILIST+N_ILIST+SCALE-1) >> sb.s_log_zone_size; sb.s_maxsize = MAX_FILE_POS; if (((sb.s_maxsize-1) >> sb.s_log_zone_size) / BLOCK_SIZE >= MAX_ZONES) sb.s_maxsize =((long)MAX_ZONES*BLOCK_SIZE)<> BITMAPSHIFT; if (sb.s_magic != SUPER_MAGIC) fatal("bad magic number in super block"); if ((short) sb.s_imap_blocks < n) fatal("too few imap blocks"); if (sb.s_imap_blocks != n) { pr("warning: expected %d imap_block%s", n, "", "s"); printf(" instead of %d\n", sb.s_imap_blocks); } n = (sb.s_nzones + (1 << BITMAPSHIFT) - 1) >> BITMAPSHIFT; if ((short) sb.s_zmap_blocks < n) fatal("too few zmap blocks"); if (sb.s_zmap_blocks != n) { pr("warning: expected %d zmap_block%s", n, "", "s"); printf(" instead of %d\n", sb.s_zmap_blocks); } if ((short) sb.s_firstdatazone >= sb.s_nzones) fatal("first data zone too large"); if ((unsigned short) sb.s_log_zone_size >= 8 * sizeof(block_nr)) fatal("log_zone_size too large"); if (sb.s_log_zone_size > 8) printf("warning: large log_zone_size (%d)\n", sb.s_log_zone_size); n = (BLK_ILIST + N_ILIST + SCALE - 1) >> sb.s_log_zone_size; if ((short) sb.s_firstdatazone < n) fatal("first data zone too small"); if (sb.s_firstdatazone != n) { printf("warning: expected first data zone to be %d ", n); printf("instead of %u\n", sb.s_firstdatazone); } maxsize = MAX_FILE_POS; if (((maxsize - 1) >> sb.s_log_zone_size) / BLOCK_SIZE >= MAX_ZONES) maxsize = ((long) MAX_ZONES*BLOCK_SIZE) << sb.s_log_zone_size; if (sb.s_maxsize != maxsize) { printf("warning: expected max size to be %D ", maxsize); printf("instead of %D\n", sb.s_maxsize); } } #ifndef STANDALONE /* Make a listing of the inodes given by `clist'. If `repair' is set, ask * the user for changes. */ lsi(clist) char **clist; { register bit_nr bit; register inode_nr ino; d_inode inode, *ip = &inode; char buf[80]; long atol(); if (clist == 0) return; while ((bit = getnumber(*clist++)) != NO_BIT) { setbit(spec_imap, bit); ino = bit; do { devread(inoaddr(ino), (char *) ip, INODE_SIZE); printf("inode %u:\n", ino); printf(" mode = %06o", ip->i_mode); if (input(buf, 80)) ip->i_mode = atoo(buf); printf(" nlinks = %6u", ip->i_nlinks); if (input(buf, 80)) ip->i_nlinks = atol(buf); printf(" size = %6D", ip->i_size); if (input(buf, 80)) ip->i_size = atol(buf); if (yes("Write this back")) { devwrite(inoaddr(ino), (char*) ip, INODE_SIZE); break; } } while (yes("Do you want to change it again")); } } #endif /*STANDALONE*/ /* Allocate `nblk' blocks worth of bitmap. */ unsigned *allocbitmap(nblk){ register unsigned *bitmap; bitmap = (unsigned *) alloc(nblk, BLOCK_SIZE); *bitmap |= 1; return(bitmap); } /* Load the bitmap starting at block `bno' from disk. */ loadbitmap(bitmap, bno, nblk) unsigned *bitmap; block_nr bno; { register i; register unsigned *p; p = bitmap; for (i = 0; i < nblk; i++, bno++, p += INTS_PER_BLOCK) devread(btoa(bno), (char *) p, BLOCK_SIZE); *bitmap |= 1; } /* Write the bitmap starting at block `bno' to disk. */ dumpbitmap(bitmap, bno, nblk) unsigned *bitmap; block_nr bno; { register i; register unsigned *p = bitmap; for (i = 0; i < nblk; i++, bno++, p += INTS_PER_BLOCK) devwrite(btoa(bno), (char *) p, BLOCK_SIZE); } /* Initialize the given bitmap by setting all the bits starting at `bit'. */ initbitmap(bitmap, bit, nblk) unsigned *bitmap; bit_nr bit; { register unsigned *first, *last; while (bit & BITMASK) { setbit(bitmap, bit); bit++; } first = &bitmap[bit >> BITSHIFT]; last = &bitmap[nblk * INTS_PER_BLOCK]; while (first < last) *first++ = ~0; } #ifndef STANDALONE /* Set the bits given by `list' in the bitmap. */ fillbitmap(bitmap, lwb, upb, list) unsigned *bitmap; bit_nr lwb, upb; char **list; { register bit_nr bit; if (list == 0) return; while ((bit = getnumber(*list++)) != NO_BIT) if (bit < lwb || bit >= upb) { if (bitmap == spec_imap) printf("inode number %u ", bit); else printf("zone number %u ", bit); printf("out of range (ignored)\n"); } else setbit(bitmap, bit - lwb + 1); } /* Deallocate the bitmap `p'. */ freebitmap(p) unsigned *p; { dealloc((char *) p); } #endif /*STANDALONE*/ /* Get all the bitmaps used by this program. */ getbitmaps(){ imap = allocbitmap(N_IMAP); zmap = allocbitmap(N_ZMAP); spec_imap = allocbitmap(N_IMAP); spec_zmap = allocbitmap(N_ZMAP); dirmap = allocbitmap(N_IMAP); } #ifndef STANDALONE /* Release all the space taken by the bitmaps. */ putbitmaps(){ freebitmap(imap); freebitmap(zmap); freebitmap(spec_imap); freebitmap(spec_zmap); freebitmap(dirmap); } #endif /* `w1' and `w2' are differing words from two bitmaps that should be * identical. Print what's the matter with them. */ chkword(w1, w2, bit, type, n, report) unsigned w1, w2; char *type; bit_nr bit; int *n, *report; { for (; w1 | w2; w1 >>= 1, w2 >>= 1, bit++) if ((w1 ^ w2) & 1 && ++(*n) % MAXPRINT == 0 && *report && (!repair || automatic || yes("stop this listing"))) *report = 0; else if (*report) if ((w1 & 1) && !(w2 & 1)) printf("%s %u is missing\n", type, bit); else if (!(w1 & 1) && (w2 & 1)) printf("%s %u is not free\n", type, bit); } /* Check if the given (correct) bitmap is identical with the one that is * on the disk. If not, ask if the disk should be repaired. */ chkmap(cmap, dmap, bit, blkno, nblk, nbit, type) unsigned *cmap, *dmap; bit_nr bit, nbit; block_nr blkno; char *type; { register unsigned *p = dmap, *q = cmap; int report = 1, nerr = 0; if (makefs) { dumpbitmap(cmap, blkno, nblk); return; } printf("Checking %s map\n", type); loadbitmap(dmap, blkno, nblk); do { if (*p != *q) chkword(*p, *q, bit, type, &nerr, &report); p++; q++; } while ((bit += 8 * sizeof(unsigned)) < nbit); if ((!repair || automatic) && !report) printf("etc. "); if (nerr > MAXPRINT || nerr > 10) printf("%d errors found. ", nerr); if (nerr != 0 && yes("install a new map")) dumpbitmap(cmap, blkno, nblk); if (nerr > 0) printf("\n"); } /* See if the inodes that aren't allocated are cleared. */ chkilist(){ register inode_nr ino = 1; mask_bits mode; if (makefs) return; printf("Checking inode list\n"); do if (!bitset(imap, (bit_nr) ino)) { devread(inoaddr(ino), (char *) &mode, sizeof(mode)); if (mode != I_NOT_ALLOC) { printf("mode inode %u not cleared", ino); if (yes(". clear")) devwrite(inoaddr(ino), nullbuf, INODE_SIZE); } } while (++ino <= sb.s_ninodes); printf("\n"); } /* Allocate an array to maintain the inode reference counts in. */ getcount(){ count = (links *) alloc(sb.s_ninodes + 1, sizeof(links)); } /* The reference count for inode `ino' is wrong. Ask if it should be adjusted. */ counterror(ino) inode_nr ino; { d_inode inode; if (firstcnterr) { printf("INODE NLINK COUNT\n"); firstcnterr = 0; } devread(inoaddr(ino), (char *) &inode, INODE_SIZE); count[ino] += inode.i_nlinks; printf("%5u %5u %5u", ino, (unsigned) inode.i_nlinks, count[ino]); if (yes(" adjust")) { if ((inode.i_nlinks = count[ino]) == 0) { fatal("internal error (counterror)"); /* This would be a patch inode.i_mode = I_NOT_ALLOC; clrbit(imap, (bit_nr) ino); */ } devwrite(inoaddr(ino), (char *) &inode, INODE_SIZE); } } /* Check if the reference count of the inodes are correct. The array `count' * is maintained as follows: an entry indexed by the inode number is * incremented each time a link is found; when the inode is read the link * count in there is substracted from the corresponding entry in `count'. * Thus, when the whole file system has been traversed, all the entries * should be zero. */ chkcount(){ register inode_nr ino; for (ino = 1; ino <= sb.s_ninodes; ino++) if (count[ino] != 0) counterror(ino); if (!firstcnterr) printf("\n"); } #ifndef STANDALONE /* Deallocate the `count' array. */ freecount(){ dealloc((char *) count); } #endif /* Print the inode permission bits given by mode and shift. */ printperm(mode, shift, special, overlay) mask_bits mode; { printf(mode >> shift & R_BIT ? "r" : "-"); printf(mode >> shift & W_BIT ? "w" : "-"); if (mode & special) printf("%c", overlay); else printf(mode >> shift & X_BIT ? "x" : "-"); } /* List the given inode. */ list(ino, ip) inode_nr ino; d_inode *ip; { if (firstlist) { firstlist = 0; printf(" inode permission link size name\n"); } printf("%6u ", ino); switch (ip->i_mode & I_TYPE) { case I_REGULAR: printf("-"); break; case I_DIRECTORY: printf("d"); break; case I_CHAR_SPECIAL: printf("c"); break; case I_BLOCK_SPECIAL: printf("b"); break; default: printf("?"); } printperm(ip->i_mode, 6, I_SET_UID_BIT, 's'); printperm(ip->i_mode, 3, I_SET_GID_BIT, 's'); printperm(ip->i_mode, 0, STICKY_BIT, 't'); printf(" %3u ", ip->i_nlinks); switch (ip->i_mode & I_TYPE) { case I_CHAR_SPECIAL: case I_BLOCK_SPECIAL: printf(" %2x,%2x ", (dev_nr) ip->i_zone[0] >> MAJOR & 0xFF, (dev_nr) ip->i_zone[0] >> MINOR & 0xFF); break; default: printf("%7D ", ip->i_size); } printpath(0, 1); } /* Remove an entry from a directory if ok with the user. */ remove(dp) dir_struct *dp; { int i; char *cp1, *cp2; setbit(spec_imap, (bit_nr) dp->d_inum); if (yes(". remove entry")) { count[dp->d_inum]--; cp1 = (char *) &nulldir; cp2 = (char *) dp; i = sizeof(dir_struct); while (i--) *cp2++ = *cp1++; return(1); } return(0); } /* See if the `.' or `..' entry is as expected. */ chkdots(ino, pos, dp, exp) inode_nr ino, exp; file_pos pos; dir_struct *dp; { if (dp->d_inum != exp) { printf("bad %s in ", dp->d_name); printpath(1, 0); printf("%s is linked to %u ", dp->d_name, dp->d_inum); printf("instead of %u)", exp); setbit(spec_imap, (bit_nr) ino); setbit(spec_imap, (bit_nr) dp->d_inum); setbit(spec_imap, (bit_nr) exp); if (yes(". repair")) { count[dp->d_inum]--; dp->d_inum = exp; count[exp]++; return(0); } } else if (pos != (dp->d_name[1] ? DIR_ENTRY_SIZE : 0)) { printf("warning: %s has offset %D in ", dp->d_name, pos); printpath(1, 0); printf("%s is linked to %u)\n", dp->d_name, dp->d_inum); setbit(spec_imap, (bit_nr) ino); setbit(spec_imap, (bit_nr) dp->d_inum); setbit(spec_imap, (bit_nr) exp); } return(1); } /* Check the name in a directory entry. */ chkname(ino, dp) inode_nr ino; dir_struct *dp; { register n = NAME_SIZE + 1; register char *p = dp->d_name; if (*p == 0) { printf("null name found in "); printpath(0, 0); setbit(spec_imap, (bit_nr) ino); if (remove(dp)) return(0); } while (--n != 0 && *p != 0) if (*p++ == '/') { printf("found a '/' in entry of directory "); printpath(1, 0); setbit(spec_imap, (bit_nr) ino); printf("entry = '"); printname(dp->d_name); printf("')"); if (remove(dp)) return(0); break; } return(1); } /* Check a directory entry. Here the routine `descendtree' is called * recursively to check the file or directory pointed to by the entry. */ chkentry(ino, pos, dp) inode_nr ino; file_pos pos; dir_struct *dp; { char *cp1, *cp2; int i; if (dp->d_inum < ROOT_INODE || dp->d_inum > sb.s_ninodes) { printf("bad inode found in directory "); printpath(1, 0); printf("ino found = %u, ", dp->d_inum); printf("name = '"); printname(dp->d_name); printf("')"); if (yes(". remove entry")) { cp1 = (char *) &nulldir; cp2 = (char *) dp; i = sizeof(dir_struct); while (i--) *cp2++ = *cp1++; return(0); } return(1); } if ((unsigned) count[dp->d_inum] == MAX_LINKS) { printf("too many links to ino %u\n", dp->d_inum); printf("discovered at entry '"); printname(dp->d_name); printf("' in directory "); printpath(0, 1); if (remove(dp)) return(0); } count[dp->d_inum]++; if (strcmp(dp->d_name, ".") == 0) { top->st_presence |= DOT; return(chkdots(ino, pos, dp, ino)); } if (strcmp(dp->d_name, "..") == 0) { top->st_presence |= DOTDOT; return(chkdots(ino, pos, dp, ino == ROOT_INODE ? ino : top->st_next->st_dir->d_inum)); } if (!chkname(ino, dp)) return(0); if (bitset(dirmap, (bit_nr) dp->d_inum)) { printf("link to directory discovered in "); printpath(1, 0); printf("name = '"); printname(dp->d_name); printf("', dir ino = %u)", dp->d_inum); return !remove(dp); } return(descendtree(dp)); } /* Check a zone of a directory by checking all the entries in the zone. * The zone is split up into chunks to not allocate too much stack. */ chkdirzone(ino, ip, pos, zno) inode_nr ino; d_inode *ip; file_pos pos; zone_nr zno; { dir_struct dirblk[CDIRECT]; register dir_struct *dp; register n = SCALE * (NR_DIR_ENTRIES / CDIRECT), dirty; register long offset = zaddr(zno); do { devread(offset, (char *) dirblk, DIRCHUNK); dirty = 0; for (dp = dirblk; dp < &dirblk[CDIRECT]; dp++) { if (ip->i_size - pos < DIR_ENTRY_SIZE) { printf("bad format in directory "); printpath(2, 0); if (yes(". truncate")) { setbit(spec_imap, (bit_nr) ino); ip->i_size = pos; dirty = 1; } else return(0); } if (dp->d_inum != NO_ENTRY && !chkentry(ino, pos, dp)) dirty = 1; if ((pos += DIR_ENTRY_SIZE) >= ip->i_size) break; } if (dirty) devwrite(offset, (char *) dirblk, DIRCHUNK); offset += DIRCHUNK; } while (--n && pos < ip->i_size); return(1); } /* There is something wrong with the given zone. Print some details. */ errzone(mess, zno, level, pos) char *mess; zone_nr zno; file_pos pos; { printf("%s zone in ", mess); printpath(1, 0); printf("zno = %u, type = ", zno); switch (level) { case 0: printf("DATA"); break; case 1: printf("SINGLE INDIRECT"); break; case 2: printf("DOUBLE INDIRECT"); break; default: printf("VERY INDIRECT"); } printf(", pos = %D)\n", pos); } /* Found the given zone in the given inode. Check it, and if ok, mark it * in the zone bitmap. */ markzone(ino, zno, level, pos) inode_nr ino; zone_nr zno; file_pos pos; { register bit_nr bit = (bit_nr) zno - FIRST + 1; ztype[level]++; if (zno < FIRST || zno >= sb.s_nzones) { errzone("out-of-range", zno, level, pos); return(0); } if (bitset(zmap, bit)) { setbit(spec_zmap, bit); errzone("duplicate", zno, level, pos); return(0); } nfreezone--; if (bitset(spec_zmap, bit)) errzone("found", ino, zno, level, pos, bit); setbit(zmap, bit); return(1); } /* Check an indirect zone by checking all of its entries. * The zone is split up into chunks to not allocate too much stack. */ chkindzone(ino, ip, pos, zno, level) inode_nr ino; d_inode *ip; file_pos *pos; zone_nr zno; { zone_nr indirect[CINDIR]; register n = NR_INDIRECTS / CINDIR; register long offset = zaddr(zno); do { devread(offset, (char *) indirect, INDCHUNK); if (!chkzones(ino, ip, pos, indirect, CINDIR, level - 1)) return(0); offset += INDCHUNK; } while (--n && *pos < ip->i_size); return(1); } /* Return the size of a gap in the file, represented by a null zone number * at some level of indirection. */ file_pos jump(level){ file_pos power = ZONE_SIZE; if (level != 0) do power *= NR_INDIRECTS; while (--level); return(power); } /* Check a zone, which may be either a normal data zone, a directory zone, * or an indirect zone. */ zonechk(ino, ip, pos, zno, level) inode_nr ino; d_inode *ip; file_pos *pos; zone_nr zno; { if (level == 0) { if ((ip->i_mode & I_TYPE) == I_DIRECTORY && !chkdirzone(ino, ip, *pos, zno)) return(0); *pos += ZONE_SIZE; return(1); } else return chkindzone(ino, ip, pos, zno, level); } /* Check a list of zones given by `zlist'. */ chkzones(ino, ip, pos, zlist, len, level) inode_nr ino; d_inode *ip; file_pos *pos; zone_nr *zlist; { register ok = 1, i; for (i = 0; i < len && *pos < ip->i_size; i++) if (zlist[i] == NO_ZONE) *pos += jump(level); else if (!markzone(ino, zlist[i], level, *pos)) { *pos += jump(level); ok = 0; } else if (!zonechk(ino, ip, pos, zlist[i], level)) ok = 0; return(ok); } /* Check a file or a directory. */ chkfile(ino, ip) inode_nr ino; d_inode *ip; { register ok, i, level; file_pos pos = 0; ok = chkzones(ino, ip, &pos, &ip->i_zone[0], NR_DZONE_NUM, 0); for (i = NR_DZONE_NUM, level = 1; i < NR_ZONE_NUMS; i++, level++) if (!chkzones(ino, ip, &pos, &ip->i_zone[i], 1, level)) ok = 0; return(ok); } /* Check a directory by checking the contents. Check if . and .. are present. */ chkdirectory(ino, ip) inode_nr ino; d_inode *ip; { register ok; setbit(dirmap, (bit_nr) ino); if (ip->i_size > MAXDIRSIZE) { printf("warning: huge directory: "); printpath(2, 1); } ok = chkfile(ino, ip); if (!(top->st_presence & DOT)) { printf(". missing in "); printpath(2, 1); ok = 0; } if (!(top->st_presence & DOTDOT)) { printf(".. missing in "); printpath(2, 1); ok = 0; } return(ok); } /* Check the mode of an inode, and if it is a file or a directory, check * the contents. */ chkmode(ino, ip) inode_nr ino; d_inode *ip; { switch (ip->i_mode & I_TYPE) { case I_REGULAR: nregular++; return chkfile(ino, ip); break; case I_DIRECTORY: ndirectory++; return chkdirectory(ino, ip); case I_BLOCK_SPECIAL: nblkspec++; return(1); case I_CHAR_SPECIAL: ncharspec++; return(1); default: nbadinode++; printf("bad mode of "); printpath(1, 0); printf("mode = %o)", ip->i_mode); return(0); } } /* Check an inode. */ chkinode(ino, ip) inode_nr ino; d_inode *ip; { if (ino == ROOT_INODE && (ip->i_mode & I_TYPE) != I_DIRECTORY) { printf("root inode is not a directory "); printf("(ino = %u, mode = %o)\n", ino, ip->i_mode); fatal(""); } if (ip->i_nlinks == 0) { printf("link count zero of "); printpath(2, 0); return(0); } nfreeinode--; setbit(imap, (bit_nr) ino); if ((unsigned) ip->i_nlinks > MAX_LINKS) { printf("link count too big in "); printpath(1, 0); printf("cnt = %u)\n", (unsigned) ip->i_nlinks); count[ino] -= MAX_LINKS; setbit(spec_imap, (bit_nr) ino); } else count[ino] -= (unsigned) ip->i_nlinks; return chkmode(ino, ip); } /* Check the directory entry pointed to by dp, by checking the inode. */ descendtree(dp) dir_struct *dp; { d_inode inode; register inode_nr ino = dp->d_inum; register visited; struct stack stk; char *cp1, *cp2; int i; stk.st_dir = dp; stk.st_next = top; top = &stk; if (bitset(spec_imap, (bit_nr) ino)) { printf("found inode %u: ", ino); printpath(0, 1); } visited = bitset(imap, (bit_nr) ino); if (!visited || listing) { devread(inoaddr(ino), (char *) &inode, INODE_SIZE); if (listing) list(ino, &inode); if (!visited && !chkinode(ino, &inode)) { setbit(spec_imap, (bit_nr) ino); if (yes("remove")) { count[ino] += inode.i_nlinks - 1; clrbit(imap, (bit_nr) ino); devwrite(inoaddr(ino), nullbuf, INODE_SIZE); cp1 = (char *) &nulldir; cp2 = (char *) dp; i = sizeof(dir_struct); while (i--) *cp2++ = *cp1++; top = top->st_next; return(0); } } } top = top->st_next; return(1); } /* Check the file system tree. */ chktree(){ dir_struct dir; if (!makefs) nfreeinode = sb.s_ninodes; nfreezone = N_DATA; dir.d_inum = ROOT_INODE; dir.d_name[0] = 0; if (!descendtree(&dir)) fatal("bad root inode"); printf("\n"); } /* Print the totals of all the objects found. */ printtotal(){ printf("blocksize = %5d ", BLOCK_SIZE); printf("zonesize = %5d\n", ZONE_SIZE); printf("\n"); pr("%6u Regular file%s\n", nregular, "", "s"); pr("%6u Director%s\n", ndirectory, "y", "ies"); pr("%6u Block special file%s\n", nblkspec, "", "s"); pr("%6u Character special file%s\n", ncharspec, "", "s"); if (nbadinode != 0) pr("%6u Bad inode%s\n", nbadinode, "", "s"); pr("%6u Free inode%s\n", nfreeinode, "", "s"); /* Don't print some fields. printf("\n"); pr("%6u Data zone%s\n", ztype[0], "", "s"); pr("%6u Single indirect zone%s\n", ztype[1], "", "s"); pr("%6u Double indirect zone%s\n", ztype[2], "", "s"); */ pr("%6u Free zone%s\n", nfreezone, "", "s"); } /* Check the device which name is given by `f'. The inodes listed by `clist' * should be listed separately, and the inodes listed by `ilist' and the zones * listed by `zlist' should be watched for while checking the file system. */ chkdev(f, clist, ilist, zlist) char *f, **clist, **ilist, **zlist; { if (automatic || makefs) repair = 1; device = f; initvars(); #ifndef STANDALONE devopen(); #endif getsuper(); chksuper(); #ifndef STANDALONE lsi(clist); #endif getbitmaps(); initbitmap(imap, (bit_nr) sb.s_ninodes + 1, N_IMAP); initbitmap(zmap, (bit_nr) sb.s_nzones - FIRST + 1, N_ZMAP); #ifndef STANDALONE fillbitmap(spec_imap, (bit_nr) 1, (bit_nr) sb.s_ninodes + 1, ilist); fillbitmap(spec_zmap, (bit_nr) FIRST, (bit_nr) sb.s_nzones, zlist); #endif getcount(); chktree(); chkmap(zmap, spec_zmap, (bit_nr) FIRST - 1, BLK_ZMAP, N_ZMAP, (bit_nr) sb.s_nzones, "zone"); chkcount(); chkmap(imap, spec_imap, (bit_nr) 0, BLK_IMAP, N_IMAP, (bit_nr) sb.s_ninodes + 1, "inode"); chkilist(); printtotal(); #ifndef STANDALONE putbitmaps(); freecount(); devclose(); #endif if (changed) printf("----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n"); } main(argc, argv) char **argv; { register char **clist = 0, **ilist = 0, **zlist = 0; #ifdef STANDALONE register c, command; if (virgin) floptrk = tracksiz; /* save 9 or 15 in floptrk */ virgin = 0; /* only on first pass thru */ if (tracksiz < 9 || cylsiz < 18) printf("Bootblok gave bad tracksiz\n"); rwbuf = rwbuf1; prog = "fsck"; printf("\n\n\n\n"); for (;;) { printf("\nHit key as follows:\n\n"); printf(" = start MINIX (root file system in drive 0)\n"); printf(" f check the file system (first insert any file system diskette)\n"); printf(" l check and list file system (first insert any file system diskette)\n"); printf(" m make an (empty) file system (first insert blank, formatted diskette)\n"); printf(" h check hard disk file system\n"); printf("\n# "); c = getc(); command = c & 0xFF; printf("%c\n", command); part_offset = 0; partition = 0; drive = 0; switch (command) { case 'h': get_partition(); drive = (partition < PARB ? 0x80 : 0x81); cylsiz = 68; tracksiz = 17; printf("Checking hard disk. %s\n", answer); if (read_partition() < 0) continue; repair = 1; break; case 'f': printf("Checking diskette. %s\n", answer); disktype(); /* init tracksiz & cylsiz */ repair = 1; break; case 'l': printf("Checking diskette. %s\n", answer); listing = listsuper = 1; disktype(); /* init tracksiz & cylsiz */ break; case 'm': printf("Making empty file system\n"); disktype(); /* init tracksiz & cylsiz */ makefs = 1; if (tracksiz == 15) { /* 1.2M diskette. */ zone_ct = 1200; inode_ct = 255; } break; case '=': return((c >> 8) & 0xFF); default: printf("Illegal command\n"); continue; } chkdev("disk(ette)", clist, ilist, zlist); repair = listing = listsuper = makefs = 0; } #else /* STANDALONE */ register devgiven = 0; register char *arg; rwbuf = rwbuf1; #ifdef DOS if (DMAoverrun(rwbuf1)) rwbuf = rwbuf2; disktype() /* init tracksiz & cylsize for disk in A: */ #endif sync(); prog = *argv++; while ((arg = *argv++) != 0) if (arg[0] == '-' && arg[1] != 0 && arg[2] == 0) switch (arg[1]) { case 'a': automatic ^= 1; break; case 'c': clist = getlist(&argv, "inode"); break; case 'i': ilist = getlist(&argv, "inode"); break; case 'z': zlist = getlist(&argv, "zone" ); break; case 'r': repair ^= 1; break; case 'l': listing ^= 1; break; case 's': listsuper ^= 1; break; case 'm': makefs ^= 1; break; default: printf("%s: unknown flag '%s'\n", prog, arg); } else { chkdev(arg, clist, ilist, zlist); clist = 0; ilist = 0; zlist = 0; devgiven = 1; } if (!devgiven) chkdev("/dev/disk", clist, ilist, zlist); return(0); #endif /*STANDALONE*/ } get_partition() { /* Ask for a partition number and wait for it. */ char chr; while (1) { printf("\n\nPlease enter partition number. Drive 0: 1-4, drive 1: 6-9, then hit RETURN: "); while (1) { chr = getc(); printf("%c", chr); if (chr == '\r') { printf("\n"); if (partition > 0) return; else break; } else { if (partition > 0) break; } if (chr < '1' || chr > '9' || chr == '5') break; partition = chr - '0'; } partition = 0; } } /* This define tells where to find things in partition table. */ #define P1 0x1C6 int read_partition() { /* Read the partition table to find out where the requested partition * begins. Put the sector offset in 'part_offset'. */ int error, p, retries = 0; long val[4]; long b0, b1, b2, b3; while (1) { retries++; if (retries > 5) { printf("Disk errors. Can't read partition table\n"); return(-1); } error = diskio(READING, 0, rwbuf, 1); if ( (error&0xFF00) == 0) break; } /* Find start of the requested partition and set 'part_offset'. */ for (p=0; p<4; p++) { b0 = rwbuf[P1+16*p+0] & 0xFF; b1 = rwbuf[P1+16*p+1] & 0xFF; b2 = rwbuf[P1+16*p+2] & 0xFF; b3 = rwbuf[P1+16*p+3] & 0xFF; val[p] = (b3<<24) | (b2<<16) | (b1<<8) | b0; if (val[p] > 65535) { printf("Fsck can't handle partitions above sector 65535\n"); exit(1); } } p = (partition >= PARB ? partition - PARB + 1 : partition); sort(val); part_offset = (unsigned) val[p-1]; if ((part_offset % (BLOCK_SIZE/SECTOR_SIZE)) != 0) part_offset = (part_offset/(BLOCK_SIZE/SECTOR_SIZE)+1)*(BLOCK_SIZE/SECTOR_SIZE); return(0); } sort(val) register long *val; { register int i,j; for (i=0; i<4; i++) for (j=0; j<3; j++) if ((val[j] == 0) && (val[j+1] != 0)) swap(&val[j], &val[j+1]); else if (val[j] > val[j+1] && val[j+1] != 0) swap(&val[j], &val[j+1]); } swap(first, second) register long *first, *second; { register long tmp; tmp = *first; *first = *second; *second = tmp; } /* This program takes the previously compiled and linked pieces of the * operating system, and puts them together to build a boot diskette. * The files are read and put on the boot diskette in this order: * * bootblok: the diskette boot program * kernel: the operating system kernel * mm: the memory manager * fs: the file system * init: the system initializer * fsck: the file system checker * * The bootblok file goes in sector 0 of the boot diskette. The operating system * begins directly after it. The kernel, mm, fs, init, and fsck are each * padded out to a multiple of 16 bytes, and then concatenated into a * single file beginning 512 bytes into the file. The first byte of sector 1 * contains executable code for the kernel. There is no header present. * * After the boot image has been built, build goes back and makes several * patches to the image file or diskette: * * 1. The last 4 words of the boot block are set as follows: * Word at 504: Number of sectors to load * Word at 506: DS value for running fsck * Word at 508: PC value for starting fsck * Word at 510: CS value for running fsck * * 2. Build writes a table into the first 8 words of the kernel's * data space. It has 4 entries, the cs and ds values for each * program. The kernel needs this information to run mm, fs, and * init. Build also writes the kernel's DS value into address 4 * of the kernel's TEXT segment, so the kernel can set itself up. * * 3. The origin and size of the init program are patched into bytes 4-9 * of the file system data space. The file system needs this * information, and expects to find it here. * * Build is called by: * * build bootblok kernel mm fs init fsck image * * to get the resulting image onto the file "image". */ #define PROGRAMS 5 /* kernel + mm + fs + init + fsck = 5 */ #define PROG_ORG 1536 /* where does kernel begin in abs mem */ #define DS_OFFSET 4L /* position of DS written in kernel text seg */ #define SECTOR_SIZE 512 /* size of buf */ #define READ_UNIT 512 /* how big a chunk to read in */ #define KERNEL_D_MAGIC 0x526F /* identifies kernel data space */ #define FS_D_MAGIC 0xDADA /* identifies fs data space */ #define CLICK_SHIFT 4 #define KERN 0 #define MM 1 #define FS 2 #define INIT 3 #define FSCK 4 /* Information about the file header. */ #define HEADER1 32 /* short form header size */ #define HEADER2 48 /* long form header size */ #define SEP_POS 1 /* tells where sep I & D bit is */ #define HDR_LEN 2 /* tells where header length is */ #define TEXT_POS 0 /* where is text size in header */ #define DATA_POS 1 /* where is data size in header */ #define BSS_POS 2 /* where is bss size in header */ #define SEP_ID_BIT 0x20 /* bit that tells if file is separate I & D */ #ifdef MSDOS # define BREAD 4 /* value 0 means ASCII read */ #else # define BREAD 0 #endif int image; /* file descriptor used for output file */ int cur_sector; /* which 512-byte sector to be written next */ int buf_bytes; /* # bytes in buf at present */ char buf[SECTOR_SIZE]; /* buffer for output file */ char zero[SECTOR_SIZE]; /* zeros, for writing bss segment */ long cum_size; /* Size of kernel+mm+fs+init */ long all_size; /* Size of all 5 programs */ struct sizes { unsigned text_size; /* size in bytes */ unsigned data_size; /* size in bytes */ unsigned bss_size; /* size in bytes */ int sep_id; /* 1 if separate, 0 if not */ } sizes[PROGRAMS]; char *name[] = {"\nkernel", "mm ", "fs ", "init ", "fsck "}; main(argc, argv) int argc; char *argv[]; { /* Copy the boot block and the 5 programs to the output. */ int i; if (argc != PROGRAMS+3) pexit("seven file names expected. ", ""); IOinit(); /* check for DMAoverrun (DOS) */ create_image(argv[7]); /* create the output file */ /* Go get the boot block and copy it to the output file or diskette. */ copy1(argv[1]); /* Copy the 5 programs to the output file or diskette. */ for (i = 0; i < PROGRAMS; i++) copy2(i, argv[i+2]); flush(); printf(" ----- -----\n"); #ifdef PCIX printf("Operating system size %29ld %5lx\n", cum_size, cum_size); printf("\nTotal size including fsck is %ld.\n", all_size); #else printf("Operating system size %29D %5X\n", cum_size, cum_size); printf("\nTotal size including fsck is %D.\n", all_size); #endif /* Make the three patches to the output file or diskette. */ patch1(all_size); patch2(); patch3(); exit(0); } copy1(file_name) char *file_name; { /* Copy the specified file to the output. The file has no header. All the * bytes are copied, until end-of-file is hit. */ int fd, bytes_read; char inbuf[READ_UNIT]; if ( (fd = open(file_name, BREAD)) < 0) pexit("can't open ",file_name); do { bytes_read = read(fd, inbuf, READ_UNIT); if (bytes_read < 0) pexit("read error on file ", file_name); if (bytes_read > 0) wr_out(inbuf, bytes_read); } while (bytes_read > 0); flush(); close(fd); } copy2(num, file_name) int num; /* which program is this (0 - 4) */ char *file_name; /* file to open */ { /* Open and read a file, copying it to output. First read the header, * to get the text, data, and bss sizes. Also see if it is separate I & D. * write the text, data, and bss to output. The sum of these three pieces * must be padded upwards to a multiple of 16, if need be. The individual * pieces need not be multiples of 16 bytes, except for the text size when * separate I & D is in use. The total size must be less than 64K, even * when separate I & D space is used. */ int fd, sepid, bytes_read, count; unsigned text_bytes, data_bytes, bss_bytes, tot_bytes, rest, filler; unsigned left_to_read; char inbuf[READ_UNIT]; if ( (fd = open(file_name, BREAD)) < 0) pexit("can't open ", file_name); /* Read the header to see how big the segments are. */ read_header(fd, &sepid, &text_bytes, &data_bytes, &bss_bytes, file_name); /* Pad the total size to a 16-byte multiple, if needed. */ if (sepid && ((text_bytes % 16) != 0) ) { pexit("separate I & D but text size not multiple of 16 bytes. File: ", file_name); } tot_bytes = text_bytes + data_bytes + bss_bytes; rest = tot_bytes % 16; filler = (rest > 0 ? 16 - rest : 0); bss_bytes += filler; tot_bytes += filler; if (num < FSCK) cum_size += tot_bytes; all_size += tot_bytes; /* Record the size information in the table. */ sizes[num].text_size = text_bytes; sizes[num].data_size = data_bytes; sizes[num].bss_size = bss_bytes; sizes[num].sep_id = sepid; /* Print a message giving the program name and size, except for fsck. */ if (num < FSCK) { printf("%s text=%5u data=%5u bss=%5u tot=%5u hex=%4x %s\n", name[num], text_bytes, data_bytes, bss_bytes, tot_bytes, tot_bytes, (sizes[num].sep_id ? "Separate I & D" : "")); } /* Read in the text and data segments, and copy them to output. */ left_to_read = text_bytes + data_bytes; while (left_to_read > 0) { count = (left_to_read < READ_UNIT ? left_to_read : READ_UNIT); bytes_read = read(fd, inbuf, count); if (bytes_read < 0) pexit("read error on file ", file_name); if (bytes_read > 0) wr_out(inbuf, bytes_read); left_to_read -= count; } /* Write the bss to output. */ while (bss_bytes > 0) { count = (bss_bytes < SECTOR_SIZE ? bss_bytes : SECTOR_SIZE); wr_out(zero, count); bss_bytes -= count; } close(fd); } read_header(fd, sepid, text_bytes, data_bytes, bss_bytes, gijklmnopqrstfile_name) int fd, *sepid; unsigned *text_bytes, *data_bytes, *bss_bytes; char *file_name; { /* Read the header and check the magic number. The standard Monix header * consists of 8 longs, as follows: * 0: 0x04100301L (combined I & D space) or 0x04200301L (separate I & D) * 1: 0x00000020L (stripped file) or 0x00000030L (unstripped file) * 2: size of text segments in bytes * 3: size of initialized data segment in bytes * 4: size of bss in bytes * 5: 0x00000000L * 6: total memory allocated to program (text, data and stack, combined) * 7: 0x00000000L * The longs are represented low-order byte first and high-order byte last. * The first byte of the header is always 0x01, followed by 0x03. * The header is followed directly by the text and data segments, whose sizes * are given in the header. */ long head[12]; unsigned short hd[4]; int n, header_len; /* Read first 8 bytes of header to get header length. */ if ((n = read(fd, hd, 8)) != 8) pexit("file header too short: ", file_name); header_len = hd[HDR_LEN]; if (header_len != HEADER1 && header_len != HEADER2) pexit("bad header length. File: ", file_name); /* Extract separate I & D bit. */ *sepid = hd[SEP_POS] & SEP_ID_BIT; /* Read the rest of the header and extract the sizes. */ if ((n = read(fd, head, header_len - 8)) != header_len - 8) pexit("header too short: ", file_name); *text_bytes = (unsigned) head[TEXT_POS]; *data_bytes = (unsigned) head[DATA_POS]; *bss_bytes = (unsigned) head[BSS_POS]; } wr_out(buffer, bytes) char buffer[READ_UNIT]; int bytes; { /* Write some bytes to the output file. This procedure must avoid writes * that are not entire 512-byte blocks, because when this program runs on * MS-DOS, the only way it can write the raw diskette is by using the system * calls for raw block I/O. */ int room, count, count1; register char *p, *q; /* Copy the data to the output buffer. */ room = SECTOR_SIZE - buf_bytes; count = (bytes <= room ? bytes : room); count1 = count; p = &buf[buf_bytes]; q = buffer; while (count--) *p++ = *q++; /* See if the buffer is full. */ buf_bytes += count1; if (buf_bytes == SECTOR_SIZE) { /* Write the whole block to the disk. */ write_block(cur_sector, buf); clear_buf(); } /* Is there any more data to copy. */ if (count1 == bytes) return; bytes -= count1; buf_bytes = bytes; p = buf; while (bytes--) *p++ = *q++; } flush() { if (buf_bytes == 0) return; write_block(cur_sector, buf); clear_buf(); } clear_buf() { register char *p; for (p = buf; p < &buf[SECTOR_SIZE]; p++) *p = 0; buf_bytes = 0; cur_sector++; } patch1(all_size) long all_size; { /* Put the ip and cs values for fsck in the last two words of the boot blk. * If fsck is sep I&D we must also provide the ds-value (addr. 506). * Put in bootblok-offset 504 the number of sectors to load. */ long fsck_org; unsigned short ip, cs, ds, ubuf[SECTOR_SIZE/2], sectrs; if (cum_size % 16 != 0) pexit("MINIX is not multiple of 16 bytes", ""); fsck_org = PROG_ORG + cum_size; /* where does fsck begin */ ip = 0; cs = fsck_org >> CLICK_SHIFT; if (sizes[FSCK].sep_id) ds = cs + (sizes[FSCK].text_size >> CLICK_SHIFT); else ds = cs; /* calc nr of sectors to load (starting at 0) */ sectrs = (unsigned) (all_size / 512L); read_block(0, ubuf); /* read in boot block */ ubuf[(SECTOR_SIZE/2) - 4] = sectrs + 1; ubuf[(SECTOR_SIZE/2) - 3] = ds; ubuf[(SECTOR_SIZE/2) - 2] = ip; ubuf[(SECTOR_SIZE/2) - 1] = cs; write_block(0, ubuf); } patch2() { /* This program now has information about the sizes of the kernel, mm, fs, and * init. This information is patched into the kernel as follows. The first 8 * words of the kernel data space are reserved for a table filled in by build. * The first 2 words are for kernel, then 2 words for mm, then 2 for fs, and * finally 2 for init. The first word of each set is the text size in clicks; * the second is the data+bss size in clicks. If separate I & D is NOT in * use, the text size is 0, i.e., the whole thing is data. * * In addition, the DS value the kernel is to use is computed here, and loaded * at location 4 in the kernel's text space. It must go in text space because * when the kernel starts up, only CS is correct. It does not know DS, so it * can't load DS from data space, but it can load DS from text space. */ int i, j; unsigned short t, d, b, text_clicks, data_clicks, ds; long data_offset; /* See if the magic number is where it should be in the kernel. */ data_offset = 512L + (long)sizes[KERN].text_size; /* start of kernel data */ i = (get_byte(data_offset+1L) << 8) + get_byte(data_offset); if (i != KERNEL_D_MAGIC) { pexit("kernel data space: no magic #",""); } for (i = 0; i < PROGRAMS - 1; i++) { t = sizes[i].text_size; d = sizes[i].data_size; b = sizes[i].bss_size; if (sizes[i].sep_id) { text_clicks = t >> CLICK_SHIFT; data_clicks = (d + b) >> CLICK_SHIFT; } else { text_clicks = 0; data_clicks = (t + d + b) >> CLICK_SHIFT; } put_byte(data_offset + 4*i + 0L, (text_clicks>>0) & 0377); put_byte(data_offset + 4*i + 1L, (text_clicks>>8) & 0377); put_byte(data_offset + 4*i + 2L, (data_clicks>>0) & 0377); put_byte(data_offset + 4*i + 3L, (data_clicks>>8) & 0377); } /* Now write the DS value into word 4 of the kernel text space. */ if (sizes[KERN].sep_id == 0) ds = PROG_ORG >> CLICK_SHIFT; /* combined I & D space */ else ds = (PROG_ORG + sizes[KERN].text_size) >> CLICK_SHIFT; /* separate */ put_byte(512L + DS_OFFSET, ds & 0377); put_byte(512L + DS_OFFSET + 1L, (ds>>8) & 0377); } patch3() { /* Write the origin and text and data sizes of the init program in FS's data * space. The file system expects to find these 3 words there. */ unsigned short init_text_size, init_data_size, init_buf[SECTOR_SIZE/2], i; unsigned short w0, w1, w2; int b0, b1, b2, b3, b4, b5, mag; long init_org, fs_org, fbase, mm_data; init_org = PROG_ORG; init_org += sizes[KERN].text_size+sizes[KERN].data_size+sizes[KERN].bss_size; mm_data = init_org - PROG_ORG +512L; /* offset of mm in file */ mm_data += (long) sizes[MM].text_size; init_org += sizes[MM].text_size + sizes[MM].data_size + sizes[MM].bss_size; fs_org = init_org - PROG_ORG + 512L; /* offset of fs-text into file */ fs_org += (long) sizes[FS].text_size; init_org += sizes[FS].text_size + sizes[FS].data_size + sizes[FS].bss_size; init_text_size = sizes[INIT].text_size; init_data_size = sizes[INIT].data_size + sizes[INIT].bss_size; init_org = init_org >> CLICK_SHIFT; /* convert to clicks */ if (sizes[INIT].sep_id == 0) { init_data_size += init_text_size; init_text_size = 0; } init_text_size = init_text_size >> CLICK_SHIFT; init_data_size = init_data_size >> CLICK_SHIFT; w0 = (unsigned short) init_org; w1 = init_text_size; w2 = init_data_size; b0 = w0 & 0377; b1 = (w0 >> 8) & 0377; b2 = w1 & 0377; b3 = (w1 >> 8) & 0377; b4 = w2 & 0377; b5 = (w2 >> 8) & 0377; /* Check for appropriate magic numbers. */ fbase = fs_org; mag = (get_byte(mm_data+1L) << 8) + get_byte(mm_data+0L); if (mag != FS_D_MAGIC) pexit("mm data space: no magic #",""); mag = (get_byte(fbase+1L) << 8) + get_byte(fbase+0L); if (mag != FS_D_MAGIC) pexit("fs data space: no magic #",""); put_byte(fbase+4L, b0); put_byte(fbase+5L, b1); put_byte(fbase+6L, b2); put_byte(fbase+7L, b3); put_byte(fbase+8L ,b4); put_byte(fbase+9L, b5); } int get_byte(offset) long offset; { /* Fetch one byte from the output file. */ char buff[SECTOR_SIZE]; read_block( (unsigned) (offset / SECTOR_SIZE), buff); return(buff[(unsigned) (offset % SECTOR_SIZE)] & 0377); } put_byte(offset, byte_value) long offset; int byte_value; { /* Write one byte into the output file. This is not very efficient, but * since it is only called to write a few words it is just simpler. */ char buff[SECTOR_SIZE]; read_block( (unsigned) (offset/SECTOR_SIZE), buff); buff[(unsigned) (offset % SECTOR_SIZE)] = byte_value; write_block( (unsigned)(offset/SECTOR_SIZE), buff); } pexit(s1, s2) char *s1, *s2; { printf("Build: %s%s\n", s1, s2); exit(1); } /*=========================================================================== * The following code is only used in the UNIX version of this program. *===========================================================================*/ #ifndef MSDOS create_image(f) char *f; { /* Create the output file. */ image = creat(f, 0666); close(image); image = open(f, 2); } read_block(blk, buff) int blk; char buff[SECTOR_SIZE]; { lseek(image, (long)SECTOR_SIZE * (long) blk, 0); if (read(image, buff, SECTOR_SIZE) != SECTOR_SIZE) pexit("block read error", ""); } write_block(blk, buff) int blk; char buff[SECTOR_SIZE]; { lseek(image, (long)SECTOR_SIZE * (long) blk, 0); if (write(image, buff, SECTOR_SIZE) != SECTOR_SIZE) pexit("block write error", ""); } IOinit() {} /* dummy */ #else /*MSDOS*/ /*=========================================================================== * This is the raw diskette I/O for MSDOS. It uses diskio.asm or biosio.asm *==========================================================================*/ #define MAX_RETRIES 5 char *buff; char buff1[SECTOR_SIZE]; char buff2[SECTOR_SIZE]; int drive; IOinit() /* check if no DMAoverrun & assign the buffer */ { if (DMAoverrun(buff1)) buff = buff2; else buff = buff1; } read_block (blocknr,user) int blocknr; char user[SECTOR_SIZE]; { /* read the requested MINIX-block in core */ int retries,err,i; char *p; retries = MAX_RETRIES; do err = absread (drive, blocknr, buff); while (err && --retries); if (!retries) dexit ("reading",drive,blocknr,err); p=buff; i=SECTOR_SIZE; while (i--) *(user++) = *(p++); } write_block (blocknr,user) int blocknr; char user[SECTOR_SIZE]; { /* write the requested MINIX-block to disk */ int retries,err,i; char *p; p=buff; i=SECTOR_SIZE; while (i--) *(p++) = *(user++); retries = MAX_RETRIES; do err = abswrite (drive, blocknr, buff); while (err && --retries); if (!retries) dexit ("writing",drive,blocknr,err); } dexit (s,drive,sectnum,err) int sectnum, err,drive; char *s; { extern char *derrtab[]; printf ("Error %s drive %c, sector: %d, code: %d, %s\n", s, drive+'A',sectnum, err, derrtab[err] ); exit (2); } create_image (s) char *s; { char kbstr[10]; if (s[1] != ':') pexit ("wrong drive name (dos): ",s); drive = (s[0] & ~32) - 'A'; if (drive<0 || drive>32) pexit ("no such drive: ",s); printf("Put a blank, formatted diskette in drive %s\nHit return when ready",s); gets (kbstr,10); puts(""); } char *derrtab[14] = { "no error", "disk is read-only", "unknown unit", "device not ready", "bad command", "data error", "internal error: bad request structure length", "seek error", "unknown media type", "sector not found", "printer out of paper (??)", "write fault", "read error", "general error" }; #endif /*MSDOS*/ /* This process is the father (mother) of all MINIX user processes. When * MINIX comes up, this is process 2. It executes the /etc/rc shell file and * then reads the /ect/ttys file to find out which terminals need a login * process. */ #include "../h/signal.h" #define PIDSLOTS 10 #define STACKSIZE 256 #define DIGIT 8 char name[] = {"/dev/tty?"}; /* terminal names */ int pid[PIDSLOTS]; /* pids of init's own children */ int pidct; extern int errno; char stack[STACKSIZE]; char *stackpt = &stack[STACKSIZE]; main() { char line[10]; /* /etc/ttys lines are supposed to be 3 chars */ int rc, tty, k, status, ttynr, ct, i; /* Carry out /etc/rc. */ sync(); /* force buffers out onto RAM disk */ if (fork()) { /* Parent just waits. */ wait(&k); } else { /* Child exec's the shell to do the work. */ if (open("/etc/rc", 0) < 0) exit(-1); open("/dev/tty0", 1); /* std output */ open("/dev/tty0", 1); /* std error */ execn("/bin/sh"); exit(-2); /* impossible */ } /* Read the /etc/ttys file and fork off login processes. */ if ( (tty = open("/etc/ttys", 0)) == 0) { /* Process /etc/ttys file. */ while ( (ct = getline(line)) > 1) { if (ct != 4) continue; if (line[0] != '1') continue; ttynr = line[2] - '0'; if (ttynr < 0 || ttynr >= PIDSLOTS) continue; startup(ttynr); } } else { tty = open("/dev/tty0", 1); write(tty, "Init can't open /etc/ttys\n", 26); while (1) ; /* just hang -- system cannot be started */ } close(tty); /* All the children have been forked off. Wait for someone to terminate. * Note that it might be a child, in which case a new login process must be * spawned off, or it might be somebody's orphan, in which case ignore it. * First ignore all signals. */ for (i = 1; i <= NR_SIGS; i++) signal(i, SIG_IGN); while (1) { k = wait(&status); pidct--; /* Search to see which line terminated. */ for (i = 0; i < PIDSLOTS; i++) if (pid[i] == k) startup(i); } } startup(linenr) int linenr; { /* Fork off a process for the indicated line. */ int k; if ( (k = fork()) != 0) { /* Parent */ pid[linenr] = k; pidct++; } else { /* Child */ close(0); /* /etc/ttys may be open */ name[DIGIT] = '0' + linenr; if (open(name, 0) != 0) exit(-3); /* standard input */ if (open(name, 1) != 1) exit(-3); /* standard output */ if (open(name, 1) != 2) exit(-3); /* standard error */ execn("/usr/bin/login"); execn("/bin/login"); execn("/bin/sh"); /* last resort, if mount of /usr failed */ execn("/usr/bin/sh"); /* last resort, if mount of /usr failed */ return; /* impossible */ } } int getline(buf) char *buf; { /* Read a line from standard input. */ char *p; p = buf; while (1) { if (read(0, p, 1) <= 0) return(0); if (*p == '\n') { p++; *p = 0; return(p - buf); /* count of chars read */ } else { p++; } } } : Increase default stack size from 2K. b=../commands/bin t=../test chmem =30000 $b/asld chmem =2000 $b/cc chmem =52000 $b/cem chmem =30000 $b/cg chmem =32000 $b/cpdir chmem =40000 $b/cpp chmem =40000 $b/dd chmem =50000 $b/diff chmem =8000 $b/df chmem =32000 $b/dosread chmem =50000 $b/find chmem =50000 $b/fix chmem =8000 $b/grep chmem =8000 $b/gres chmem =64000 $b/libpack chmem =64000 $b/libupack chmem =20000 $b/make chmem =64000 $b/mined chmem =8000 $b/mkdir chmem =16000 $b/mkfs chmem =8000 $b/mv chmem =20000 $b/opt chmem =8000 $b/pr chmem =50000 $b/readfs chmem =8000 $b/rm chmem =8000 $b/rmdir chmem =8000 $b/sh chmem =30000 $b/sort chmem =2000 $b/tail chmem =2000 $b/time chmem =8000 $t/t10a chmem =8000 $t/t11a chmem =8000 $t/t11b for i in 1 2 3 4 5 6 7 8 9 10 do chmem =8000 ../test/test$i done ¸ŔŽŘ3ö¸ŕ/ŽŔ3˙šóĽęŕ/ŒĘŽÚ3ŔŽŔŽŇź¸;&Łx&‰z¸Í¸3Ű3ŇÍťgčŇ3ŔÍ3ŔŽŔ¸ťšşÍsÇ. 3ŔŽŔ¸0&ŁxÍčC‹,ĂŃăŃăŃăŃăŃăŽĂ3Ű,´ÍrsĄ,;řrÔşň¸ îú‹.ĄúŽŘŽŔŽĐ.˙.ü‹6.Ą,3Ň÷ö‹Č‹ÚĄ,ĆH3Ň÷6.:Át+ňNĄ,‹ĐÖJŃŕŃâ:ćtĐę2ö+ňN‹Ć3Ҋń€ćŠéĐíŠËţÁ2ŇĂPťFč 3É÷&âúÍŠ„ŔuĂ´CSł2˙Í[éë˙ß *˙Pöß˙TöRead error. Automatic reboot. Booting MINIX 1.2. Copyright 1987 Prentice-Hall, Inc.  P|ÚéúŒČŽŘĄŽŘŽĐ‰ dźşdÄč7éý˙苋.žd˙ś˙v˙6œd˙śčů6éĎčoč›éĆčfč)Cé˝č]Ǥd¸˘dP¸ű˙PčÚ5éŚčFǤd¸˘dP¸ú˙PčĂ5éč/Ǥd¸˘dP¸ý˙PčŹ5éxčč°éoččÓéfčč é]Ž2P4P‰0P‹ždƒĂ‡‡‡ Œ—‰§‹ăŒŰŽÓ˙62PŽĂUWVRQ˙60PPźşdÄÇňaşdňaĄ4P˙ŕ>œdüt<ú‹&ždX[YZ^_‰6P‹Ü‹Ż&‰.ňa‹Ż‰.8P]‹§ Ž—˙ˇ˙ˇ˙ˇ Ĺ6PĎű›éü˙¸ čDDčDÇFř`Ą P"P‰Fú‹FřFú‰FöżşeéU+ö‹ĆšÓŕ‹ÖŃâ׋ډFƒţ |é‹Ç-şe™šV÷ů-‹đ˙jhs D šÓŕĘm븉E‹E‰E2ƒ}2tm2řD‹ŘŃ㋇Řa‰Eƒ}u…ö|Wč8ƒÄÇEÇE…ö}:ÇE$ ™‹Fř‰E"ÇE* ™‹Fř P‰E(ÇE0 ™‹Fř P"P‰E.Ą P"P‰E,逍DşV÷ę‹Ř‹‡če‰Fô‹ĆŃŕ‹ŘŃ㋇ P‰E$…öu‹Föë‹Fô‰E"‹ĆŃŕ‹ŘŃ㋇ P‰E*‹ĆŃŕ‹ŘŃ㋇ PE"‰E(‹ĆŃŕ‹ŘŃ㋇ P‰E,‹ĆŃŕ‹ŘŃ㋇ PE(‰E.‹E"‰E‹E(‰E‹E(‰E‹E(‰EƒÇV˙iwé˘ţÇ*hşd*hÇFhşdƒFhżliëÇEƒÇV˙ĘmrňčÍBŁĘt¸P¸˙˙Pč˜CƒÄ‹đţüuÇĚt¸P¸bP¸P¸hPč+2ƒÄ‰Fđ‰Vň+ҸRP˙vň˙vđ+ŔRPčAƒÄ +ö˙vř¸—PVčƒÄFƒţ|ěž˙vř¸ PVčŤƒÄFţ|ë˙vř¸ŠP+ŔPč”ƒÄ˙vř¸$P¸ PčƒƒÄ˙vř¸€P¸PčrƒÄ˙vř¸@P¸ PčaƒÄ˙vř¸RP¸PčPƒÄ˙vř¸IP¸Pč?ƒÄƒ>Ětt ˙vř¸iP¸vë ˙vř¸iP¸ PčƒÄ+ŔP¸şeP¸Pč ƒÄÇÎthčU5+ŔP¸!PčAƒÄ+ŔP¸ĄPčř@ƒÄčĹüéƒA+ŔčPA¸JPPčFƒÄ‹žd‹G*šÓŕP˙w¸hPPčsFƒÄéWA+Ŕč$A¸‹PPčaFƒÄ¸ŤPPčWFƒÄ¸ÖPPčMFƒÄ‹žd‹G*šÓŕP˙w¸QPč3FƒÄéA+Ŕčä@¸ƒÄ éA@¸č @čĚë<Ńŕ“˙§XFäPčqƒÄë)FäPWč5ëFäPWčˆëFäPWč ëFäPWč) ƒÄFäP¸tPčîHƒÄ‹F躂÷ę´Q‹ř‹Fć=vĄ+Ň+ŔRP+ŇRP¸ę˙P˙vę˙vä¸DPčL ƒÄ뽸č‚?čA?‹^‹G‰FđÇFîXU‹ŘŠ˜‰Fř‰Fö‹FřŔ‰FřƒFđë‹^đŠ˜‹^îˆ˙Fđ˙Fî‹Fř˙Nř…Ŕĺ‹^‹G‰Fđ‹ŘĆčő>ÇFîXU開^Fí˙Fî‹^‰Fř˙FîŠFí˜P˙vř脃Ä‹Fřş‚÷ę´Q‰Fę‹Řƒżr~Z‹Ř‹‡\%"‰FúƒżÎ …ŔtCƒżĚ~<˙vęč†ƒÄ‰Fú‹^ꊇn˜‰FôЇo˜‰Fň+Ň+ŔRP+ŇRP˙vú˙vň˙vô¸CPčP ƒÄ‹Fö˙Nö…Ŕ~é]˙éŹ>¸čx>‹Fş‚÷ę´Q‹ř€~;}éĹ€~D~韊F˜PčéŤƒ~útéŠF˜Š•gšÓâÓú;Âu2€˝cu+Wč)ƒÄ=˙˙ué¸PWčéƒÄ¸ PWčŢƒÄ¸éáŠF˜Š•hšÓâÓú;Âu%€˝cuWčäƒÄ…ŔtőŠ…h˜PWčŚƒÄ¸ 銀˝cu'€~\uƅc鐊F˜Š•mšÓâÓú;ÂuaĆFë[ƅcŠF˜Š•gšÓâÓú;ÂtCŠF˜Š•hšÓâÓú;Ât0ŠF˜Š•mšÓâÓú;Ât‹ČĆ\˙…Č˙…̍…Č9…Ču‰˝Č€~ u ÷…\tĆF ŠF˜Š•išÓâÓú;ÂtŠF˜Š•jšÓâÓú;Âu,ŠF˜Š•išÓâÓú;Âu¸ë¸‰FřP˙vWčŕƒÄéĊF˜Š•lšÓâÓú;Âuƅd驊F˜Š•kšÓâÓú;Âu[ƅdW˙•ZƒÄ醁˝ĚČ}~‹…\%"‰Fú€˝etŠF˜PčhƒÄˆFë ƒ~ú t€f€~tMƒ~úué ţƒ~úuéţ€~ t€~u˙…΋ČŠFˆ˙…ȍ…Č9…Ču‰˝Č˙…ĚŠF˜PWčďƒÄéB<¸č<ŠF˜%‰FúŠF˜Š€t+Ŕ븉Fřƒ>ętumƒ>xVuƒ>zVt ‹^úЇÜVë‹^úЇˆV˜‰Föƒ>€Vtƒ~ú} ‹^úЇÜV˜‰Föƒ~úF铃>~Vu鉃>xVuƒ>zVt ‹^úЇˆVën‹^úЇÜVëeƒ>xVuƒ>zVt ‹^úЇ˜Wë‹^úЇ0W˜‰Föƒ>€Vtƒ~ú} ‹^úЇÜV˜‰Föƒ~úF~)ƒ>~Vt"ƒ>xVuƒ>zVt ‹^úЇ0Wë‹^úЇ˜W˜‰Föfö˙~ö€|~ö†|^ƒ>|Vt"ƒ~öA| ƒ~öZƒFö ëƒ~öa| ƒ~özƒnö ƒ>‚VtNö€ƒ>€Vtföƒ~öuÇFöƒ~řuÇFö‹Fö˜éŃ:‹Fö-€=w Ńŕ“˙§ X‹FřŁxV+Ŕëá‹FřŁzVëô‹FřŁ€Vëě‹FřŁ‚Vëäƒ~řtƒ>„Vt ¸+|VŁ|V¸+FřŁ„Vëƒ~řtƒ>†Vt ¸+~VŁ~V¸+FřنVë +Ŕč&:‹ž÷…\t€~t ŠF˜PWčđƒÄWč ƒÄé,:¸čř9‹žƒ˝Ěu¸˙˙ë.9˝Čt ‹…Č-덅ljFú‹Ř€? tދ؀? t׉…Č˙Ě+Ŕéĺ9¸čą9‹žƒ˝r~+Ň+ŔRP+ŇRP¸ý˙P‹^˙wë@‹^‹ˆ…n‹Gˆ…o‹G‰…p‹G‰…rWč0ƒÄ‰FúŠ…o˜‰Fř+Ň+ŔRP+ŇRP˙vú˙vř‹^˙7¸DPčƒÄél9¸ č89‹ž÷…\"t+Ŕ븉Fúƒ˝Ět …Ŕtƒ˝Îu¸üë…ŔuB¸ö˙é/9Š…o˜şV÷ęşe‰F܋…p‰F싅r‰FęP˙vě¸P˙vÜč—(ƒÄ‰Fć‰Vč…Ňtş¸P¸xUP¸P¸fPčw(ƒÄ‰Fâ‰VäÇFňÇFđÇFré؋…r;…Ě}‹…rë‹…̉Fô=|¸‰FôÇFřÇFŢxU‹Fô˙Nô…Ŕ~Q‹ĘŠˆFá˙…ʍ…Č9…Ęu‰˝Ę‹^ފFáˆ˙FŢ˙Fř€~á t€~áuÁ˙Îƒ~út €~áu˙Fî˙Fđƒ~útĽƒ~ît‹Fř-ë‹Fř‰Fö™RP˙vč˙vć˙vä˙vâčŸ6ƒÄ ‹Fö™FćVčFň‹Fř)…r)…Ěƒ˝Ět ƒ~đué˙Džr‹Fňé¨ţ¸čŚ7‹žDžPDž|€˝ft2Š…t˜‰FúŠ…u˜‰Fř+Ň+ŔRP+ŇRP˙v˙vř˙vú¸DPč$ƒÄƅféˆ7¸čT7‹ž‹^‹ˆ…t‹Gˆ…u‹G‰…v‹G‰…|ƅfDž~Š…u˜şV÷ęşe‰Fö‹…v‰Fú‹…|‰FřP˙vú¸P˙vöč˝&ƒÄ‰…x‰•z…Ňu…Ŕu Dž~ö˙Dž|W˙•ZƒÄéü6¸&čČ6‹žÇFÖÇFřÇFúÇFôÇFö‹^‹G-t= véíŃŕ“˙§X‹^‹W ‹G šŃúŃŘâú*ä+҈…g‹^‹W ‹G +ÉëŃúŃŘâú*ä+҈…h‹^‹W‹G‰…\˙vö˙vô˙vú˙vř˙v֋^˙w˙7¸DPčňƒÄé[6‹^‹W ‹G šŃúŃŘâú*ä+҈…i‹^‹W ‹G šŃúŃŘâú*ä+҈…j‹^‹W ‹G šŃúŃŘâú*ä+҈…k‹^‹W ‹G +ÉëŃúŃŘâú*ä+҈…l‹^‹W‹GšŃúŃŘâú*ä+҈…méV˙‹…g˜™*ä+҉Fđ‰Vň‹…h˜™*ä+҉Fě‰Vî‹Vň‹FđšŃŕŃŇâú Fě Vî‰Fô‰Vö‹…\™‰Fř‰Vúé ˙‹…i˜™*ä+҉Fč‰Vꋅj˜™*ä+҉Fä‰V担k˜™*ä+҉Fŕ‰V⋅l˜™*ä+҉F܉Vދ…m˜™*ä+҉F؉VڋVę‹FčšŃŕŃŇâú‹vć‹^äšŃăŃÖâú à ֋vâ‹^ŕšŃăŃÖâú à ֋vދ^Ü+ÉëŃăŃÖâú à ։Fô‰Vö‹VڋFŘšŃŕŃŇâúéF˙ÇFÖę˙éTţ+Ŕč 4‹žƒ˝ruƒ˝|tJ‰˝Č‰˝ĘDžĚDžÎDžrDž|ƅfƅd+Ň+ŔRP+ŇRP¸ü˙P‹^˙w˙7¸DPčƒÄéo4¸č;4‹F‰Fć‹F‰Fč‹F ‰Fę‹V‹F ‰Fň‰Vô‹V‹F‰Fî‰VđFäP˙vč/=ƒÄé/4+Ŕčü3‹žƅd¸ü˙PWč?üƒÄ‰˝Č‰˝ĘDžĚDžÎ˙v‹FPčŃ"ƒÄéď3¸ čť3FřP¸`Pč\3ƒÄFúP¸aPčN3ƒÄ‹Fú €P¸aPč+3ƒÄ˙vú¸aPč3ƒÄ‹Fř-€‰Fö…Ŕ~K=t[=*tV=6tQ=8tL=:tG=Euë@ƒ>€Vt9ƒ~řu3ŠFó˜ş;Âu(ĆU¸ PPčÉ2ƒÄéW3ĄU% ‰Fô  UˆFóƒ~ôtŔƒ>€Vtƒ>‚Vt ¸S9Fřuč4 6U˜‰FöŠ7UšÓâÓú;Â}ŽŔ‰Fö‹Ř‹Fřˆ‡8UƇ9Uţ6UÇŇtÇât6U¸ĐtP¸ů˙PčU#놸 čŻ2‹ž‹•z‹…xšŃúŃŘâú+҉Fö‹•z‹…x%+҉Fô‰Fň‰Vúë)€˝du)˙vô˙vöč{3ƒÄˆFůŠFů˜PWčCƒÄ˙Fô˙|ƒ˝|ĐWčԃċFô+Fň‰Fú™…x•z…~ƒ˝|u ˙ľ~WčuúƒÄéI2+Ŕč2‹ž€˝Vté֊Fˆ…WƅVéĊF˜PŠ…W˜PWč-ƒÄƅVéŞŃŕ“˙§4XWč_ƒÄ¸3PčƒÄ鏋…`@P˙ľ^WčƒÄë|˙ľ`‹…^@Pëë˙ľ`‹…^Hëň÷…\t ¸ PWčo˙ƒÄƒ˝`u +ŔPW蘃Äë˙`˙ľ`ëŹ˙ľ`+Ŕ뺋…\% = u!¸ PWč3˙ƒÄ÷…^tëëWčȃÄƅVé`1€˝Vué/˙ŠF˜-=wé:˙ƒ˝^P}݁˝P@uW葃ÄŠF˜ …X•Đ‹PŃăӋډ˙…P˙…^돸čŰ0‹žƒ~u¸ ë¸`˙‰Fú‹…RFú#čt‰…Rƒ~u ‹…R#čtë‹…R‰Fř¸PP˙vř˙60X+ŔPč1ƒÄ‹…RŃřP¸ PčjƒÄéŁ0+Ŕčp0‹žƒ˝Pt<˙ľP˙ľT˙60X…ĐPčŐ0ƒÄ‹…PŃŕ…T‰…T‹…TŃřP¸Pč!ƒÄDžPéT0+Ŕč!0˙včŚ˙ƒÄƒ~|Rƒ~P}Lƒ~|Fƒ~}@‹^‹F‰‡^‹F‰‡`¸+FŃŕşP÷ꋗR‹VŃ≇T‹‡TŃřP¸P貃Äéë/¸čˇ/‹ž€~zuŠF˜šÓŕ‰…X鉀~~ul€~0uS‹…`@ş ÷ꋕ^Ńâ+‰Fú‹…T‰Föƒ~ú~[‹Fú;.X|Ą.X‰Fř™š÷ůP˙vö˙60X+ŔPčĐ/ƒÄ‹FřFö)Fúëɀ~1u$¸PWčOţƒÄëŠF˜- PŠF˜- PWčńţƒÄé?/+Ŕč /˙vĄ2XPč™.ƒÄ‹FšÓř*äPĄ2XPč.ƒÄ‹F@PĄ2XPčo.ƒÄ‹F*äPĄ2XPč\.ƒÄéę.¸čś.ču.¸śP¸CPčB.ƒÄ‹F*äP¸BPč2.ƒÄ‹FšÓř*äP¸BPč.ƒÄFúP¸aPč!.ƒÄ‹Fú P¸aPčţ-ƒÄÇFřë˙Fř~ř |ö˙vú¸aPčŕ-ƒÄč .ék.¸č7.¸P¸ÄPčĆ-ƒÄ¸P¸ĹPč¸-ƒÄż´Që;‰˝Č‰˝ĘDž\ DžZíƅgƅh@ƅiƅjƅkƅlƅmÇ‚˙6UrżĆUƒ>ĘttÇ0X¸Çčt˙?Ç2XĐÇ.XëÇ0X°Çčt˙Ç2X°Ç.XpÇ UĆ7U¸P¸ PčpţƒÄ+ŔP¸ PčcţƒÄ+ŔPP¸´QPč@ýƒÄƒ> d uÇęté-+ŔčN-ŠF˜P¸´QPč'űƒÄéj-+Ŕč7-€~;učŞ.€~˘X}˙6˘X¸"YPčüëƒÄĄ˘X‰FřĄ¨X‰FöĄ¤X=u ¸˘XPčƒÄ‰Fú뛸č,‹^‹G‰Fř…Ŕ|=|¸ű˙éö‹Fřş÷ę^X‹ř‹Fř‰E‹^‹G‰+ҸRP˙w ˙w čô5…ŇtéÁ…Ŕtéş+ҸRP‹^˙w ˙w č“5‰Fň‰Vô…Ň| =` r¸˜˙铊E˜Ł X‹ŘŃ㋇ňXŃŕ™RP˙vô˙vňč_5‰E‹ XŃ㋇ňX™RP˙vô˙vňč†5‹ŘЇĘX˜‰E ‹ XŃ㋇ňXŃŕ™RP˙vô˙vňčd5‰Fđ‹ XŃ㋇ňX‰Fî‹Fđ™‹Nî÷ů‰E ‹^‹G‰E‹G‰E‹G‰E}t¸ę˙éŞ+ÇFöƒ~öy˙Fö‹Fö™š÷ů…ŇuĄ X@™š÷ů‰ X‹ÂˆEÇœX‹ XŃ㋇ţX™9Vô|ż9Fňsşƒ>œXtčRWč`ƒÄWč´ƒÄWčcƒÄ‰Fú…Ŕu”WčDƒÄ‰Fú…Ŕt=ű˙uÇ˜X ¸ÂP¸´Pč˝ƒÄƒ~úu ƒ}~ÇžXƒ~útéNţ¸éD˙¸č˝*‹^ƒ?u¸Fë¸J‰Fú‹^‹G‰Fě‹G‰FęP˙vě¸P‹GşV÷ęşePčFƒÄ‰Fć‰Vč+ÉëŃúŃŘâú*ä‰Fř‹Vč‹FćšŃúŃŘâú*ä‰Fö‹Vč‹FćšŃúŃŘâú*ä‰Fô‹FęH+ÉÓč*ä‰Fň‹FęHšÓč*ä‰Fđƒ~čuƒ~ću ˙vě¸>YPčSéƒÄ‹Fę+ŇFćVč-ƒÚšŃúŃŘâú*ä+҉Fî;Fôt ˙vô¸bYPč éƒÄč™)˙vú¸ Pčg)ƒÄ˙vú¸ PčZ)ƒÄ˙vř¸PčM)ƒÄ˙vö¸Pč@)ƒÄ˙vô¸Pč3)ƒÄ˙vň¸Pč&)ƒÄ˙vđ¸Pč)ƒÄčB)¸P¸ Pč)ƒÄé–)¸čb)č!)‹^‹Gş‹ČÓâ‰Vú‹Â G٘XĄ–X…šXtĄšX ˜XĄ–X#Fú‰Fř˙6˜X¸ňPčˇ(ƒÄĄ˜XŁ–X‹FúٚXčÔ(ƒ~řu"¸Ť!P‹ XŃă˙ˇYčĘƒÄ¸˘XP¸ý˙Pč2ƒÄé)+ŔčŰ(Ą˜X%đ‹–Xâđ;Ât˙6˜X¸ňPčX(ƒÄĄ˜XŁ–Xéŕ(¸čŹ(‹^€uSčEƒÄ…Ŕt ¸˙˙ë+Ŕéź(‹^‹G;Gtđ¸Pčԃċ^‹G šÓŕ GPčżƒÄ‹ XŃ㋇ Y‰Fř‹^‹G÷nřPč˘ƒÄƒ>œXu¨¸˘XP¸˙˙Pčc1ƒÄ¸PčƒƒÄ˙včđƒÄ‰Fú‹^ŠG˜%ř= tÇFú˙˙‹ XŃ㋇ Y‰Fř‹^‹G÷nřŠWšÓâÓú;ĐtÇFú˙˙ƒ~út˙včyƒÄ…Ŕté1˙‹Fúé2˙¸č˝'‹ž€}u¸ţ˙éNjE‹–X‹ČÓú÷Âtćƒ>Ětt‹ XŃă˙ˇćX¸÷Pč'ƒÄƒ=u¸ćë¸Ĺ‰FöPčƒċE šÓŕ EPč°ƒÄ˙uč§ƒÄ˙u čžƒÄ˙u č•ƒÄ žX˜PčŠƒÄ‹ XŃă˙ˇňXčzƒÄ‹ XŃă˙ˇÚXčjƒÄ¸˙Pč`ƒÄƒ>œXtéH˙‹Fúë˙u¸„YPč0,ƒÄ¸ű˙é'¸˘XP¸˙˙Pč0ƒÄW蟃ĉFú…ŔůE˜Šu ŠE˜ŠtĆEŠE˜Šu˛ŠE˜ŠřtééţŠE˜ŠUšÓâÓú ÂtéÔţ‹ XŃ㋇ňX‰FôŠE˜+EŃŕ÷nô‰Fř‹ XŃ㋇ňX‰FôŠE˜+E ÷nôFřŠE˜+E Fř‹Fřš Óŕ;Eté„ţ+ŔéL˙¸č,&‹žÇFúëgÇFôÇFřë+Ŕëf˙Fřƒ~řd}FöP¸ôPčŠ%ƒÄ÷Fö€tâÇFôƒ~ôt:÷FötĚ÷Fö@t,FöP¸őPč{%ƒÄ‹Fö*äUVƒ„…†‡ˆ‰Š‹ŒŽ‘’“”ú‹Úˆ˙Fúƒ~ú|“ÇœX¸ý˙éÖ%¸č˘%ƒ>œXu>ÇFúd‹Fú˙Nú…Ŕ~)FřP¸ôPč-%ƒÄfřŔ~ř€uÜ˙v¸őPč%ƒÄëÇœXéˆ%¸čT%‹žWčäűƒÄ¸Pčš˙ƒÄ˙uč‘˙ƒÄƒ>œXt¸˙˙ë ÇœXĆE¸ü˙éH%¸˘XP¸˙˙Pč=.ƒÄ¸Pč]˙ƒÄWčĚţƒÄ‰FúÇE˙˙…ŔuŊE˜%ř= uš€}ułĆE+Ŕ븸čĎ$ÇœXčˆ$Ç–XǘX+ŔP¸ňPčJ$ƒÄ¸ P¸ňPč<$ƒÄče$¸˘XP¸˙˙Pčż-ƒÄż^XĆE¸PčŘţƒÄWčGţƒÄ‰FřŠE˜*ä‰Fö¸PčťţƒÄ¸ßPčąţƒÄ¸Pč§ţƒÄÇFúë‹Fúş÷ę‹ŘƇxX˙Fúƒ~ú|čéX$+Ŕč%$ǤXÇŚXű˙‹F™ŁŹX‰ŽX‹FٰX¸˘XP¸ý˙Pč1-ƒÄé%$+Ŕčň#ǤX˙¸˘XP¸ű˙Pč -ƒÄé $¸čÔ#č5ë=t>ÇFúę˙ëD˙6ňZ¸._Pčü(ƒÄ¸ňZP¸tPčŘ,ƒÄƒ>ňZ|ÝĄňZ‰FřĄřZ‰FöĄôZ=u˝¸ňZPč$ƒÄ‰FúÇôZD‹FöŁöZ‹FúŁřZ¸ňZP˙vřč‹,늸 č[#ÇFö‹^‹G‰Fř…Ŕ|= | ¸ű˙ëg¸ę˙ëb‹^uń‹FřšÓŕŽY‹ř‹G‰+ҸRP˙w ˙w č¸,…Ňu˅ŔuÇ+ҸRP‹^˙w ˙w č],‰Fň‰VôƒŇ;U| ;Ev¸˜˙é#‹Vô‹FňEU‰Fň‰Vô‹E ş÷ę™RP˙vô˙vňč,‰E+ҸRP˙vô˙vňčF,‰E+ҸRP‹E ş÷ę™RP˙vô˙vňč(,RPčă+‰E ‹^‹G‰E‹G‰E‹G‰Eƒ~ö+˙Föƒ~ö|é ˙ƒ>îZtčŐWč ƒÄWčUƒÄ‰Fú…Ŕuσ~útéăţ¸éI˙¸č"‹^ƒ?u¸Gë¸K‰Fú‹^‹G‰Fě‹G‰FęP˙vě¸P‹GşV÷ęşePč¤ƒÄ‰Fć‰Vč*ä‰Fř‹FćšŃúŃŘâú*ä‰Fö‹Vč‹FćšŃúŃŘâú*ä‰Fô‹FęH*ä‰Fň‹FęHšÓč*ä‰Fđƒ~čuƒ~ću ˙vě¸S_PčÂŕƒÄ‹Fę+ŇFćVč-ƒÚšŃúŃŘâú*ä+҉Fî;Fôt ˙vô¸{_PčŕƒÄč!˙vú¸ PčÖ ƒÄ˙vú¸ PčÉ ƒÄ˙vř¸Pčź ƒÄ˙vö¸PčŻ ƒÄ˙vô¸‚Pč˘ ƒÄ˙vň¸Pč• ƒÄ˙vđ¸Pčˆ ƒÄčą é!+Ŕčŕ ‹žƒ=u¸ë¸ Ł [‹E EŁ [‹E%šÓř EŁ[‹E*äŁ[Ç[‹EŁ[¸Pč[ƒÄ…Ŕu3¸P¸ Pč ƒÄč2Wč(ƒÄ…ŔtŠE˜%?=tÇîZëč}¸˙˙ë+Ŕé ¸čM ‹žFúP¸ PčęƒÄ+ŔP¸#Pč˃Ä÷Fút|Ç [‹EŁ [+ŔPčŮƒÄ…Ŕu@+ö¸Pč‰ƒÄ…Ŕu0FúP¸ PčŸƒÄ‹Fú*äU֋ڈFƒţ|иPčYƒÄ…Ŕt¸˙˙ë FúP¸ PčjƒÄ÷FúućŠE˜Š?uÝ+ŔéÔ¸č ƒ>îZu&FúP¸!Pč:ƒÄ‹Fú% =tç˙v¸ PčƒÄ鞸čjÇFú+ŔP¸!PčőƒÄÇFř€ ë˙Nřƒ~řu÷+ŔP¸"PčŘƒÄÇFřë8FúP¸!PčŐƒÄ÷Fú0t¸˙˙éÉ˙vú¸_PčS$ƒÄëë‹Fú% = t ˙Fř~ř}|Á~ř}tŐÇîZ¸_P+ŔPčƒÄ…Ŕt뜸"_P¸PčîƒÄ…Ŕt 뢃>đZĺÇFřëXÇ [‹FřšÓ࣠[‹Fřş ÷ę‹Ř‹‡źYŁ[¸PčNƒÄ…Ŕt éa˙ÇîZéX˙č'‹Fřş ÷ęŽYPčţƒÄ…ŔuŢ˙Fř‹Fř;đZ|Ÿ+Ŕé{¸čG¸ňZP¸˙˙Pčj'ƒÄ¸P¸ PčČƒÄÇFřëFúP¸!PčĹƒÄ÷Fú u ˙Fř~ř}|áƒ~ř ~ ~ř}u ¸Á_Pč5#ƒÄë ˙vř¸í_Pč&#ƒÄé +Ŕč×Ç [ ‹FšÓ࣠[+ŔPč„ƒÄ…Ŕt¸˙˙éáčr‹^‹šÓřPčüýƒÄ‹^˙7čńýƒÄ‹^˙wčĺýƒÄ‹^‹GšÓřPčÓýƒÄ‹^˙wčÇýƒÄ‹^‹GšÓřPčľýƒÄ‹^˙wčŠýƒÄ‹^˙wčýƒÄčč…Ŕt ÇîZét˙+Ŕér˙¸č"¸P蟃Ä…Ŕu*FúP¸ PčľƒÄFřP¸!Pč§ƒÄ÷Fřuë÷Fút¸˙˙é+Ŕëů¸čÚÇ [ +ŔP蒃Ä…ŔuE¸PčDƒÄ…Ŕu7FúP¸ PčZƒÄ¸Pč(ƒÄ…ŔuFúP¸ Pč>ƒÄ÷FútÇîZ¸˙˙骸čv‹ž+öFúP¸!PčƒÄ!~ú‹ĆF=}}9~úuâţ}| ÇîZ¸˙˙én+Ŕëů¸č6˙v¸#PčĆƒÄ˙v¸"PčšƒÄ+˙FúP¸!PčťƒÄ÷FúuG˙}|ä˙}u ÇîZ¸˙˙éčŤ+˙¸Pčd˙ƒÄ…Ŕu1FúP¸!PčzƒÄ‹Fú%= u‹ßŃă˙ˇ [¸ PčKƒÄGƒ˙|Áčnƒ˙uŽ+Ŕë­¸č–+ҸRPP¸[P¸P¸ffPčD ƒÄRP+ҸuRPč,ƒÄ  [*ä=~¸ë [*äŁđZFúP¸"Pč÷ƒÄ‹Fú%‰Fô‹FúšÓč%‰FňĄc‰FöĄc‰Fř+ŇšŃŕŃŇâú‹^ö+öĂ։Fî‰Vđ+Ҹ@RPP¸[P¸P¸ffPčš ƒÄRP˙vđ˙vîč˘ƒÄ ¸_P‹FôšÓŕ[PčqƒÄ¸"_P‹FňšÓŕ[Pč[ƒÄÇFúë/‹^úšÓăĄ_‰‡şY‹^úšÓ㥠_‰‡źY‹^úšÓăLJ˛Y˙Fúƒ~úrËÇ^ZÇ`ZÇžYÇŔY+ҸRPĄ_™RPĄ_™RPč—#RPč’#ŁÂY‰ÄYÇFúë/‹^úšÓăĄ$_‰‡şY‹^úšÓăĄ,_‰‡źY‹^úšÓăLJ˛Y ˙Fúƒ~ú rË+ҸRPĄ$_™RPĄ"_™RPč9#RPč4#ŁbZ‰dZƒ>đZ~ čiú…ŔtÇđZÇFúë]‹Fúş÷âŁöZÇüZÇţZÇúZÇ[[ÇřZú˙ÇôZ¸ňZPč1öƒÄ=t ˙vú¸`PčĂ؃Ä‹Fúş÷âPčJƒÄ˙Fú‹Fú;đZršé+ŔčZ‹ž‹ś‹‰ŠE*ä‰D‹E‰D‹E‰DŠE*ä‰DŠE*ä‰D éU¸ č!+˙ÇFöÇFř‹ÇF@šÓŕŽY‰Fú‹ÇšÓŕĆ‹đ‹^ú‹”[‹„[‰G‰W+ҸRP˙w˙wč"…Ňu…ŔtJ‹^ú‹W‹G‰Fö‰Vř+ҸRP˙w˙wč"ƒŇŃŕŃ҉Fň‰Vô‹^ú‰G‰W‹W‹G+FöVř‰Fö‰Vř‹”[‹„[+FöVř‰Fň‰Vô‹^ú‰G‰WGƒ˙}é@˙‹F@šÓŕŽYPčƒÄéw¸čC‹ž+öÇFú顋FúšÓŕNj؃uƒu‹Fú@šÓŕNj؃uVƒuP‹Fú@šÓŕNj؋W‹G‰Fö‰Vř‹FúšÓŕNj؋W‹G;Vř|=;Föv6‹Fú@šÓŕNj؃uƒt‹Fú@šÓŕÇP‹FúšÓŕÇPčƒÄ˙Fúƒ~ú}éV˙Fƒţ}éE˙é­¸ čy‹ž‹śFÜVW‹÷‹řšëóĽ_^VWšëóĽ_^FÜVW‡÷‹đšëóĽ_^ém+Ŕč9¸D`P¸tPč\ ƒÄĄF`-=woŃŕ“˙§d`¸D`PčfƒÄ‹ř‰>F`¸D`P˙6D`č& ƒÄëŔ¸D`Pč ë޸D`PčëŐ¸D`Pč}ë̸D`PčzëøD`PčŠ뺸D`Pč빸D`Pč머D`PčŮ럿÷˙럸 茋^‹G‰Fř‹G‰Fö‹G‰Fôƒ~ř|ƒ~ř} ƒ~ö|ƒ~ö|¸ő˙饋FöşV÷ęşe‹ř‹FřşV÷ęşe‹đ‹FöşV÷ęşe‰FúÇFňVë‹ŢFŠ˜‹^úˆ˙Fú‹Fň˙Nň…ŔučM‹Fô‰E4ÇÇE6ÇE8ÇE:ÇE<ÇE>ÇE@ÇEBÇED+Ŕéq˙¸čá‹^‹‰Fč‹G‰Fć‹G ‰Fâƒ~ćř|ƒ~ć|¸ő˙éé‹FćşV÷ęşe‹ř‹FčşV÷ęşe‹đÇFę‹Fę+҉Fđ‰Vň‹Fâ‰FîE ‰Fě˙vę˙vî¸PVč6ƒÄ‰Fř‰Vú…Ňu…Ŕu¸€P¸v`Pč˜ÔƒÄ˙vę˙vě¸P¸žgPčƒÄ‰Fô‰Vö…Ňu…Ŕu¸€P¸“`PčhԃÄ˙vň˙vđ˙vö˙vô˙vú˙vřčÉƒÄ ‹E"‰E‹E(‰E‹E(‰E‹E(‰E‹E‰Fäeý˙…Ŕt ƒ}uWč) ƒÄ+Ŕé˙¸čË‹^‹G‰Fú‹G ‰Fřƒ~ú|ƒ~ú|¸ő˙éŘ‹FúşV÷ęşe‹ř‹Fř‰EÇEÇEFÇEHe÷˙ƒ}uWčĆƒÄ˙vř˙vúčƒÄ+Ŕ뜸 č]‹^‹G‰Fö‹G‰Fôƒ~ö|ƒ~ö} …Ŕ|=|¸ő˙éa‹FöşV÷ęşe‹ř‹FôşV÷ęşe‹đ‹T8‹D6D>T@‰Fđ‰Vň‹U@‹E>FđVň‰E>‰U@‹T<‹D:DBTD‰Fđ‰Vň‹UD‹EBFđVň‰EB‰UDVč€ƒÄÇDFÇDH+ŔP˙vôč ƒÄ÷Dt@żşeë$‹EJ‰Fú‹Ř‹GL‰Fř…Ŕt;Ćuí‹Ř‹GL‹^ú‰GLƒÇV˙Ęmsƒ}Jtń9uJuˋDL‰EJÇD+Ŕé'˙¸čW‹^‹G‰Fú…Ŕ|=|¸ő˙ém‹FúşV÷ęşe‹ř‹EŁN`+Ŕëă¸č‹^‹G‰Fú…Ŕ|=|¸ő˙é5‹FúşV÷ęşe‹ř‹^‹U8‹E6‰G‰W‹U<‹E:‰G‰W ‹U@‹E>‰G ‰W‹UD‹EB‰G‰W+Ŕëś+Ŕ蝸€P¸°`PčóуÄéظ褋^‹G‰Fě‹G‰Fę‹G‰Fčƒ~ě|ƒ~ě|¸ő˙鍋FěşV÷ęşe‹řÇFň\`‹E‰Fî˙vęW¸\`Pč(ƒÄÇFđ‹Fđ)FîP˙vň¸P¸žgPč˙ƒÄ‰Fř‰Vú˙vđ˙vî¸PWččƒÄ‰Fô‰Vö…Ňu…Ŕu¸€P¸ą`PčJуÄ‹Fđ+ŇRP˙vö˙vô˙vú˙vřčŞƒÄ ‹Fî‰E‹Fč‰E+ŔéZ˙¸čÔ‹^‹G‰Fú‹G‰FřŠG˜‰FöŠG˜‰Fô‹W ‹G ‰Fň‹W‹G‰Fđ‹W‹G‰Fä‰Vć~úüu‹W ‹G ë˙vä˙vň˙vö‹FúşV÷ęşePč4ƒÄ‰Fě‰Vî~řüu ‹^‹W‹Gë˙vä˙vđ˙vô‹FřşV÷ęşePčţƒÄ‰Fč‰Vęƒ~îuƒ~ět ƒ~ęu ƒ~ču¸ň˙é@˙vć˙vä˙vę˙vč˙vî˙věčšƒÄ +Ŕëá+Ŕčń‹FşV÷ęşe‹řƒ}Tu˙ět‹FHş‹ČÓâ UT+ŔPčƒÄéë+Ŕ踋FşV÷ęşe‹đ÷Dt^ƒ|PtuXżjh˙ĘmsOƒ}TtLÇF`@‹Ç-şe™šV÷ů-ŁH`‹ETŁJ`˙ět¸D`P˙v¸˙˙Pč}ƒÄ…Ŕt¸€P¸Í`PčŽĎƒÄÇETénƒÇV룸 č5‹žƒ~ u+Ň+ŔéR‹FF HšÓč‰Fúƒ~t‹E&E*9Fús¸ë¸‰F‹Fş÷ęU ‹؋G‰Fđ‹Fş÷ęU ‹؋Fđ‹VšÓę;Đs™‹Fş÷ęU ‹؋G+҉Fö‰VřšŃŕŃŇâú‰Fö‰Vř‹F+҉Fň‰Vô‹Fş÷ęU ‹؋šÓŕ+Ň)FňVô‹Vř‹FöFňVôé<˙¸č\¸ PPčîƒÄƒ>Ěttƒ~úu¸ P¸ PčӃċF÷Řş‹ČÓâ‰Vô˙v˙v¸˙˙Pč:ƒÄ…Ŕt+Ąît‰Föƒ~ýu˙đtë(‹Fô ît‹F÷؋ŘŃă‹F‰‡ňtë‹Fô÷Đ!îtĄît‰Föƒ~ötKÇFúë>‹Fö‹NúÓřŠt.‹^úŃă˙ˇňt‹Fú÷ŘP¸˙˙PčɃĉFř…Ŕu¸‹NúÓŕ÷Đ!ît˙Fúƒ~ú~źƒ>utƒ>œd}>œdüučO隸čf‹FşV÷ęşe‹řƒ~ř| ƒ~| ƒ~ttÇţ˙ë[ƒ~t ƒ~|Çř˙ëI÷Ft'˙v ˙v˙vč9ƒÄ‰Fúƒ~t…Ŕt‹Fú‰ƒ~úu÷Ft˙v ˙v˙včƒÄ‰Fú‰é¸ čÚ ƒ~|ƒ~t ƒ~t¸˙˙ë^‹FşV÷ęşe‹ř‹FşV÷ęşe‹đ÷DuԋE*‰Fň‹F‰FřšÓč‰Fö‹FřšÓč‰Fô;För+E&;Fňr ¸ö˙ë¸ü˙é ÷Dt7ƒ|Ptt‹DP;Fu)˙tN˙t(˙v˙u(˙včĄ ƒÄ d÷˙ƒ|uLVčyƒÄëCƒ~˙tś‹F‰ENMWčČƒÄ‹DJ‰Fú…Ŕu‰|Jë‹^úƒLt‹GL‰Fúëď‹^ú‰LÇEL+Ŕéw˙¸čÖ ‹FşV÷ęşe‹ř‹uJëg‹Ć-şe™šV÷ů-‰Fřƒ~tt‹F;FřuB˙v˙u(˙tN˙t(˙vřčö ƒÄ dű˙ƒ|uVč΃Ä;uJu‹DL‰EJë ‹^ú‹DL‰GL+ŔéŽ ‰vú‹tL…öu•‹F‰EP‹F‰ENMWčúƒÄƒ>ět~҃~ũ~tuĆ+ŔPčhűƒÄëť+Ŕč ƒ>ut+˙ëƒ>utżëżĄœdŁ u‹ßŃヿut+‹ßŃ㋇u-şe™šV÷ů-ٜd‹ßŃ㋇uŁždƒ>œd}ëÇœdüÇždhĄždŁÎtéŢ ¸čŞ ‹žče ‹Ç-şe™šV÷ů-‰Fú…Ŕ}+Ŕëƒ~ú}¸ë¸‹đ‹ŢŃヿuu ‹ŢŃ㉿uë ‹ŢŃ㋟ u‰R‹ŢŃ㉿ uÇERč éu ¸čA ‹žčü ‹Ç-şe™šV÷ů-‰Fú…Ŕ}+Ŕëƒ~ú}¸ë¸‰Fř‹ŘŃ㋷u…ötB;÷u‹ŘŃă‹DR‰‡učŇţë+9|Rt ‹tR…öuôë ‹\R‹GR‰DRë‹tRƒ|Ru÷‹^řŃ㉷ uč éí +Ŕčş čy ƒ>ut&‹uĄu‰GRĄuŁu‹u‹GRŁu‹uÇGRčjţčR é˛ ¸č~ č¸ę`P¸tPčžƒÄĄě`‰Fú-=w@Ńŕ“˙§a¸ę`PčBƒÄÇě`ƒ~útǸę`P˙6ę`č_ƒÄëˇč ë߸ę`Pč/ëÓčYëŃ˙6ě`¸aPčWɃÄëÁ¸č ‹^‹G‰Fú‹W ‹G ‰Fö‰Vř‹G‰Fô‹FúşV÷ęşe‹řƒ}Hu ƒ}Fu+Ň+Ŕë+Ҹ<RP‹UH‹EF+uuRPčŁô`‰ö`ƒ~řu ƒ~öu+Ň+Ŕë ‹uĄuFöVř‰EF‰UHƒ~ú}‹Fú÷؋ŘŃă‹Fô‰‡aÇâ`˙˙Çä`˙żşeë0ƒ}Huƒ}Ft!‹UH‹EF;ä`|;â`s ‹UH‹EFŁâ`‰ä`ƒÇV˙ĘmrĘéT +Ŕč! Çě`+Ҹ<RP˙6u˙6učsŢ`ŕ`Łô`‰ö`é% +Ŕčň+Ҹ<RP˙6u˙6učJ‹^‹w ‹_ +Řň‰Ţ`‰6ŕ`éö¸č‹6đtD™‰Fö‰Vř‹uĄuFöVřŁu‰u)6đt‹ä`Ąâ`;u~éą| ;uvéŚÇâ`˙˙Çä`˙żşe鋃}Huƒ}Ft|‹UH‹EF;uC|;uw;‹Ç-şe™šV÷ů-‰Fú…Ŕ|¸P˙vúč:÷ƒÄë ‹Fú÷؋ŘŃă˙—aÇEFÇEHƒ}Huƒ}Ft!‹UH‹EF;ä`|;â`s ‹UH‹EFŁâ`‰ä`ƒÇV˙Ęmsél˙čBƒ.ć`u8ĄÎt;č`učýÇć`ĄÎtŁč`ƒ>utƒ>u~ Ąu;uučuĄuŁuéÄ+Ŕč‘ƒ> u|‹ÎtƒG6ƒW8ë ‹ÎtƒG:ƒW<雸čgÇFúŽM‹Fú*ä‰Fř‹FúšÓč*ä‰Fö¸6P¸CPč܃Ä˙vř¸@PčĎƒÄ˙vö¸@PčƒÄéP¸čč/ +ŇšŃŕŃŇâúŁXa‰ZaĄ P"PšÓŕ+ŇŁha‰jaÇdaÇfa ë.=t`=tjÇFúę˙Ç:aD‹FöŁa¸8aP˙vřčáƒÄ¸8aP¸tPčŮƒÄƒ>8a}˙68a¸paPčŮŃÄĄ8a‰FřĄ>a‰FöĄ:a=u›¸8aPčƒÄ‰Fú뛸8aPčëď¸ča‹ž‹E‰Fú…Ŕ|=|¸ú˙ëƒ}t ‹Eë ;‡`ar<¸˜˙é^ƒ~útáƒ} |֋^úšÓ㋗Ra‹‡PaE U ‰Fô‰Vö‹^úšÓă;—ba}ź‹E‰Fř™FôVö‹^úšÓă;—ba|!;‡`av‹^úšÓ㋗ba‹‡`a+FôVö‰Fř‹EşV÷ęşe‰Fî˙vř‹EP¸P˙vîčaőƒÄ‰Fđ‰Vň…Ňu …Ŕu¸ö˙éR˙ƒ}u‹Fř™RP˙vň˙vđ˙vö˙vôë‹Fř™RP˙vö˙vô˙vň˙vđčƒÄ ‹Fřé˙¸čG‹^‹G‰Fú…Ŕ|=|¸ú˙é]‹^‹W ‹G ‹^úšÓ㉇Pa‰—Ra‹^‹W ‹G ‹_+ö…Ű}÷Öš ŃăŃÖâúĂ֋^úšÓ㉇`a‰—ba+Ŕ미čÚčZë=t.=u FäPč+ƒÄFäP¸tPčä ƒÄ‹Fć=u֍FäPčëލFäPč4ëŐ¸č“ÇFöƒ>utÇFöő˙‹^ƒÇFöę˙‹^‹GşV÷ęşe‰Fň˙w‹GP¸P˙vňčôƒÄ‰Fî‰Vđ…Ňu …ŔuÇFöö˙ƒ~öté„čď‹^‹ŁŽa‹Gِa‹GŁu‹GŁ’a‹Vđ‹FîšŃúŃŘâúŁ”a‹Vđ‹Fî%+ŇŁ–a‰Vú~úč}=FôPĄŒa@Pč‰ƒÄ‹Fô%°=uKÇučœÇFöüë˙FřëF˙vôčüƒÄÇFöű˙‹Fô%°=uÇFöő˙˙vö‹^˙w˙7¸DP誃Ä鲋Fô%°=użÇFř~řč|Ž˙Fúéw˙¸ča‹^ƒuĄ’aë¸ű˙‰Fú>aüt%P˙6a˙6Ža¸CPčUƒÄƒ~úűu ‹^˙wčkƒÄÇuéE+Ŕčƒ>ut(ÇuÇuǐaü¸ü˙P‹^˙w˙7¸DPčƒÄé¸čÚ‹F‰Fć‹F ‰Fę‹F‰FčFäP˙vč㠃Äéć+Ŕčł÷F t ¸˜aPčéƒÄ÷Fu ¸ąaPčŘƒÄ÷Fu ¸ÉaPčǃÄ鍸čwƒ>Ętt¸x븟ٌaÇu¸PĄŒaPčëƒÄÇFúë˙Fúƒ~úd|÷¸ PĄŒaPčĘƒÄéX¸č$Ąu;’at ¸ PPč­ƒÄƒ>uu鞃>ué+Ŕ鞍FúPĄŒa@Pč—ƒÄ‹Fú%°=uf˙6–a˙6”ačŕƒÄˆFőŠFő˜*ä‰FřP˙6ŒačUƒÄ¸PĄŒaPčDƒÄ¸PĄŒaPč3ƒÄ˙–a˙u˙uÇFöƒ~öd|év˙˙Föëň‹Fú%°=t$Ǥdƒ>uué`˙‹Fúٍd¸˘dP¸ř˙PčéńƒÄésœúUPSQRVW‹ě‹†‹žšŃŘŃßâúŽÇ‹†‹śšŃŘŃŢâúŽŢ‹žç‹ść‹– ‹Ž÷Á€u ÷Â˙˙u隀‹Á÷Átó¤éŃé󥋖 ‹Ž3Ű+ČÓ Éu Ňu _^ZY[X]Ă‰– ‰Ž†ž†žéc˙U‹ěœúQVW‹†‹žކ‹ś Žž &‰ƒĆƒÇš óĽ_^Y]ĂS‹ÜPR‹—‹‡îZX[ĂS‹ÜPR‹—ě2䋟‰ZX[ÜúîaĂűĂ˙6îaĂU‹ěSV‹ž‹ś‹†‰‹„‰‡‹„‰‡‹„‰‡^[]Ă[U‹ěWV+ŕ;&ňav˙ăÇňa‹ždLJ2˙6œd¸öaPčżéâ˙fü^_]ĂÍ$0<0t¸Ă3ŔĂU‹ěQRWšşđüކ‹žóm_ZZ‹ĺ]ĂU‹ěQRVšşđüŽž‹śóo^ZZ‹ĺ]ĂU‹ěVWSQR‹ś‹ž#>čt‹Ž şÚ‹ßŮŮ+čtë~Ńű+ˉôa÷Ęttě¨tűœúކţt5đ˙đa󥝁ű~‰ž džžtœ‹6ôaöśé˙ZY[_^]øóŤéĘ˙U‹ěކ‹ž&Š2ä]Ăú¸ ć č?¸@ŽŘ¸4Łr¸˙˙ŽŘĄPĄPËú¸ ć č3Ŕ͸@ŽŘ¸4Łr¸˙˙ŽŘĄPĄPËüšŽžb3˙ŽÇóĽĂűéü˙¸č~ţ¸FcPčťƒÄ¸P¸^uP¸P¸žgPč&îƒÄ‰Fę‰Věżşeéw÷Etéj‹E"‰Fô‹E.E0‰Fň‹Fô+ŇšŃŕŃŇâúƒŇ‰Fî‰Vđ+ҸRP˙vđ˙vîčy‰Fř‹Fň+ŇšŃŕŃŇâúƒŇ‰Fî‰Vđ+ҸRP˙vđ˙vîčL‰Fö‹Ç-şe™šV÷ůPčăƒÄ˙vö˙vř˙u<˙u:˙u8˙u6˙u˙u˙u˙u4¸cPčěƒÄƒ}u ¸łcPčÜë ‹EPPčŸƒÄ‹Ç-şe™šV÷ů-‰Fč=鈋عÓヿ uuƒżuts+ҸRP˙vě˙vę‹^čšÓă˙ˇ u˙ˇuč÷űƒÄ ÇnuÇpuÇFú^uë‹^ú€? ~€?|‹^úĆ˙Fú~úrurăƒ~ču ¸şcPč?ƒÄë¸^uP¸ÂcPč/ƒÄ¸ĹcPč%ƒÄƒÇV˙Ęmsé€ţ¸ÇcPčƒÄéóü¸ čżü¸ÉcPčüƒÄżjhéś÷Et驋E"‰Fö‹E.E0‰Fô‹Fö+ŇšŃŕŃŇâúƒŇ‰Fđ‰Vň+ҸRP˙vň˙vđčÖ‰Fú‹Fô+Fö+ŇšŃŕŃŇâúƒŇ‰Fđ‰Vň+ҸRP˙vň˙vđ茉Fř‹Ç-şe™šV÷ůPč=ƒÄ˙vř˙vú˙u0˙u.˙u,˙u*˙u(˙u&˙u$˙u"˙u ¸ dPčCƒÄƒÇV˙ĘmséA˙éü+Ŕččűƒ~|u ¸ŒdPčƒÄë+ƒ~|ƒ~ ‹^Ńă˙ˇ0c¸“dë ‹F-P¸–dPčňƒÄéÖű¸ č˘űƒ~u‹^šÓăLJuLJ u阸P‹FP¸P‹FşV÷ęşePč)ëƒÄ‰Fř‰Vú…Ňu…Ŕtf¸P¸tuP¸P¸žgPčëƒÄ‰Fô‰Vö+ҸRP˙vö˙vô˙vú˙vřčÝůƒÄ ¸P˙6tu¸P‹FşV÷ęşePčĹęƒÄ‹^šÓ㉇u‰— uéűŒŘøvuĂúW¸ +˙ŽŔ&ǤĽ3Ű&‹ű¤Ľu= uć_űø"čśúF‰Fôé#‹^€?%uKÇFú˙F‹^€?0}N‹Fô‰Fě‹^Š˜=cuéB~éŤ=Duéă=Ouéű=Xué ¸%Pč ̓Ä‹^˙FŠ˜Pčú̃Ä齋^€?9Ş‹Fúş ÷ꊚÓâÓúƒę0‰Fú넋^ô‹‰FřƒFô™‰Fî‰VđÇFö FŕP˙vö˙vđ˙vîč€ƒÄ‰Fř‹Fú+Fř‰Fö…Ŕé5‹Fö˙Nö…Ŕué(¸ Pč̃Äëç‹^ô‹‰FřƒFô‰Fň+҉Fî‰VđÇFö룋^ô‹‰FřƒFô‰Fň+҉Fî‰VđÇFö녋^ě‹W‹‰Fî‰VđƒFěÇFö ‹Fě‰Fôée˙‹^ě‹W‹‰Fî‰VđƒFěÇFöëދ^ě‹W‹‰Fî‰VđƒFěÇFöëŋ^ô‹‰FřƒFôPčÜ˃Ä霋^ô‹‰FރFô‰FÜë ŠFۘPč˝ËƒÄ‹^Ţ˙Fފ˜ˆFۅŔuĺ˙F‹FŢ+FÜH‹Vú+ЉVř…Ň~]‹Fř˙Nř…ŔtS¸ PčƒËƒÄëę=duéĽţ=ouéôţ=st“=xué˙éMţ‹FřH‰FöëFŕFö‹ŘŠ˜PčF˃Ä˙Nöƒ~ö}ĺ˙F‹^€?téŇýéŞř¸čvřÇFôƒ~uƒ~u ‹^ Ć0¸é‡řƒ~}ƒ~ u‹V‹F÷Ú÷؃ډF‰V˙FôÇFřë‹F Fř‹ŘĆ˙Fřƒ~ř |ěÇFřƒ~ uB+Ҹ RP˙v˙v荋V Vř‹Úˆ+Ҹ RP‹F Fř‹ŘŠ˜™‹v‹^+ŘňVSč?‰F‰Vƒ~u.‹V‹F%+ҋV Vř‹Úˆ‹V‹FšŃúŃŘâúâ˙‰F‰Vƒ~u.‹V‹F%+ҋV Vř‹Úˆ‹V‹FšŃúŃŘâúâ˙‰F‰V˙Fřƒ~téD˙ƒ~té;˙ÇFö‹FřH‰FúëK‹F Fú‹Ř€?uƒ~öu ‹F Fú‹ŘĆ ë(‹F Fú‹Ř€? } ‹F Fú‹Ř€0ë ‹F Fú‹Ř€7˙Fö˙Núƒ~ú}݃~ôt‹FřF ‹ŘĆ-˙Fř‹Fřé}ţšé šéšéU‹ě‹†‹žÍ ]ĂU‹ě‹F÷f‹Č‹F÷f ȋF÷fŃ]ÂU‹ěW+˙‹V‹F‹^ ‹N…Ňy ÷Ú÷؃Ú÷ׅŰy ÷Ű÷كŰ÷×čS…˙t÷Ú÷؃Ú_]ÂU‹ěW+˙‹V‹F‹^ ‹N…Ňy ÷Ú÷؃Ú÷ׅŰy÷Ű÷كŰč‹Ó‹Á…˙t÷Ú÷؃Ú_]Â…Űu‹Ř‹Â+Ň÷ń“÷ń‹Ę‹Ó+ŰĂUWV+˙„˙u&GWŠűŠÝŠé*ɋéŠč*ɊĊâŠÖ*öRPQ‹Í;Ór ¸˙˙ë WWRP‹Â+Ň÷ó‹č÷á_+řƒŇ‹ň‹Ă÷ĺƃŇ^+đƒŇX+Ây Můóëô‹Ď‹Ţ_…˙tŠÍŠëŠßŠř‹Ĺ+Ň^_]ĂoRRS232 interruptUnexpected trap: vector < 16 pc = 0x%x text+data+bss = 0x%x Unexpected trap: vector >= 16 This may be due to accidentally including a non-MINIX library routine that is trying to make a system call. pc = 0x%x text+data+bss = 0x%x Trap to vector 0: divide overflow. pc = 0x%x text+data+bss = 0x%x Kernel panic: %s %d Type space to reboot 1234567890-= qwertyuiop[] ‚asdfghjkl;'`€\zxcvbnm,./*ƒ „Ą˘Ł¤ĽŚ§¨ŠŞ…ˆˇ¸š‰´ľśŒą˛ł0!@#$%^&*()_+ QWERTYUIOP{} ‚ASDFGHJKL:"~€|ZXCVBNM<>?*ƒ „‘’“”•–—˜™š„‹789‰456Œ1230.1234567890-^ qwertyuiop@[ ‚asdfghjkl;:]€\zxcvbnm,./*ƒ „Ą˘Ł¤ĽŚ§¨ŠŞˆˇ¸š‰´ľśŒą˛ł0. Š ´˛ś¸‹ /ŤŹ­ŽŻŽ!"#$%&'()_=~ QWERTYUIOP`{ ‚ASDFGHJKL+*}€|ZXCVBNM<>?*ƒ „‘’“”•–—˜™š¸789‰456Œ123‡š ş  ťź/›œžŸ˝žżĚ˘úŽ¸Â  # + 3 U űőőőőőőőuDĘý@Ţń8ń‰‰‰‰‰‰‰‰‰‰‰‰a˙˙˙˙˙˙˙˙˙˙˙ ***##  Đ` Đ Đ ---disk task got message from FS gave floppy disk driver bad addrTrying to DMA across 64K boundaryDiskette in drive %d is write protected. winchester task got message from %d FS gave winchester disk driver bad addrTrying to DMA across 64K boundaryHard disk won't reset, status = %x wini: timeout waiting for INTERRUPT status wini: %d loops waiting for INTERRUPT status Can't read partition table of winchester ť.Ä.ß.‰.Š.č.˛.Í.Ö.bad call to sys_newmap (src)bad call to sys_newmap (dst)do_sig can't signal; SP badcan't inform MMJ;~;p;u;clock task got bad messagemem task got message from Printer is out of paper Printer is not on line Printer error Â@Č!˜€>;d.Kernel stack overrun, task = ?dFdMdTd[dbdidpdwd~d…d proc -pid- -pc- -sp- flag user -sys- base limit recv command %4d %4x %4x %4x %6D %7D %3dK %3dK /bin/sh%s PROC -----TEXT----- -----DATA----- ----STACK----- BASE SIZE %4x %4x %4x %4x %4x %4x %4x %4x %4x %3dK %3dK PRINTRTTY WINCHEFLOPPYRAMDSKCLOCK SYS HARDWRMM FS INIT ANY %s%4d  N#ÖZ é‹&ô'čéý˙éý˙¸č˛!ččlĄ$)ş(÷ę&)ŁŚ+ÇFúǨ+ÇŞ+üƒ>Ź+|ƒ>Ź+E|ÇFúš˙ë ‹Ź+Ńă˙—ö'‰Fúƒ>¨+uľƒ>Ź+;uƒ~út¨˙6Ž+˙6°+˙vú˙6$)čQƒÄë‘+Ŕč;!¸˛+P¸tPčx!ƒÄ…Ŕt¸€P¸`#PčƒÄĄ˛+Ł$)=˙˙|=|˙6$)¸q#Pč÷ƒÄĄ´+ŁŹ+é.!+Ŕčď ‹Fş(÷ę&)‹ř÷E&t8÷E&u1‹FŁĚ+‹FŁÎ+‹F ŁÜ+¸Ę+P˙včú ƒÄ…Ŕt¸€P¸~#PčƒÄéÚ +Ŕč› čƒŁ^#Pč ƒÄL)t)œ)Çâ+é­ ¸čm ƒ>$)t¸˙˙éš Ąś+‰Fꥸ+‰F襺+‰F쥟+‰Fô‹FęFč‰Fň‹FôFň‰Fđ‹Fě+Fđ‰Fî˙věčQƒÄ+Ҹ@RPĄ^#RPčy ‰Fú+Ҹ@RP‹Fđ RPčd ‰Fř+Ҹ@RP‹FîRPčR ‰Fö¸PP¸#Pč3ƒÄ˙vú¸–#Pč&ƒÄ˙vř¸­#PčƒÄ˙vö¸ž#Pč ƒÄ‹Fú+Fř+FöP¸Ň#PčřƒÄ‹Fú+Fř+Fö= }¸€P¸ä#Pč܃ÄčAżv)‹Fô‰E‹Fę‰E‹FôFę‰E‹Fč‰E ‹Fň‰E ‹FôFň‰Eƒ~ętM& +Ŕéâţ¸č?‹Fş(÷ę&)‹ř‹F‰FúÇÇE‹F‰EÇE‹Fú‰E ‹F‰E‹Fú‰E ÇE‹FFú‰EW˙vč ƒÄé%¸čä‹>Ś+ƒ>â+u ëHƒ}t ë@ƒ>â+}ń‹EE E‰Fě‹E +E Fě‹Fě+ŇšŃŕŃŇâú‰Fî‰Vđ˙věčĂƒÄ‰Fę…Ŕu¸ő˙éĂ‹Fę+ŇšŃŕŃŇâú‰Fâ‰Vä‹E+ŇšŃŕŃŇâú‰Fć‰Vč˙vđ˙vî˙vä˙vâ+ŔP¸üPR˙vć+ŔP¸üPčČƒÄ‰Fú…Ŕ} P¸ $Pč%ƒÄž&)ë ÷D&t ƒĆ(ţŚ+rđ‹Ć-&)™š(÷ů‰Fř˙â+‰~ô‰vň‰Núë‹^ôŠ˜‹^ňˆ˙Fô˙Fň‹Fú˙Nú…Ŕuĺƒ>$)u Ą$‰D˙$Ą$)‰D‹Fę‰D‹FęD‰D‹E+ED‰DĆDĆDÇFö>$0u}Ą$븣$ż&)˙Ś+s‹E;$uSÇFöĄ$‰Dƒ~öuÂ˙t˙vř˙6$)č+ƒÄ+ŔP˙vř˙6$)¸Pč"ƒÄV˙vřčSƒÄ+ŔPPP˙vřč9üƒÄĄ$é˜ţƒÇ(ë™+Ŕč˙6ś+˙6Ś+čƒÄǨ++Ŕé;+Ŕčü‹ž‹FˆE‹Eş(÷ę‹Ř‹‡L)Št W荃ÄëM&÷E&t+ŔP‹Ç-&)™š(÷ůPč™ ƒÄ‹Ç-&)™š(÷ůP˙učƒÄ+ŔPP‹Ç-&)™š(÷ůP¸PčfƒÄé˝+Ŕč~+öż&)ë7÷E&t-‹E;$)u$F÷E&tWč+ƒÄǨ++Ŕ닌+O&ëëƒÇ(˙Ś+rÅöč¸ö˙éj¸ č*‹ž‹Ç-&)™š(÷ů‰Fö‹E‹Ń÷ę&)‹đŠE˜*ä‰FôŠE˜šÓŕ Fô‰Fô+ŔP˙vô˙u˙učńúƒÄ‹E E‰Fň÷E& t‹EFň˙vň˙uč1ƒÄe&ű˙e&÷˙d&ý˙e&ţ˙˙â+÷œ)t¸ë+Ŕ‰FřÇFú&)ë.‹^ú‹G;FöuÇGƒ~řt‹G&Št Sč=˙ƒÄÇFřƒFú(~úŚ+rË鑸čP‹>Ś+Ąź+‰Fř+ŇŇšŃúŃŘâú‰FôFöP˙6$)čŞƒÄ˙vö˙vôWčƒÄ‰Fú…ŔuĄź+ë¸˙˙ŁŽ+‹Fúé:¸čú‹žE‰FúE ‹đÇFđ‹D+҉Fŕ‰Vâ‹+ŇFŕVâ‰Fč‰Vę‹FšÓč‰Fř+Ň;Vę| ;Fčr¸ô˙éć‹Fř+҉Fŕ‰Vâ‹+Ň+FŕVâ‰Fä‰Vć…Ň| …Ŕt‹Fř닉Fô‹^ú‹F‰Fö‹Fô;För¸‹G‰Fň‹F;Gt‰GNđƒ~ć|ƒ~ät‹Fä))DDNđ‹E&% ‰Fě˙u ˙u˙u˙u ˙uPčPƒÄ ‰Fî…Ŕuƒ~đtW‹Ç-&)™š(÷ůPčƒÄ+ŔéC˙÷Fđt ‹^ú‹Fň‰G÷Fđué&˙‹FäD)Dé˙¸čÄ‹FšÓŕ+Ňš÷ń‰Fú‹FšÓŕ+Ňš÷ń‰Fř‹F šÓŕ+Ňš÷ń‰Föƒ~ u~ú&‹FřFö=~ë‹FúFřFö= ‹F F;Fv¸ô˙é†+Ŕëů¸čB‹Fş(÷ę&)‹řFřP‹Ç-&)™š(÷ůPč¤ƒÄ˙vř˙u WčţƒÄ‰Fú…ŔtÇE"¸ PWč ƒÄé2¸<čň‹>Ś+Ą¸+‰†ć÷=v ¸ô˙ë¸ę˙éƒ>ś+~ó>ś+€륟+‰†đ÷†ô÷‰†î÷Ąś+™RP‹†î÷+ŇRP¸P+ŔP‹†đ÷RP¸P˙6$)čƒÄ‰Fř…Ŕt‹FřëŞ+ŔPP˙6$)¸ PčRƒÄ¸P†Ŕ÷P†ô÷PčƒÄ‰Fö+ŔP¸P+ŔP¸ Pč'ƒÄƒ~ö}‹Föéa˙‹†ć÷šÓ艆Ţ÷P†ŕ÷P†č÷P†ę÷P†ě÷PFôP˙vöč›ƒÄ‰Fú…Ŕ}˙vöčŔƒÄ¸ř˙é˙Ąž+‰†đ÷†ôű‰†î÷‹†ć÷+ŇRP‹†î÷RP¸P+ŔP‹†đ÷RP¸P˙6$)čFƒÄ‰Fř…Ŕt˙vöčrƒÄ¸ó˙éËţ¸P†ô÷P˙śâ÷˙śŕ÷˙ść÷˙śč÷˙śę÷˙śě÷čUƒÄ‰Fř…Ŕt ˙vöč5ƒÄéâţ‹E šÓŕ‰†ä÷P†ôűPčPƒÄ†ôű‰†đ÷‹†ć÷+ŇRP‹†ä÷RP¸P˙6$)‹†đ÷RP¸P+ŔPč­ƒÄ‰Fř…Ŕt¸€P¸$PčƒÄ˙śě÷+ŔP˙vöčDƒÄ˙śę÷¸P˙vöč3ƒÄ˙vöčŞƒÄ÷†Ä÷t‹†Č÷‰E˙u˙u˙6$)¸Pč ƒÄ÷†Ä÷t‹†Ę÷ˆEŠE˜PŠE˜P˙6$)¸.PčyƒÄÇE"e&ß˙‹Fô E&‹†ä÷‰†ň÷P˙6$)čoƒÄ+Ŕé—ý¸.čk¸ PFÎP˙vč•ƒÄ= uz‹VЋF΁â˙úuj=ue‹VĐ+Ŕâ u…Ŕt¸ ë+Ŕ‹^‰‹F֋^‰‹Fڋ^ ‰‹^ƒ? t‹^‹‹^ ‹^Ç‹Fދ^ ‰‹^‹Vč‹F扉Wƒu ƒ?u¸ř˙é‹^‹šÓč‰Fö‹^ ‹‹^ šÓč‰Fô‹^‹W‹ƒŇšŃúŃŘâú‰Fî‹Fô;Fîsł‹^ƒ? u+Ŕë‹Fö‰Fđ‹Fî+FFđ‰FňP˙vđ˙v˙vô˙vö‹^˙7č‘űƒÄ ‰Fú‹VԋFŇ*ä+҉Fř= ~- PFÎP˙včmƒÄ‹FúéT˙¸"č&‹FšÓč‰Fö‹FFšÓč‰Fô‹F šÓč‰Fđ‹V‹F ƒŇšŃúŃŘâú‰Fî+Fô+Fđ‰Fň…Ŕ} ¸ô˙ë¸ő˙éč ‹VöVî;Đwí‹>Ś+‹E E‰Fę÷E& t‹EFę˙vę˙uč ƒÄ‹FöFîPčś ƒÄ‰Fě…Ŕu¸€P¸5$Pčn ƒÄÇ‹Fö‰E‹Fě‰EÇE‹Fô‰E ‹FěFö‰E‹EFôFň‰E ‹Fđ‰E‹EFôFň‰EW˙6$)čBƒÄ‹F‰Fúë ‹^úĆ˙Fú‹FF9Fúrě‹FôFňFđ+ŇšŃŕŃŇâú‰Fć‰Vč‹F‰Fř‹E+ҋ]+öĂ։Fâ‰VäšŃŕŃŇâú‰Fâ‰Vä‹FšÓčšÓŕ+҉FډV܋Vä‹FâFÚV܉Fâ‰Vä‹Vč‹Fć+FÚV܉Fć‰Vč…Ň}+Ŕéşţƒ~ćtó‹F™9Vč|9Fćs‹Vč‹Fćë‹F™‰FމVŕRP˙vä˙vâ+ŔP¸üP‹Fř+ŇRP¸P+ŔPčÄ ƒÄ…Ŕt¸€P¸R$Pč! ƒÄ‹Vä‹FâFŢVŕ‰Fâ‰Vä‹Vč‹Fć+FŢVŕéq˙¸čĆFů‹F‰Fúë‹^ú‹‰Fö‹FFö‹Fö‰ƒFú€~ů|é‹F9Fúsň‹^úƒ?uÍţFůë۸čśƒ~tCĄ$)šÓŕ‹VšÓâ  F‰Fú‹Fş÷ęŚ+‹Ř‹šÓŕ‰Fö‹F‰FřP˙vö˙vúč¨ƒÄ餸čdƒ>ś+|ƒ>ś+~¸ę˙ëjƒ>ś+ taĄś+Hş‹ČÓâ‰Vúƒ>Ŕ+u%‹Ś+‹Â G ‹Fú÷ЋŚ+!G"ë5‹Fú÷ЋŚ+!G ëäƒ>Ŕ+të‹Fú÷ЋŚ+!G ‹Ś+‹Fú G"‹Ś+ĄŔ+‰G$+Ŕé+Ŕčß‹Ś+˙w˙6¸+˙6ś+čփÄé¸ čÁƒ>$)˙tƒ>$)t¸˙˙éł˙vöč_řƒÄ鼥ś+‰Föş(÷ę&)‹ř÷E&ué‹÷E&t運E‰FřĄ¸+‰FňÇŚ+&)‹Ś+‹E‰G~ň€t­ÇFúëK‹Fú@=t ‹Fú@=u+Ŕë‹Fř‰Fô‹Fú@= uÇFô˙˙‹Fň‹NúÓčŠt+ŔP‹Fú@P˙vôčƒÄ˙Fúƒ~ú|ŻÇ¨++Ŕé1¸čńƒ~|ƒ~~¸ę˙éÇFú‹FHş‹ČÓâ‰Vöżž)éŻ÷E&ué˘ÇFř‹F;Et …ŔtÇFřƒ~~ ‹F;EtÇFř÷E&tÇFřƒ~u‹Ś+‹G;EtÇFřƒ~u ƒ~˙uÇFřƒ~u ÷E&t8e&ď˙ƒ~řt-‹E …Föu%˙Fú˙vWčRƒÄ‹Ç-&)™š(÷ůPč‘ƒÄƒ~ ƒÇ(˙Ś+séH˙‹Ś+‹G&Št‹G&ŠtǨ+ƒ~ú~+Ŕé˙¸ý˙é˙¸čÝ‹ž÷E&u鏋FHş‹ČÓâ‰Vú‹E"…ÂtL‹Â÷Đ!E"FöP‹Ç-&)™š(÷ůPč" ƒÄƒnö˙vö˙u WčôƒÄ…Ŕu˙u$˙v‹Ç-&)™š(÷ůPč ƒÄë.‹FH‹ň'‹ČÓęâ‰Vř‹FˆE…ŇtWčƒÄ+ŔPWčBňƒÄéw¸č7Ąś+‰FúP˙6$)č ƒÄ‹ř‹ÇéY¸čÇh$‹FŁj$‹Fş<÷â+ŇŁp$‰r$ƒ~t‹Fş(÷ę‹ŘL)ë‹Fş(÷ę‹Ř§L)ď˙¸f$P¸ý˙PčƒÄ…Ŕt¸€P¸~$PčŽƒÄĄp$‰Fúéĺ+Ŕ茋Ś+O&Ǩ++ŔéĚ+Ŕč‹Fş(÷ę&)‹ř÷E&t*÷E&u#e&÷˙+ŔPP¸ü˙P˙včkíë#÷E&ue&ý˙ëâ÷E&uë+ŔPP˙v¸APč ƒÄén¸`č.‹ž‹Ç-&)™š(÷ů‰†´ţ+ŔPP˙ś´ţ¸ Pčé ƒÄ‹E;Et+ŔP¸P+ŔP¸ PčÍ ƒÄ饌+‰†œţ‰>Ś+¸PFŢP¸ě'PčˆƒÄ‰†źţ¸PFŔP¸‡$PčrƒÄ‰†şţ‹†œţŁŚ+ƒžźţ| ˙śźţčbƒÄƒžşţ| ˙śşţčQƒÄƒ}udžźţƒžşţ}éľƒžźţ} ƒžźţţt餸˙P¸ě'PčƒÄ‰†źţ+ŔP¸P+ŔP¸ Pč ƒÄƒžźţ|L€M€Ç†žţëG‹†žţş÷ęNj؋GšÓŕ+҉†Žţ‰–°ţ¸P†ŽţP˙śźţčű ƒÄ…Ŕ} ˙śźţčąƒÄé! ˙†žţƒžžţ|˛†Ŕţ‰†˛ţ+҉†žţ‰– ţdžžţƒžžţ}ɋ†žţş÷ęNj؋+ŇšŃŕŃŇâú‰†Şţ‰–Źţ‹†žţş÷ęNj؋G+ŇšŃŕŃŇâú‰†Śţ‰–¨ţ…Ň}˙†žţëŞƒžŚţtńƒž¨ţ|žŚţs ‹–¨ţ‹†Śţë+Ҹ‰†˘ţ‰–¤ţRP˙ś ţ˙śžţ¸P+ŔP˙śŹţ˙śŞţ˙śžţ˙ś´ţčĄƒÄ‰†¸ţ˙ś˘ţ†ŔţP˙śźţč ƒÄ‰†śţƒž¸ţ}éýţ…Ŕ}éöţ‹–Źţ‹†Şţ†˘ţ–¤ţ‰†Şţ‰–Źţ‹–¨ţ‹†Śţ+†˘ţ–¤ţé?˙+ŔP¸P+ŔP¸ Pč‹ ƒÄé´ţ+ŔčŁ ‹>Ś+ĄŹ+=t0=tI=t=.ty=/t‹Ćé¸ ‹u‹Eٰ+ëđŠE˜‹đŠE˜ëďĄ$)ş(÷ę‹Ř‹ˇ:)‹Eş(÷ę‹Ř‹‡:)ëыE;ś+t ƒ}t¸˙˙ë´Ąś+‰EĄś+‰E˙6ś+˙6ś+˙6$)¸Pčó ƒÄ+ö댊E˜‹ś+šÓâÓú;Âtƒ}uźĄś+ˆEĄś+ˆEĄś+˜PĄś+˜P˙6$)¸.뽸čĐ ‹>Š'ë0‹E;Fr#‹‰Fú‹F)Eƒ}t‹Fúéă WV聃Äëđ‹÷‹}…˙uĚ+Ŕëć¸čŒ ‹6Œ'…öu¸€P¸Ž'PčpƒÄ‹F‰‹F‰D‹Dٌ'‹>Š'…˙t‹F;w ‰|‰6Š'Vë …˙t‹F;v‰~ú‹}ëí‹^ú‹G‰D‰wSč4ƒÄé] +Ŕč ‹ž‹ś;6Š'u‹Dي'ë‹D‰EĄŒ'‰D‰6Œ'é/ +Ŕč𠋾‹u…öt9‹E;u‹DEVWčŽ˙ƒÄë‹ţ‹u…öt‹E;u‹DEVWčŒ˙ƒÄéă +Ŕč¤ ‹>Š'+öë 9uv‹u‹}…˙uń‹Ćé +Ŕčƒ żŠ$ë E‰EƒÇ˙Š'rńÇŽ$Lj'ÇŠ'Š$ÇŒ'$ÇŠ$‹Fٌ$é‚ ¸čB +ŔP˙včqƒÄ‹ř…Ŕ}0Ąä+÷Řë&~ú€tPWčâƒÄ¸ó˙ëƒ~uH‹^‹GŠIt=‹Çé: ˙vWč ƒÄ…Ŕ}¸€P¸ś'PčރÄ‹^‹G%đ‰Fúƒ~tŠ‹Ś+ƒt˛‹Ś+‹G‹^;Gužë‹Ś+ŠG˜‹^;G užë+ö‹Ś+ƒuƒ~uˆ‹^‹G‹ÎÓč…Ftév˙éV˙+Ŕčsƒ~u ƒ~u+Ŕ霋F˘˘'‹F٤'‹V ‹Fٍ'‰Ş'‹F˘Ł'‹F ŁŚ'‹V‹FŁŹ'‰Ž'‹V‹Fٰ'‰˛'¸ž'PčVƒÄĄ 'ëŻ+Ŕč¸ę˙éC+Ŕč˙v¸Ě'PčNƒÄ~€t ˙v¸ć'Pč:ƒÄ¸é'Pč0ƒÄ+ŔPPP¸$PčŞƒÄč†éţ+Ŕčż‹€(ŠFˆ‡‚(˙€(ƒ>€(duč €~ učéÔ+Ŕč•ƒ>€(t2Çč(Çě(Çę(Çř(‚(Ą€(Łî(¸ć(P¸ů˙PčłƒÄÇ€(é“+ŔčS˙v˙v¸P¸PčžƒÄév+Ŕč7+ŔPPPPP˙v¸P¸PčFƒÄéVŒŘø~5ĂúW¸ +˙ŽŔ&ǤĽ3Ű&‹ű¤Ľu= uć_űøčč+ŔPP˙vPP˙v¸P¸PčőƒÄ‰Fúé+ŔčĂ˙v˙v¸P¸PčƒÄéć¸"覍F‰Fôé#‹^€?%uKÇFú˙F‹^€?0}N‹Fô‰Fě‹^Š˜=cuéB~éŤ=Duéă=Ouéű=Xué ¸%Pč‰ţƒÄ‹^˙FŠ˜PčyţƒÄ齋^€?9Ş‹Fúş ÷ꊚÓâÓúƒę0‰Fú넋^ô‹‰FřƒFô™‰Fî‰VđÇFö FŕP˙vö˙vđ˙vîč€ƒÄ‰Fř‹Fú+Fř‰Fö…Ŕé5‹Fö˙Nö…Ŕué(¸ PčţýƒÄëç‹^ô‹‰FřƒFô‰Fň+҉Fî‰VđÇFö룋^ô‹‰FřƒFô‰Fň+҉Fî‰VđÇFö녋^ě‹W‹‰Fî‰VđƒFěÇFö ‹Fě‰Fôée˙‹^ě‹W‹‰Fî‰VđƒFěÇFöëދ^ě‹W‹‰Fî‰VđƒFěÇFöëŋ^ô‹‰FřƒFôPč[ýƒÄ霋^ô‹‰FރFô‰FÜë ŠFۘPč<ýƒÄ‹^Ţ˙Fފ˜ˆFۅŔuĺ˙F‹FŢ+FÜH‹Vú+ЉVř…Ň~]‹Fř˙Nř…ŔtS¸ PčýƒÄëę=duéĽţ=ouéôţ=st“=xué˙éMţ‹FřH‰FöëFŕFö‹ŘŠ˜PčĹüƒÄ˙Nöƒ~ö}ĺ˙F‹^€?téŇý錸čfÇFôƒ~uƒ~u ‹^ Ć0¸éƒƒ~}ƒ~ u‹V‹F÷Ú÷؃ډF‰V˙FôÇFřë‹F Fř‹ŘĆ˙Fřƒ~ř |ěÇFřƒ~ uB+Ҹ RP˙v˙vč•‹V Vř‹Úˆ+Ҹ RP‹F Fř‹ŘŠ˜™‹v‹^+ŘňVSč)‰F‰Vƒ~u.‹V‹F%+ҋV Vř‹Úˆ‹V‹FšŃúŃŘâúâ˙‰F‰Vƒ~u.‹V‹F%+ҋV Vř‹Úˆ‹V‹FšŃúŃŘâúâ˙‰F‰V˙Fřƒ~téD˙ƒ~té;˙ÇFö‹FřH‰FúëK‹F Fú‹Ř€?uƒ~öu ‹F Fú‹ŘĆ ë(‹F Fú‹Ř€? } ‹F Fú‹Ř€0ë ‹F Fú‹Ř€7˙Fö˙Núƒ~ú}݃~ôt‹FřF ‹ŘĆ-˙Fř‹Fřé}ţ¸čÂ+ŔPP˙vP˙v˙v¸P¸Pč̓ĉFúéÚ+Ŕč›+ŔPPPP˙v˙v¸P¸ţ˙Pč¨ƒÄé¸+Ŕčy+ŔPPPPP˙v¸P¸ţ˙PčˆƒÄĄp5‹^‰é+ŔčQ‹FŁj5‹FŁl5‹FŁt5¸P¸ţ˙PčŢƒÄéh+Ŕč)+ŔPPP˙v˙v˙v¸P¸ţ˙Pč4ƒÄéD+Ŕč+ŔPP˙vPP˙v¸œžŸ P¸ţ˙PčƒÄé"+Ŕčă+ŔPP˙vPP˙v¸P¸ţ˙PčđƒÄé+ŔčÁ‹^ÇGS¸ţ˙Pč˙ƒÄ…Ŕt¸€P¸ţ(Pč–ůƒÄéÓ+Ŕč”+ŔPP˙vPP˙v¸P¸ţ˙P襃Ä‹^‹l5Ąj5‰‰W‹p5Ąn5‰G‰W‹t5Ąr5‰G‰W ‹x5Ąv5‰G ‰Wé{+Ŕč<+ŔPPPPPP¸ P¸ţ˙PčMƒÄé]+Ŕč+ŔPPP˙v ˙v˙v˙v¸Pč*ƒÄé:+Ŕčű+ŔPP˙vP˙v˙v¸P¸PčƒÄé+Ŕč׋FŁj5‹F Łl5‹F Łn5‹FŁp5‹FŁr5‹FŁt5˙v˙včTƒÄéŢ+ŔčŸ˙v č}ƒÄ‹ř‰>j5‹FŁl5‹F Łn5žp5ƒ˙~ë‹^ Š˜‹ŢFˆ˙F ‹ÇO…Ŕuë˙v˙včƒÄ鐸čP‹FŁh5¸f5P˙v莃ĉFú…Ŕuƒ>h5|Ąh5ë Ąh5÷ŘŁä+¸˙˙éV+Ŕ苞+öëF‹ßG€?u÷Dé:[U‹ěWV+ŕ;&)r˙ăÇh5Çj5Çl5Çp5)¸f5P¸PčÄéý˙fü^_]Ăšé šéšéU‹ě‹†‹žÍ ]ĂU‹ěW+˙‹V‹F‹^ ‹N…Ňy ÷Ú÷؃Ú÷ׅŰy ÷Ű÷كŰ÷×čS…˙t÷Ú÷؃Ú_]ÂU‹ěW+˙‹V‹F‹^ ‹N…Ňy ÷Ú÷؃Ú÷ׅŰy÷Ű÷كŰč‹Ó‹Á…˙t÷Ú÷؃Ú_]Â…Űu‹Ř‹Â+Ň÷ń“÷ń‹Ę‹Ó+ŰĂUWV+˙„˙u&GWŠűŠÝŠé*ɋéŠč*ɊĊâŠÖ*öRPQ‹Í;Ór ¸˙˙ë WWRP‹Â+Ň÷ó‹č÷á_+řƒŇ‹ň‹Ă÷ĺƃŇ^+đƒŇX+Ây Můóëô‹Ď‹Ţ_…˙tŠÍŠëŠßŠř‹Ĺ+Ň^_]ĂÚÚMM receive errorMM called byMM can't reply%c 8%c~0Memory size = %dK MINIX = %dK RAM disk = %dK Available = %dK Not enough memory to run MINIX do_fork can't copydo_exec stack copy errMM hole list is inconsistentnew_mem can't zeroalarm er.Hole table fullallowed: fstat failedMemory manager panic: %s %d coreüf5¡ěÂÂÂÂS€ÂÂ.ÂÂ..™Â+ÂÂÂÂÂÂÂňÂÂÂÂÂÂÂÂ..lÂÂÂÂÂÂÂÂÂÂŢÂÂÂÂÂcÂÂsys_copy can't sendStack overflow  `DîŇ`é‹&äHčéý˙éý˙¸č¤Bč čhĄNJšÓŕPJŁPN‹Řƒ0u¸ë+ŔŁRNÇTNƒ>VN|ƒ>VNE|ÇFúš˙ë ‹VNŃă˙—ćH‰Fúƒ>TNuŽ˙vú˙6NJ芃ă>XNtščaë•+Ŕč1Bƒ>ZNt_żPJëF€}=u=‹Ç-PJ™š@÷ůŁNJ‹E6*äŁVN‹E6šÓř*äŁ`N‹E8ŁfN‹E:ŁbNĆE<ĆE=˙ZNëCƒÇ@˙PNr´¸€P¸pDPčˆ:ƒÄ¸\NP¸tPčBƒÄ…Ŕt¸€P¸DPčh:ƒÄĄ\NŁNJĄ^NŁVNéÖA+Ŕč—A‹FŁvN¸tNP˙včÉAƒÄéťA¸č{AčwčxčxÇFúëa‹FúšÓŕPJŁPN¸P¸Pč (ƒÄ‹ř‹PN‰Wčř*ƒÄ‹PN‰‹PNÇG.‹PNÇG0‹PNĆG2‹PNĆG3‹PNÇ˙˙ƒFúƒ~ú|™é;A¸ čű@ÇŒNÇŽNNÇ€Ÿt›żNë DžDž˙˙… ‰……ôű‰…Ç ˙€ŸrÚÇ’RÇtŸżNé†č:šÓŕ+҉Fô‰Vö‹Ç‰Fú˙‰Fř+ŇFôVö+Ŕ‰Fđ‰Vň‹Fú+ŇFôVö+Ŕ;Vňu;Fđt@˙NuÇŽNœRÇžVë,˙t›uÇ€Ÿh—Çh›ë… ‹‰‡…ôű‹‰‡Ç ˙€Ÿséq˙żNë ‹…‰…Ç ˙€ŸrNŁ‚Ÿé7@¸č÷?ĄdD‰FîĄfD‰FěĄhD‰Fę+ŔP¸P¸Pč›)ƒÄ‹ř¸2PW¸ÂŸPč7ƒÄÇFôŸ‹^ôt¸€P¸EPčc8ƒÄ‹^ô‹G‹O Óŕ‰Fú=~ P¸?EPčE8ƒÄ‹FúšÓŕ‰Fđ¸PWčÔ*ƒÄÇvNB‹FěŁxN‹FęŁzN‹FîFěFęFđŁ|N‹FîŁ~N¸tNP+ŔPč?ƒÄ…Ŕt¸€P¸`EPčé7ƒÄÇvNÇxN‹Fě+҉Fć‰Vč‹Fę+҉Fâ‰Vä‹Fî+ŇFćVčFâVäŁ~N‰€NšŃŕŃŇâúŁ~N‰€N‹FúŁ|N¸tNP¸ü˙Pč?ƒÄ…Ŕt¸€P¸vEPčy7ƒÄ¸EPčU8ƒÄÇFňé˜+ŔP˙vň¸Pča(ƒÄ‹ř¸P˙vň¸PčN(ƒÄ‹đ¸PWVčF6ƒÄƄ ¸ĂPWčË)ƒÄ¸ĂPVčŔ)ƒÄ+ҸRP‹Fňš ŃŕŃŇâúRPčĘ>‰Fö‰Vř+ҸRP˙vř˙vöčô>…Ňu…Ŕu+ŔP˙vř˙vö¸ÇEPč¸7ƒÄ˙Fň‹Fň;Fúsé]˙¸ÔEPč 7ƒÄé4>+Ŕčő=żÂŸëÇE&˙˙ƒÇ2˙ź rňżÂŸÇE&+ŔPWčą$ƒÄ¸P¸Pč%ƒÄ‹đ‹%đ=@u €| |}t¸€P¸FPčX6ƒÄ‰u*VčJ'ƒÄ‰u(ĆE0¸Pč9!ƒÄ…Ŕt¸€P¸GFPč+6ƒÄéĽ=¸čd=¸P˙6`N˙6dNč5ƒÄ…ŔtĄź éFřPFöP¸Pčă*ƒÄ‹đ…ŔuuĄbN%˙ ‹PN# €‰Fú+ŔP˙vú¸ž PčƒÄ‹ř‹6ź …ötƒţďuDƒţďul‹%đ=€u+ŔP¸PWč/ƒÄ‹đ…ŔuNWčƒÄëE= t=@t=`të4Wču$ƒÄ‹Ćéđ<žë˙ë#+ŔP¸PWč×.ƒÄ‹đ…Ŕu¸P˙učƒƒÄ‹đ…öuČĄPN‹VöŃâ‹؋Fř‰‹^řÇG‰‹Föë­+Ŕča<ƒ>RNu¸˙˙ëG¸P˙6`N˙6fNčŽ4ƒÄ…Ŕu.ĄbN%˙ ‹PN#‹bNâđ ‹ř˙6dNW¸ž PčƒÄPčË#ƒÄĄź éE<¸č<FěP˙včłƒÄ‹ř…Ŕu ë|WčŁ#ƒÄësFěPWč™ƒÄ‹đ…öugƒ>ź ţu`˙v˙u čČ#ƒÄ‹đ…ŔtÍţD ‹F‰D¸PVčĎ$ƒÄ¸PD"PFěPWčFƒÄ‰Fú…Ŕt1WčB#ƒÄţL ĆD&Vč4#ƒÄ‹FúŁź +ŔéŠ;…ötÇFúď˙륟 ‰FúWč#ƒÄ‹FúŁź ‹Ćë۸čG;ƒ>bN|ƒ>bN~ ¸ę˙鏥ź éڏP˙6`N˙6dNčf3ƒÄ…Ŕuä‹bNЇfF˜‰FřFúPFöP˙vřč§(ƒÄ‹đ…Ŕu*¸ž PčeƒÄ‹ř…Ŕtą+ŔP˙vřWč -ƒÄ‹đ…ŔtMWč„"ƒÄ‹Ćë?=`tWĄPN‹VöŃâ‹؋Fú‰‹^úÇG‰‹Föë=@uŇ÷FřtĐWčD"ƒÄ¸ë˙éž:‹%đ= u݋PNƒ4u‹E‰G4˙vř˙učQƒÄ뛸čV:˙6`Nčf(ƒÄ‹ř…ŔuĄź éz:‹u‹%đ‰Fř= t=`u'~ř`učĺ.Vč­ ƒÄ…Ŕu ˙tč“'ƒÄ˙tč#ƒÄ‹]€'t!÷t¸ë¸‰Fú¸P˙vú˙učƒÄƒmu ˙uč…!ƒÄĄPN‹`NŃâ‹ŘÇ+Ŕéo˙¸čŹ9˙6`Nčź'ƒÄ‹ř…ŔuĄź ë¸ă˙ë =tK=tV¸ę˙éź9‹]€'tâĄbN=uߋhNĄfN‰Fř‰Vú…Ň|؋]ĆG)‰E‰U‹Vú‹FřŁ~N‰€N+Ŕ뽋U‹EfNhNëȋ]‹W‹Gëë+Ŕč!9+ŔPčƒÄéO9¸&č9ƒ>NJu+÷`N˙t#Ą`NšÓř*ä‰FâĄ`NšÓř%‰Fŕ&`N?ë ĄNJ‰FâÇFŕƒ>bNu+Ŕë ƒ>bN}¸ę˙éô8Ąź ëř¸÷˙ëóƒ>NJuâ˙6`Nčš&ƒÄ‹đ…Ŕt߃~u¸ë¸#tҋT‹D‰Fě‰Vî…Ň|ˇ‹|‹U‹E‰Fô‰VöÇFęÇFđÇFć‹%đ‰Fä=`u…Ňuƒ~ôu ÇFô˙˙ÇFö˙Ç>Ą~ä téŽ˙6fN˙6NJ˙6bN˙vî˙vě˙u˙včRƒÄ‰Fę…Ŕ|$‰Fđ‹FꙉFډV܋Vî‹FěFÚV܉Fě‰VîÇFęƒ~t鞁~ä t%~ä`t‹Vî‹Fě;Vö|;Fôv ‹Vî‹Fě‰E‰Učç.‰E‰U ĆE&éĚƒ~uh~ä`ta˙u ččƒÄ‹Ř‹W‹G ‰FډVÜĄbN™‰F։V؋V܋FÚ+FÖVŘ9Vî| 9Fěv¸ĺ˙é‘ţ‹Vî‹Fě;Vö|;Fôv+ŔP˙vö˙vôWč¸ƒÄ€}'uéٍFěP˙6bN˙vć˙vWčá ƒÄ ‰Fę…Ŕ~麋FęéAţ¸+Fň‰Fč…Ŕ} ¸+Fň‰Fčƒ~u8‹Vö‹Fô+FěVî‰Fř‰Vú…Ň }éčţ…Ŕuéáţ‹Fč™;Vú| ;Fřv‹Fř‰Fč˙vâ˙vŕ˙6fN˙v˙vč˙vň˙vî˙věWčBƒÄ‰Fę…ŔtéĄţƒ>>Ą}é—ţ‹FčfN)bNFđ™‰FډV܋Vî‹FěFÚV܉Fě‰VîÇFćƒ>bNuéaţ+ҸRP˙vî˙věčô6‰Fň¸+Fň9bNré ˙ĄbNé ˙€}'tD‹Vî‹Fě;U|9;Er2ÇEÇEÇFěÇFî¸PWč*$ƒÄ‰FޅŔt ‹ŘÇGÇG‹Vî‹Fě‰D‰Tƒ~u=€})u7+ҸRP˙vî˙věčj6…Ňu#…Ŕu~ä€t~ä@u‰>XN‹Vî‹FěŁ@Ą‰BĄ~ä€uĆE)ƒ>>ĄtĄ>Ą‰Fęƒ>>Ą˜u‹Fđ‰Fęƒ~ętéMţ‹FđéŽü¸ čE5‹ž‹%đ=`u¸ë+Ŕ‰Fô…Ŕt+ҸRP˙v˙vč5‰Fň‹Eë˙v˙vWč)ƒÄ‰Fň‹E ‰Fđƒ~ôu>ƒ~ňu8ƒ~u+ŔPP¸˙˙Pč˘ƒÄ‹đVčkƒÄëd˙v˙vWčAƒÄ‹đ…ŔuQĄź éń4ƒ~u ~ u¸ë+Ŕ‰Föƒ~uƒ~ u‹V‹F;U| ;ErÇFö˙vö˙vň˙vđč5ƒÄ‹đƒ~u,~ t%ƒ~ôu‹V‹F;U|;Er ƒ~ uVčӃă~u+Ŕ븉FřP‹ĆF P˙v ‹FP˙v˙včžƒÄ ‰Fúƒ~uƄ ‹F F =u¸ë¸‰FöPVčFƒÄ‹Fúé$˙¸čŘ3‹žWč•ƒÄ‰Fę+ҸRP˙v˙vč>4‰Fě‰Vî‹FꙉFć‹Vî‹Fě‹Nć…ÉtŃúŃŘâú‰Fđ‰Vň‹FꙉFć‹Vň‹Fđ‹Nć…ÉtŃŕŃŇâú‰Fâ‰Vä‹Vî‹Fě+FâVä‰Fčƒ~ň%|ƒ~đsE‹VđŃâ‹؋‰Fú…ŔtéŮ+Ŕét3‹Vň‹Fđ-ƒÚ‰Fô‰Vö…Ň|=s‹E‰Fúëh‹E‰Fú…Ŕt́nôƒ^ö‹NęÓŕ‰Fř+ŔP˙vř˙u č˛ƒÄ‹đ+ҸRP˙vö˙vôč]3ŃŕƋ؋‰Fú¸BPVč%ƒÄ+ҸRP˙vö˙vôčw3‰Fô‰Vöƒ~úuée˙‹Fú‹NęÓŕ‰Fř+ŔP˙vř˙u čQƒÄ‹đ‹FôŃŕƋ؋‰Fú¸BPVčŃƒÄƒ~úué'˙‹Fú‹NęÓŕFč‰Fřé˙+ŔčP2ƒ~u(ĆnFÇpF‹F +ŇŁtF‰vF‹F˘oF‹FŁrF‹Fë&‹F˘nF‹FŁpF‹F+ŇŁtF‰vFĆoFÇrF‹F +ŇŁxF‰zF‹F +ŇŁ|F‰~F¸jFPč>0ƒÄĄlFé2¸čŃ1‹>XNÇXN˙6BĄ˙6@ĄWčÝýƒÄ‰Fř…Ŕt+ŔP˙vř˙u čiƒÄ‰Fú¸P˙vúčôƒÄéÉ1+Ŕč‰1¸PčmřƒÄéś1¸čv1‹žĆE&ÇFęWč*ƒÄ‰Fú+ҸRP˙v˙včÓ1‰Fâ‰Vä‹Fú™‰Fŕ‹Vä‹Fâ‹Nŕ…ÉtŃúŃŘâú‰Fî‰Vđ…Ň&|=sE‹VîŃâ‹؋F ‰čJ(‰E‰U +Ŕé91‹Vđ‹Fî-ƒÚ‰Fň‰VôÇFčÇFć…Ň |=sE馋E‰Fř…Ŕu#˙u˙u čőƒÄ‰Fř…ŔuĄź ëŽ‹Fř‰EÇFćnňƒ^ô+ҸRP˙vô˙vňč1‰Fě+ҸRP˙vô˙vňč=1‰Fň‰Vô~ě|¸ĺ˙éd˙‹Fř‹NúÓŕ‹đƒ~ćt¸ë+ŔPV˙u č ƒÄ‰Fęƒ~ćtPč̓ċFěŃŕFę‰Fö‹Řƒ?u<˙u˙u čOƒÄ‹^ö‰ÇFčƒ~ęt‹^ęƇ ‹^öƒ?u¸BP˙vęčKƒÄé1˙¸BP˙vęč;ƒÄ‹^ö‹‹NúÓŕ‹đƒ~čt¸ë+ŔPV˙u č|ƒÄ‰Fęƒ~čtPč>ƒÄ‹FňŃŕFę‹Ř‹F ‰čÓ&‰E‰U ‹^ęƇ ¸BPSč܃Äésţ¸čq/‹žWč.ƒÄ‰Fđ…Ŕuéԙ‰Fę+Ҹ‹Nę…ÉtŃŕŃŇâú‰Fě‰Vîƒ~ uRPRP˙v˙včą/RPčŒ/‰F‰V‹V‹F˙ƒŇ‰Fň‰Vô˙vî˙vě˙v˙vč…/‰Fč‰Vę˙vî˙vě˙vô˙vňčp/;Vęu_;FčuZ˙vô˙vňWčúúƒÄ‰Fř…ŔtF‹NđÓč@‹NđÓŕH‰Fö‹Fř‰Fúë'¸P˙vú˙u čnƒÄ‹đVč7ƒÄ¸PVčőƒÄ˙Fú‹Fú;FövŃéż.¸č.‹ž˙v˙vWč“úƒÄ‰Fú…Ŕté܃}uƒ}u˙u čłƒÄ‰Fě‹Ř‹Gë‹E‰FöP˙u čnƒÄ‰Fö…Ŕu+Ŕéź˙vö˙u čëƒÄ‹F ëç˙vö˙v˙vWčŒüƒÄ‰Fî…ŔuՋV‹F;Uu;Et¸P˙v˙vWčiţƒÄWčžƒÄ‰Fđ‹Fö‹NđÓŕ‰Fř‹Fđ™‰Fę+Ҹ‹Nę…ÉtŃŕŃŇâú‰Fň‰Vô+ҸRP˙vô˙vň˙v˙včW.RPč.Fř‰Fú¸P˙vú˙u č?ƒÄ‹đVčƒÄ‹Ćé¤-¸čd-‹žž‰~ú‹^úǃFúƒîuđƅ é|-¸ č<-‹>PNFöPFđP¸PčӃĉFú…Ŕt ‹Fú鴍E‹VđŃâ‹ŘÇ‹^öÇGëŕE‹VđŃâ‹؋Fö‰‹^öÇGFôPFňP¸PčƒÄ‰Fú…Ŕu´E‹VňŃâ‹؋Fô‰‹^ôÇG‹]‹G ‰Fř¸€P˙vřčŁƒÄ‹đ…Ŕu6E‹VđŃâ‹ŘÇ‹^öÇGE‹VňŃâ‹ŘÇ‹^ôÇGĄź éœ,ĆD'‹^ö‰wVč ƒÄ‹^ô‰w¸PVčfƒÄ‹FđŁxN‹FňŁzN+Ŕë˸č*,‹ž‹ś ƒ~t闋^ ‹W‹;U}éÔ;EséʸPWč=ƒÄ…Ŕtiƒ~t +ŔP贃ă>DĄ~S¸P¸PWčńƒÄëB¸ĺ˙ë?Ç„F@ĄPN-PJ™š@÷ůنFLjF¸‚FP+ŔPčá+ƒÄ¸ŕ˙ë=v>+ŔPčZƒÄ+Ŕéź+ţł¸PWčşƒÄ…ŔtЋÙ‰Fř‰Vú‹^ ‹W‹FřVú…Ň}ť‹^ ƒuƒ?u¸P¸PWč[ƒÄ¸ëŤ+Ŕč++ƒ~u˙DĄ‹PNĆG<Ą`NšÓŕ VN‹PN‰G6‹PNĄfN‰G8‹PNĄbN‰G:‹F÷؋PNˆG>ÇTNé++ŔčŘ*‹žžPJëJ€|<uA‹D6*ä;Fu7D‹T6šÓúŃâ‹؋9u+ŔP‹Ć-PJ™š@÷ůPčƒÄ˙DĄƒnt ƒĆ@ţPNr°éś*+Ŕčw*ƒ~|ƒ~| ˙v¸šFPč#ƒÄ‹FšÓŕPJ‹ř€}<t,€}=t&€}>u ĆE=˙ZNëĆE<‹F‰E:˙v˙vč†čƒÄéV*¸ č*ƒ>NJ~¸˙˙éÍĄ`N‰Fú…Ŕ|=| ˙vú¸ĽFPčŞ"ƒÄ‹FúšÓŕPJ‹ř€}<u陊E>˜÷؉Fř…Ŕu鉋E6šÓř*ä‰Fö…Ŕ|=|¸€P¸łFPč`"ƒÄE‹VöŃâ‹؋‰Fô‹Ř‹_‹G‰Fň+ÉÓč*䣆F‹FúوFÇ„F¸‚FP˙vřčś)ƒÄ…Ŕt¸€P¸ÁFPč"ƒÄĄ†F;Fúu¸ü˙P˙vúčĹţƒÄ+Ŕés)˙6ˆF˙6†Fč˛ţƒÄ¸\NP˙vřči)ƒÄ…ŔtǸ€P¸ĎFëˇ+Ŕč )˙včƒÄ¸ŢFP˙6úF‹öFšÓă˙—pIƒÄĄäFé)+Ŕčß(˙včSƒÄ¸ŢFP˙6úF‹öFšÓă˙—tIƒÄéő(+Ŕčś(˙vč*ƒÄƒ~u¸ë¸ŁŕF‹F+ÉÓč*äŁâF‹V ‹FŁčF‰ęF‹FŁäF‹FŁđF‹F ŁćF¸ŢFP˙6úF‹öFšÓă˙—rIƒÄ>äFüu ˙6úFčýƒÄĄäFé{(¸č;(˙6`NčKƒÄ‰Fú…Ŕu Ąź ë¸ç˙éY(‹^ú‹‹%đ= uę˙u胃ÄÇŕFĄNJŁäFĄřFŁâFĄdNŁćF‹hNĄfNŁčF‰ęF‹lNĄjNŁěF‰îF¸ŢFP˙6úF‹öFšÓă˙—rIƒÄ>ŕFüu ˙6úFč{üƒÄ‹ęFĄčFŁ~N‰€N‹îFĄěFŁ‚N‰„NĄäFéd˙+Ŕč'‹FšÓč*äŁöF‹F+ÉÓč*äŁřFƒ>öFt ĄöF;¨I|˙6öF¸üFPč ƒÄ‹öFšÓ㋇vIŁúFĄřFŁâFék'¸č+'‹^‹G‰FúS˙vči'ƒÄ…Ŕt¸€P¸ GPčĂƒÄ‹^‹G;Fúué2'‹^˙w˙wčpüƒÄ˙v˙vč('ëŐ¸čŘ&‹PN‹G4šÓč*ä‰Fř‹ŘšÓ㋇vI‰Fú‹PN‹G4+ÉÓč*ä‹^‰GS˙vúčn˙ƒÄéÓ&+Ŕč”&‹^ÇGéĂ&¸č‚&FîP˙vč0ƒÄ‹ř…Ŕu +Ŕë‹Çé &€~îtőFîPWčƒÄ‹đWčƒÄ‹Ćë߸čB&‹^€?/u ‹PN‹Gë‹PN‹G‹řWčÚƒÄ˙v˙vč@ƒÄ‹đ…ŔuW蠃Ä+Ŕé=&‹Çëů€<t÷˙vW譃ĉFúWč  ƒÄƒ~út؉v‹~ú롸čŇ%‹v‹F‰Fúë˙Fú‹^úŠ˜‹ř=/tđë&ƒ˙/t<…˙t8‹F;đs‹Ç˜‹ŢFˆ˙Fú‹^úŠ˜‹ř~ú>Ąsëс~ú>Ąs˙Fú‹^úŠ˜‹řƒ˙/uëç‹ŢFĆ‹F;đrđ~ú>Ąr Çź ™˙+Ŕé…%‹Fúëř¸č@%‹^€?u‹^˙w"˙w čz ƒÄéЋFřŁź +ŔéĹ+ŔPFôP˙v˙v踃ĉFř…ŔuŰ˙vô‹^˙w čC ƒÄ‹ř…Ŕt̃}"uX‹^ƒ"uO‹^€.uFžôŸţź s=‹D&;E uaWčv ƒÄ‹\*‹G ‰Fö‹\*˙w"Pč÷ ƒÄ‰Fú˙vPčV˙ƒÄ‹ř˙vúčH ƒÄ€}(u0žÂŸţź sń9|*uWč- ƒÄ¸P˙t&čˇ ƒÄ‹řëԃĆ2댃Ć2ëӋÇé$¸čM$‹ž‹%đ=@t ¸ě˙ë‹Fřén$ƒ~ u¸ë¸‰Fö+ŔP˙vöWčJƒÄ‰Fř…ŔuŐ+ҸRP˙u˙učƒ$‰FîÇFđÇFęÇFňÇFô選ţ˙늃~ tPƒ<tK¸P˙vDPč^ƒÄ…Ŕt6ƒ~ uÇ‹^úƇ čë‰E‰U ë‹^‹‰¸AP˙vúčńƒÄ+ŔéS˙ƒ~ uƒ<toƒĆëL¸AP˙vúčĎƒÄFňƒVô‹Vô‹Fň;UT|;EsM˙vô˙vňWčjďƒÄ‰Fě+ŔP˙vě˙u čú ƒÄ‰Fú‹đ‹Fú;đs˙Fđ‹Fđ;Fîwé6˙ƒ~ uÇFęƒ~ęt‹ƒ~ té˙ƒ~ęu.˙Fđƒ~đu¸ĺ˙é°¨ŞŤŹ­ŽŻ°ą˛ł´ţ˙u˙uWčXôƒÄ‰Fú…ŔuĄź é–ţ‹Fú‹đ¸P˙vDPč„ƒÄ‹^‹‰‹^úƇ ¸APSč˙ ƒÄčÚ‰E‰U ĆE&‹Fđ;Fîwéöţ+ŇšŃŕŃŇâú‰E‰Uéâţ¸čj"ƒ>RNu¸˙˙鄸P˙6`N˙6fNč–ƒÄ…Ŕté̸ž PčĚƒÄ‰Fö=˙˙uéˇÇFřÇFđÇFúŸë#‹^ú‹G&;FöuÇFđ‹^ú&˙˙u‹Ă‰FřƒFú2~úź rփ~đt¸đ˙ë¸é˙ë ‹^řÇG&˙˙¸ę˙é"ƒ~řtç‹^ř‹Fö‰G&+ŔPSčžƒÄ‹^ř‹Fö‰G&uɃ?răržƒr¸ƒr˛¸P˙6bN˙6hNčĎƒÄ…Ŕt ‹^řÇG&˙˙Ąź ëš¸ž PčäúƒÄ‹ř…ŔtăÇFňƒ}$~ÇFňđ˙‹%đ‰Fô=`t= uÇFňě˙+ö9vňu¸P˙vöčyƒÄ‹đ…ŔuĄź ‰Fň…öt ƒ<uÇFňę˙ÇFîƒ~ňu˙vöčłƒÄ…ŔtÇFňé˙ÇFîƒ~ňu‹%đ=@u‹%đ=@tÇFňě˙ƒ~ňt7WčzƒÄVčsƒÄƒ~ît ˙vöčƒÄčk˙vöč$ƒÄ‹^řÇG&˙˙‹FňéˇţĆE(‹^ř‰*‰w(ĄdNˆG0+ŔéŸţ¸čr ƒ>RNu ¸˙˙霡ź é–¸P˙6`N˙6dNč˜ƒÄ…Ŕu丞 PčуĉFö=˙˙tŇÇFôżFĄëƒ}$~‹E ;Föu‹E$FôƒÇ*˙†Śrăƒ~ô~D¸đ˙ë<‹Fř‰Fúƒ~út˙vöč^ƒÄ…Ŕt¸€P¸GPč›ƒÄčŸ˙vöčX ƒÄƒ~úu(¸ę˙é ÇFúÇFřŸ~řź sś‹^ř‹G&;FötĽƒFř2ëč‹^ú‹_*ĆG(‹^ú˙w*čHƒÄ‹^ú˙w(č<ƒÄ‹^úÇG*ÇG&˙˙+Ŕë¨+Ŕčl˙včŢřƒÄ‹ř…Ŕu¸˙˙ë%Çź ń˙WčƒÄëě‹%đ=`uç‹uWčďƒÄ‹Ćéj¸č*¸P˙6`N˙6fNčcƒÄ…ŔuZ¸ž Pč…řƒÄ‹đ…ŔtJÇFúŠD ˜*ä=uÇFúá˙ƒ~úu‹%đ=@u ƒ>RNuÇFú˙˙ƒ~útVč€ƒÄ‹Fúë VčtƒÄĄź éî¸P˙6bN˙6hNčíƒÄ…ŔuݍFěP¸ž PčKřƒÄ‹ř…ŔuĄź ‰Fúƒ~úu2FěPWč0ůƒÄ‰Fę…ŔuĄź ‰Fú=ţ˙uÇFúë˙vęč ƒÄÇFúď˙ƒ~úu ‹D ;E tÇFúî˙ƒ~úu¸PD"PFěPWčĐůƒÄ‰Fúƒ~úuţD ĆD&VčĂƒÄWé9˙¸č˙¸P˙6`N˙6dNč8ƒÄ…ŔtĄź ë@FęP¸ž Pč‘÷ƒÄ‹đ…ŔtçÇFúFęPVč}řƒÄ‹ř…ŔuĄź ‰Fúƒ~út VčaƒÄ‹FúéŰ‹%đ=@u ƒ>RNuÇFú˙˙ƒ~úu¸PFřPFęPVč"ůƒÄ‰Fúƒ~úuţM ĆE&WčƒÄ델čS‹ž‹E ‰FęWč ƒÄ‰FFč+Ҹ‹Nč…ÉtŃŕŃŇâú‰Fô‰Vö€}'u ÇEÇEÇFřÇFúë@|;EsD˙vú˙vřWčéƒÄ‹đ…Ŕt‹Ć‹NîÓč‰FňP˙vęč§ ƒÄ‹Vú‹FřFôVö‰Fř‰Vú‹Vú‹Fř;U~ľ˙u˙vęč~ ƒÄ‹E‰Fň…ŔtR‹NîÓŕ‹đ+ŔPV˙vęčYƒÄ‰Fě‰Fđë‹^đ˙7˙vęčJ ƒÄƒFđ‹Fě9Fđră¸BP˙věčƒÄ˙vň˙vęč" ƒÄWčƒÄ鄸čD˙včŸƒÄ‹đĄŒNDD=r¸˙˙é_ƒ|wƒ|v¸€P¸(GPčČƒÄ+˙ë+ŔPEP˙včžƒÄT‹ßŃăӋډG;|r݋D‰Fú+˙ë +ŔP‹FúÇP˙včŒƒÄT‹ßŃăӋډG;|rۋ\‹\‹DDŒN+Ŕém˙+Ŕč˙včëƒÄ‹đ‹DD)ŒN+˙ë¸ĂPD‹×Ńâ‹Ř˙7čƒÄG;|ră+˙ë¸ÄPD‹×Ńâ‹Ř˙7čĄƒÄG;|ră+Ŕén¸č.‹F ;FrÇF ‹F š Óč‰Fôš Óŕ‹V +ЉVđ‹Â+Ňš÷ń‰Fň…Ŕu‹Fë‹F‰Fî鮋FôŃŕF‹Ř‹‰Fě‹FňŃŕFě‹đ‹Fě‰Fú;vútr‹<˙˙˙tHÇFřƒ~řs=‹Ç‹NřÓčŠuN‹Fě‹Ö+Ћ™š÷ůšÓŕFř‹Vôš Óâ‰Fö;Fr ‹Fú-‹đƒĆ댸‹NřÓŕ ‹^ěƇ ‹FöéŽ˙Fřë›˙Fô‹Fô;FuÇFôÇFň‹Fî˙Nî…ŔtéE˙+ŔëҸ č#‹Fš Óč‰Fúš Óŕ‹V+ЉVř‹Â+Ňš÷ń‰Fö‹Fř+Ň÷ń‰Vô‹FúŃŕF‹Ř‹‰Fň…Ŕt@‹FöŃŕFň‹Ř‹‹ĘÓřŠu ˙v¸ƒÄë¸ PW˙vúč.ƒÄƄ ¸@PVčłƒÄĆE&é„+ŔčE‹^˙G$év¸č6‹ž‹ś‹Ć%‹ŘŃ㋇‚Ÿ‰Fú˙˙˙téűé‹^ú9ˇtéâ9żtéـż u˙ŒN‹^úţ‡ 鞃~út ‹^ú€ż ~¸€P¸őGPč‡ƒÄ‹^ú‹‡%‹ŘŃ㋇‚Ÿ‰Fř;Fútéĺ‹^ú‹‡‹—â‹ÚŃ㉇‚Ÿ‹^ú€ż uż˙˙t ¸PSčtƒÄ‹^ú‰ż‰ˇţ‡ ‹‡%‹ŘŃ㋇‚Ÿ‹^ú‰‡‹‡%‹ŘŃă‹Fú‰‡‚Ÿ˙˙˙tƒ~u +ŔP˙vúč%ƒÄ‹Fúé^‹^ú‹‡‰Fúƒ~úté˙ţƒ>ŒNu¸P¸âGPčš ƒÄ˙ŒNĄŽN‰Fú‹Ř€ż éţţ‹Řƒżuéňţ‹Ř‹‡ë݋^ř‹‡‰Fř‹^řƒżué%˙‹‡;Fúuŕ‹^ú‹‡‹^ř‰‡é ˙¸č›‹ž…˙uéĂţ €˝ ~éľ˙ŒN‹ľ‹…‰Fú…Ŕt‹Ř‰ˇë‰6ŽN…öt ‹Fú‰„ë‹FúŁ€Ÿ÷F€t(DžĄŽN‰…ƒ>ŽNu‰>€Ÿë‹ŽN‰ż‰>ŽNë&Ą€Ÿ‰…Džƒ>€Ÿu‰>ŽNë‹€Ÿ‰ż‰>€Ÿ÷F@t€˝ u˝˙˙t ¸PWčՃā~ĹuDž˙˙é¸ čÄ˙včúƒÄ‰Fö‹Ř‹GH‹V+ЉVřR˙w‹G+G@P‹ĂPčařƒÄ‰Fú…ŔuJÇź ä˙‹^ö‹G&šÓč*ä‰Fô‹G&+ÉÓč*ä‰Fň&u ¸HPčű ƒÄë˙vň˙vô¸(HPčé ƒÄ+Ŕé{‹^ö‹GHFúëń+Ŕč0ƒ~t˙vč…ůƒÄ‹ř‹EH‹V+ĐREPčĺřƒÄéB¸č‹ž˝˙˙tq‹…+Ňš ŃŕŃŇâú‰Fö‰VřW¸P¸PR˙vö˙ľ˙včęƒÄ‰Fú…Ŕ};‹…‰Fôƒ~ú˜t"˙ľ+ÉÓč*äP‹FôšÓč*äP¸BHPč6 ƒÄëDž˙˙‹FúŁ>ĄĆ… éˇ+ŔčxżNë‹…;FuDž˙˙Ç ˙€Ÿrçé‘+ŔčQ‹^Ç˙˙+öë¸č˙ë‹F‰ÇEÇE‹^‰?+ŔébFƒţ}ĄPN‹ÖŃâ‹؃?uç‹^‰7‹^ƒ?|źż†Śë ƒ}tśƒÇ ˙Šrń¸é˙ëž+ŔčäÇź ÷˙ƒ~|ƒ~|+ŔéĄPN‹VŃâ‹؋ëę+Ŕčľ‹žž†Śëƒ|t9|u ‹…Ft‹ĆéĎƒĆ ţŠrŕ+Ŕëđ+Ŕčƒƒ>NJu[Ą`NšÓŕPJ‹ř‹PN˙wčůƒÄƒ>bNt ‹PN‹Gë‹E‹PN‰G‹PN˙wčôúƒÄƒ>bNt+Ŕë‹E0‹PN‰G0+Ŕé[˙6`N˙6dNĄPNPč2ƒÄëć+Ŕčƒ>RNu¸˙˙é2˙6`N˙6dNĄPNPč ƒÄ‹ř‹Çëâ¸č׸P˙v˙vč ƒÄ…ŔtĄź ëC¸ž Pč/ęƒÄ‰Fú…Ŕtę‹Ř‹%đ=@tżě˙ë+ŔP¸P˙vúčŔƒÄ‹ř…˙t˙vúč7řƒÄ‹Ç鲋^˙7č'řƒÄ‹^‹Fú‰+Ŕëć+Ŕč\¸P˙6`N˙6fNč•ƒÄ…ŔtĄź ë)¸ž Pč˛éƒÄ‹ř…Ŕtë˙6hN+ŔPWč<ƒÄ‹đWčÔ÷ƒÄ‹ĆéO+Ŕč˙6`Nč ţƒÄ‹ř…ŔuĄź é4˙6fNW˙učƒÄëí¸&č䋞Fދđ‹E ‰‹E"‰D‹‰DŠE ˜*ä‰D‹E‰DŠE ˜*ä‰D ‹E‰D ‹U‹E‰D‰T€}'u,ƒ~t&‹^ƒ?u‹W‹G‰F։V؋T‹D+FÖV؉D‰T‹U ‹E‰D‰T‹U ‹E‰D‰T‹U ‹E‰D‰T‹F‰FÚ+ŔPV¸P˙vÚ˙6NJ¸PčÚÜƒÄ ‰FÜé`+Ŕč!¸P˙6`N˙6dNčZƒÄ…ŔtĄź ë>¸ž PčwčƒÄ‹ř…Ŕtë‹PN‹E;G0t ƒ>RNuž˙˙ë WčĐƒÄ‹đ…öt Wč„öƒÄ‹Ćé˙‹%ň‹bNâ˙ ‰ĆE&WčcöƒÄ+ŔëÝ+Ŕč ƒ>RNu ¸˙˙ëQĄź ëL¸P˙6`N˙6fNčČƒÄ…Ŕu帞 PčęçƒÄ‹ř…ŔtŐWč[ƒÄ‹đ…öuĄbN‰EĄdNˆE ĆE&Wč˙őƒÄ‹Ćéz+Ŕč;‹PN‹÷ЋřĄ`N%˙÷Љ‹Çé\¸č¸P˙6`N˙6dNčUƒÄ…ŔtĄź ë/¸ž PčrçƒÄ‰Fú…Ŕtę¸P˙6bN˙vúčƒÄ‹ř˙vúčŽőƒÄ‹Çé ¸ čÉ ‹ž‹5ƒ~t ‹PN‹G.ë‹PN‹G0‰Fňƒ~t ‹PNŠG2ë‹PNŠG3˜‰Fđƒ~ňuÇFúë1‹Fň;EuÇFôëŠE ˜9FđuÇFôëÇFô‹Ć‹NôÓč%‰FúÇFö‹Fú F;FútÇFöó˙ÇFřI÷Ft …vřuÇFöó˙ƒ~öu÷Ft Wč ƒÄ‰Fö‹FöéD +Ŕč ‹^˙w č]óƒÄ‹ř€}0t¸â˙é% +Ŕëů+Ŕčá ¸P˙6`N˙6nNčƒÄ…ŔtĄź ëE¸ž Pč7ćƒÄ‹ř…Ŕtë+ö‹PN‹E;G0t 96RNuž˙˙…öu‹lNĄjN‰E‰U ĆE&Wč=ôƒÄ‹Ćé¸ +Ŕčy 蜣~N‰€N+Ŕé¤ +Ŕče ƒ>RNu¸˙˙é’ ÇxH‹hNĄfNŁ€H‰‚H¸vHP¸ý˙Pč‡ ƒÄ‹ř…Ŕt W¸ŽHPčâƒÄ+ŔëƸč FěP˙6NJč› ƒÄ‹Vî‹FěŁxN‰zN‹Vň‹FđŁ|N‰~N‹Vö‹FôŁ€N‰‚N‹Vú‹FřŁ„N‰†N+Ŕé ¸čÎ Ą`N%ż˙‹ř‹6PNWčŐůƒÄ…Ŕu$Ąź ësFúP¸bNP+ŔPčNůƒÄ‰Fř…Ŕt*ëY¸÷˙ëT9>`Ntۃ>bN|îƒ>bN}ç;>bNt7ĄbNŁ`NčэD‹×Ńâ‹؋T‹bNŃăӋډD‹bNŃâ‹؋˙GĄbNév ¸č6 ¸PčńƒÄ‰Fúčf‰Fô‰Vö‹^ú‰G,‰W.€0uĆG1żFĄëƒ}$~€}&u ¸PWčôƒÄƒÇ*˙†ŚrŕÇFúŸë‹^ú&˙˙t€1u ¸PSč§ńƒÄƒFú2~úź rÚžNë+‹„‰Fř=˙˙t€ź u+ÉÓčŠ˙u ¸PVčŠ÷ƒÄĆ ţ€ŸrĎžNë+‹„‰Fř=˙˙t€ź u+ÉÓčŠ˙t ¸PVčT÷ƒÄĆ ţ€ŸrĎ+Ŕé„ ¸čD ƒ>NJt¸˙˙éq Ą`NšÓŕPJ‹đĄbNšÓŕPJ‰FúÇFř@ë‹ŢFŠ˜‹^úˆ˙Fú‹Fř˙Nř…ŔučĄbNšÓŕPJ‹řÇFřë%E‹VřŃâ‹؃?tE‹VřŃâ‹؋˙G˙Fřƒ~ř|Ő˙učnóƒÄ˙učeóƒÄ+Ŕém˙+Ŕč˘ ƒ>NJt¸˙˙éĎ Ą`NšÓŕPJŁPN‹6`N‹Ř€<u‹Ř€>u˙DĄ‰6`NčLߋPNĆG<+˙‰>`NčűÎGƒ˙|ó‹PN˙wčţđƒÄ‹PN˙wčńđƒÄ+Ŕë›+Ŕč. ƒ>NJt¸˙˙é[ Ą`NšÓŕPJ‹řƒ>VNu ĄbN‰E.ĄdN‰E0ƒ>VN.u ĄdNˆE3ĄbNˆE2+ŔëĆ+Ŕčĺƒ>NJ~¸˙˙é ˙6bN˙6`NčQރÄÇTN+Ŕëĺ+ŔčťÇ˘H¸ HP¸ý˙PčřƒÄ‹ř…Ŕt W¸¸HPčSƒÄ¸PčđîƒÄ‹đ‹ŹHĄŞH‰D,‰T.€|0uĆD1‹ŹHĄŞHéŁ+Ŕčd‹ž‹ś‹ßGŠ˜‹ŢFŠšÓâÓú;Ât+Ŕé{ƒnu߸ëň¸č0ƒ~~o‹F+Ňš÷ń…ŇuB‹F+Ň÷ń…Ňu7‹F+Ň÷ń…Ňu,‹F+Ňš÷ń‹ř‹v‹F‰Fú‹^ú‹‹ŢƒĆ‰ƒFúƒďuëë‹~‹v‹F‰Fú‹^úŠ˜‹ŢFˆ˙Fúƒďuíéň¸č˛ƒ~u-ƒ~'żž žfN‹ŢFŠ˜‹ßGˆƒnuď+Ŕë Çź ™˙¸˙˙隁~€í‹F‰Fú¸P¸ž P˙v˙vú˙6NJ¸PčŐƒÄ Łź ëĎ+ŔčL¸ę˙é€+ŔčAƒ>žHu7ÇžH˙v¸ÇHPčʃā~€t ˙v¸ŢHP蜃ĸáHP菃ÄčĘűčćé:+Ŕčű€~t‹ŞIŠFˆ‡ŹI˙ŞIƒ>ŞIduč €~ učé +Ŕč˃>ŞIt2ÇJÇJÇJÇ"JŹIĄŞIŁJ¸JP¸ů˙PčéƒÄÇŞIéÉŒŘø ŤĂúW¸ +˙ŽŔ&ǤĽ3Ű&‹ű¤Ľu= uć_űø"čZF‰Fôé#‹^€?%uKÇFú˙F‹^€?0}N‹Fô‰Fě‹^Š˜=cuéB~éŤ=Duéă=Ouéű=Xué ¸%Pč˙ƒÄ‹^˙FŠ˜PčńţƒÄ齋^€?9Ş‹Fúş ÷ꊚÓâÓúƒę0‰Fú넋^ô‹‰FřƒFô™‰Fî‰VđÇFö FŕP˙vö˙vđ˙vîč€ƒÄ‰Fř‹Fú+Fř‰Fö…Ŕé5‹Fö˙Nö…Ŕué(¸ PčvţƒÄëç‹^ô‹‰FřƒFô‰Fň+҉Fî‰VđÇFö룋^ô‹‰FřƒFô‰Fň+҉Fî‰VđÇFö녋^ě‹W‹‰Fî‰VđƒFěÇFö ‹Fě‰Fôée˙‹^ě‹W‹‰Fî‰VđƒFěÇFöëދ^ě‹W‹‰Fî‰VđƒFěÇFöëŋ^ô‹‰FřƒFôPčÓýƒÄ霋^ô‹‰FރFô‰FÜë ŠFۘPč´ýƒÄ‹^Ţ˙Fފ˜ˆFۅŔuĺ˙F‹FŢ+FÜH‹Vú+ЉVř…Ň~]‹Fř˙Nř…ŔtS¸ PčzýƒÄëę=duéĽţ=ouéôţ=st“=xué˙éMţ‹FřH‰FöëFŕFö‹ŘŠ˜Pč=ýƒÄ˙Nöƒ~ö}ĺ˙F‹^€?téŇýéZ¸čÇFôƒ~uƒ~u ‹^ Ć0¸é7ƒ~}ƒ~ u‹V‹F÷Ú÷؃ډF‰V˙FôÇFřë‹F Fř‹ŘĆ˙Fřƒ~ř |ěÇFřƒ~ uB+Ҹ RP˙v˙vči‹V Vř‹Úˆ+Ҹ RP‹F Fř‹ŘŠ˜™‹v‹^+ŘňVSčý‰F‰Vƒ~u.‹V‹F%+ҋV Vř‹Úˆ‹V‹FšŃúŃŘâúâ˙‰F‰Vƒ~u.‹V‹F%+ҋV Vř‹Úˆ‹V‹FšŃúŃŘâúâ˙‰F‰V˙Fřƒ~téD˙ƒ~té;˙ÇFö‹FřH‰FúëK‹F Fú‹Ř€?uƒ~öu ‹F Fú‹ŘĆ ë(‹F Fú‹Ř€? } ‹F Fú‹Ř€0ë ‹F Fú‹Ř€7˙Fö˙Núƒ~ú}݃~ôt‹FřF ‹ŘĆ-˙Fř‹Fřé}ţ+Ŕčw+ŔPPPP˙v˙v¸P¸ţ˙Pč„ƒÄé”+ŔčU+ŔPPPPP˙v¸P¸ţ˙PčdƒÄĄŤ‹^‰él+Ŕč-‹FŁ Ť‹FŁ Ť‹FŁŤ¸P¸ţ˙PčşƒÄéD+Ŕč+ŔPPP˙v˙v˙v¸P¸ţ˙PčƒÄé +Ŕčá+ŔPP˙vPP˙v¸P¸ţ˙PčîƒÄéţ+Ŕčż+ŔPP˙vPP˙v¸P¸ţ˙Pč̃ÄéÜ+Ŕč‹^ÇGS¸ţ˙PčŰƒÄ…Ŕt¸€P¸(JPč5úƒÄéŻ+Ŕčp+ŔPP˙vPP˙v¸P¸ţ˙Pč}ƒÄ‹^‹ ŤĄ Ť‰‰W‹ŤĄŤ‰G‰W‹ŤĄŤ‰G‰W ‹ŤĄŤ‰G ‰WéW+Ŕč+ŔPPPPPP¸ P¸ţ˙Pč)ƒÄé9+Ŕčú+ŔPPP˙v ˙v˙v˙v¸PčƒÄé+Ŕč׋FŁ Ť‹F Ł Ť‹F ŁŤ‹FŁŤ‹FŁŤ‹FŁŤ˙v˙včTƒÄéŢ+ŔčŸ˙v č}ƒÄ‹ř‰> Ť‹FŁ Ť‹F ŁŤžŤƒ˙~ë‹^ Š˜‹ŢFˆ˙F ‹ÇO…Ŕuë˙v˙včƒÄ鐸čP‹FŁŤ¸ŤP˙v莃ĉFú…Ŕuƒ>Ť|ĄŤë ĄŤ÷ŘŁŤ¸˙˙éV+Ŕ苞+öëF‹ßG€?u÷Dé:[U‹ěWV+ŕ;&J¸ŤP¸PčÄéý˙fü^_]Ăšé šéšéU‹ě‹†‹žÍ ]ĂU‹ě‹F÷f‹Č‹F÷f ȋF÷fŃ]ÂU‹ěW+˙‹V‹F‹^ ‹N…Ňy ÷Ú÷؃Ú÷ׅŰy ÷Ű÷كŰ÷×čS…˙t÷Ú÷؃Ú_]ÂU‹ěW+˙‹V‹F‹^ ‹N…Ňy ÷Ú÷؃Ú÷ׅŰy÷Ű÷كŰč‹Ó‹Á…˙t÷Ú÷؃Ú_]Â…Űu‹Ř‹Â+Ň÷ń“÷ń‹Ę‹Ó+ŰĂUWV+˙„˙u&GWŠűŠÝŠé*ɋéŠč*ɊĊâŠÖ*öRPQ‹Í;Ór ¸˙˙ë WWRP‹Â+Ň÷ó‹č÷á_+řƒŇ‹ň‹Ă÷ĺƃŇ^+đƒŇX+Ây Můóëô‹Ď‹Ţ_…˙tŠÍŠëŠßŠř‹Ĺ+Ň^_]ĂÚÚget_work couldn't revive anyonefs receive errorZONE_NUM_SIZE != 2SUPER_SIZE > BLOCK_SIZEBLOCK_SIZE % INODE_SIZE != 0NR_FDS > 127NR_BUFS < 6inode size != 32Diskette in drive 0 is not root file systemRAM disk is too big. # blocks = FS Can't report to MMCan't report size to MEMLoading RAM disk from root diskette. Loaded: 0K %3DK %c RAM disk loaded. Please remove root diskette. Root file system corrupted. Possibly wrong diskette.init: can't load root bit mapsrevive errunpause err 1unpause err 2unpause err 3unpause err 4bad major devrw_dev: can't senddo_umounttoo many map blocksfreeing unused block or inode--check file syscan't find superblock for device (in decimal)Out of i-nodes on root device (RAM disk) Out of i-nodes on device %d/%d All buffers in useNo free bufferNo space on root device (RAM disk) No space on device %d/%d Unrecoverable disk error on device %d/%d, block %d do_stime errorclock_time errFile system panic: %s %d Ťw;!9~8˘ :{lw;^˜#Ă$w;@1J6b˘3#4w;g2 w;X P"•9w;^6w;w;ł2w;â5w;w;Ś4w;w;Œ7w;w;w;w;ô6†§6w;w;•9w;w;w;w;w;w;w;‡w;w;w;w;w;ˆ4ž1w;w;w;Źw;Ţ9w;/—/ü˙/—/ű˙/—/ú˙/—/ů˙/ę/ů˙/—/ř˙sys_copy can't sendStack overflow  |˛Ré‹&–čéý˙éý˙¸čôč§č’…Ŕt FěPčˇëH+ŔP¸˜PčšƒÄ…Ŕ} ¸˙˙PčĚ˙ƒÄ¸P¸ PčƒÄ¸P¸ŞPčƒÄ¸´PčƒÄ¸ţ˙Pčœ˙ƒÄ+ŔP¸źPčnƒÄ‰Fî…Ŕu9FňPčfƒÄ‰Fć=~K=ué€~ň1uăŠFô˜-0‰Fč…Ŕ|Ő= }ĐP臃ÄëǸP¸ĆPč ƒÄ‰Fî¸P¸ĐP˙vîč*ƒÄëţ˙vîčáƒÄÇFäë¸P˙väč1ƒÄ˙Fäƒ~ä~ęFęPčĚƒÄ‰Fě˙BÇFäƒ~ä }ä‹^äŃ㋇.;Fěu ˙väčƒÄ˙Fäë޸čÁčb‰Fú…Ŕt‹^Ń㉇.˙Béá+ŔPčcƒÄ‹F0˘”+ŔP¸ŒPčmƒÄ…Ŕt ¸ý˙Pč€ţƒÄ¸P¸ŒPčQƒÄ=t ¸ý˙PčcţƒÄ¸P¸ŒPč4ƒÄ=t ¸ý˙PčFţƒÄ¸ëPč›ƒÄ¸úPč‘ƒÄ¸Pč‡ƒÄ¸ Pč}ƒÄék˙¸č‹F‰Fú¸P˙vú+ŔPčúƒÄ…Ŕ+Ŕë˙Fú‹^úĆ‹Ă+Fé‹^ú€? tç˙FúëĘ+Ŕč͸D PFP˙včKƒÄéó¸čłF‰Fú‹^úƒFúƒ?uô‹^ú˙7FP˙včƒÄéĆ+Ŕ臸D P˙v˙včƒÄ鎸čndžîűdžěű‹F‰†úű‹F‰†řűë˙†îű‹žúűƒ†úűƒ?tëě˙†ěű‹žřűƒ†řűƒ?uîdžčű‹†îű†ěű÷Žčű–üű‰†öű†îű†ěűVü;Âr$é苞ňűŠ˜‹žöűˆ˙†ňű˙†öűFü9†öűrHéǍ†üű‰†ôű‹Ř‹†îű‰ƒ†ôűdžđűë@†üű‹–öű+Љ–ćű‹žôű‹Â‰ƒ†ôű‹^‹‰†ňűƒF‹žňű€?u‘‹žöűĆ˙†öű˙†đű‹†đű;†îű|ś‹žôűǃ†ôűdžđűë`†üű‹–öű+Љ–ćű‹žôű‹Â‰ƒ†ôű‹^‹‰†ňűƒF‹žňű€?t Š˜‹žöűˆ˙†ňű˙†öűFü9†öűrݸů˙éG‹žöűĆ˙†öű˙†đű‹†đű;†ěű|–‹žôűǃ†ôű†üű‹–öű+Đ–čűJ‹Â™‹Žčű÷ů÷鉆ęű+ŔP†üűP˙v+ŔP˙śęű˙vč•ƒÄP¸;P+ŔPčǃÄ뎸č˜ĆFřĆFůĆFúĆFű+ŔPFřP˙v+ŔP¸P˙včUƒÄP¸;P+ŔPč‡ƒÄé—+ŔčW+ŔPPPPPP¸P+ŔPčiƒÄéy+Ŕč9+ŔPPPPP˙v¸P¸PčHƒÄéX+Ŕč˙v˙v¸P¸PčdƒÄé<¸čü+ŔPP˙vP˙v˙v¸P¸PčƒÄ‰Fúé¸čÔ‹FH‹ŘŃ㋇F ‰Fř‹FH‹ŘŃă‹F‰‡F ‹FŁj ƒ~tƒ~u‹F븜Łt ¸0P+ŔPč9ƒÄ‰Fú…Ŕ}éź‹FřëřPSQRVWU‹Ü‹Ÿ‹ĂKۋŸF ˙6h P˙ÓXh ]_^ZY[XĎ+ŔčE+ŔPPPPPP¸$P¸PčVƒÄéf¸č&+ŔPPPPPP¸P+ŔPč8ƒÄ‰Fú‹^Ąj ‰‹Fúé:+Ŕčű+ŔPP˙vP˙v˙v¸P¸PčƒÄé+Ŕč׋FŁj ‹F Łl ‹F Łn ‹FŁp ‹FŁr ‹FŁt ˙v˙včTƒÄéŢ+ŔčŸ˙v č}ƒÄ‹ř‰>j ‹FŁl ‹F Łn žp ƒ˙~ë‹^ Š˜‹ŢFˆ˙F ‹ÇO…Ŕuë˙v˙včƒÄ鐸čP‹FŁh ¸f P˙v莃ĉFú…Ŕuƒ>h |Ąh ë Ąh ÷ŘŁ~ ¸˙˙éV+Ŕ苞+öëF‹ßG€?u÷Dé:[U‹ěWV+ŕ;&r˙ăÇh Çj Çl Çp ¸f P¸PčÄéý˙fü^_]Ăšé šéšéU‹ě‹†‹žÍ ]ĂÚÚ/dev/tty?D /etc/rc/dev/tty0/dev/tty0/bin/sh/etc/ttys/dev/tty0Init can't open /etc/ttys /usr/bin/login/bin/login/bin/sh/usr/bin/shStack overflow  `.j h,‹Ó3ŔťĘ;š2h+ËŃů‰Ăâř‰Ě;҉Ę;ź2hč„'‹Řúş`ŽÚŽÂŽŇę`‹Ě;éÂ˙3Ŕ詊†´łUÍ]é¤2äÍĂ3ŔčÍé“3Ŕč„Çb.‹ž ‰>d.‹†3Ň÷6Ę;ŠĚĐÉĐɊč‹Â3Ň÷6Ě;Šđ ĘţÁŠÎ;‹žŠÁ† ţČ:Ě;~dž ŠŚ€ÄІ Ł`.Í€üu Ą`.2äb.‹6b.;6d.t ˙††é˙é [U‹ěWV+ŕ˙ăfü^_]Ă+Ŕčé˙ƒ~ u ¸ Pč.˙ƒÄ˙vč%˙ƒÄé×˙+ŔčČ˙č+˙*ä‹ř= uż WčÇ˙ƒÄ‹Çéˇ˙¸"č§˙F܉Fڃ~ t#ƒ~}‹V‹F÷Ú÷؃ډF‰V˙N ëÇF +ö+˙Ńćƒ~}FŃfŃV;v| +vƒFƒVGƒ˙ |ۋ^ڊ„Ţ.ˆ˙FÚ˙N ƒ~uƒ~t ëş˙vč>˙ƒÄ‹F ˙N …Ŕíƒ~ t‹^ÚĆ-˙FÚë˙Nڋ^ڊ˜Pč˙ƒÄFÜ9FÚwčéýţ+Ŕčîţƒ~t‹F- =^wAƒ~\t;˙včăţƒÄ¸ë*=tP= tZ¸0P¸P+ŔP¸P‹F*ä™RPčřţƒÄ ¸éŚţ¸\Pč§ţƒÄ‹F= t2=uş¸0PčŽţƒÄ¸ëŐ¸bëď¸nëę¸rëĺ¸tëŕ¸fë۸\ëÖ= tń= tâ=\tě놸č?ţ‹~ë¸ PčEţƒÄŠ˜Pč;ţƒÄG€=u銘= tŰ=%uŕG€=-uG€=0u¸0ë¸ ‰FřÇFúë‹Fúş ÷ę‰Fú‹ßGŠ˜-0FúŠ˜-0= vހ=luGŠ˜-a=wŠ˜- ˆŠ˜-A=w¸ë+Ŕ‰FöŠ˜=Xuéç~éN=Duéź~é =t"=Bt\=Cté(˙vö‹^ƒF˙7čqţƒÄ)Fú‹Fú˙Nú…Ŕé+˙˙vřč]ýƒÄëč˙vř˙vú+ŔP¸P‹^ƒF‹+ŇRPč|ýƒÄ ÇFúëÁ˙vř˙vú+ŔP¸P‹^ƒF˙w˙7ëŘ˙vř˙vú+ŔP¸ëź˙vř˙vú+ŔP¸ëŐ˙vř˙vú¸P¸ P‹^ƒF‹™ë ˙vř˙vú¸P¸ ëŹ˙vř˙vú+ŔP¸ év˙˙vř˙vú+ŔP¸돋^‹7ƒF€<ué3˙˙vö‹ŢFŠ˜Pč‘ýƒÄ)Fúëă=Ot=StĐ=Uu"˙vř˙vú+Ŕëž=bué˙=cuéŕţ=duéc˙Š˜Péöţ=oué8˙~×=st“=uuén˙=xuÝ˙vř˙vú+ŔP¸éßţé ü+ŔčüFP˙včÂýƒÄé ü+ŔčüűÇH2hÇHÇHÇHÇHÇH+˙‹ßŃăLJHGƒ˙|đÇ HÇ.HÇč;ÇHéľű+ŔčŚű‹ž‹ś‹ßGŠ˜‹ŢFˆƒnuďé”ű+Ŕč…ű˙v¸ď.Pče˙ƒÄ¸ó.Pč[˙ƒÄ¸˙˙Pč˛úƒÄékű+Ŕč\űƒ~| ƒ~ tƒ~ u¸éNű+Ŕëů+Ŕč;űƒ>$Hu¸ú.Pč˙ƒÄ+Ŕë ¸/Pč ˙ƒÄ¸é ű˙v¸ü.PčöţƒÄƒ>&HuÜč2ű‹đ‹ř=qtƒ˙Qu¸Pč5úƒÄëčű‹řWč{˙ƒÄ…ŔtđƒţntڃţNuŻëŸ+ŔčÄú+˙ë‹^€?8}‹Çş÷ę‹řŠ˜-0ř˙F‹^€?0}܋ÇéĄú+Ŕč’ú‹~¸/PčrţƒÄƒ>$Ht-¸/PčaţƒÄë&č˘úˆŠ˜Pč˙ƒÄ…ŔtĆ;~v¸é[ú+ŔëůGƒnuÔĆčsúPčŰţƒÄ…Ŕtňëܸč-úĄH‰Fú‹F+Ňš÷ń÷fŃŕH‹~úëǃÇ;>Hró‹Fúéú+Ŕčôůż‹^€?t&Š˜- =^wŠ˜ë¸?P¸ /Pč¸ýƒÄ˙FƒďuŇéĘů+Ŕčťů‹^ƒt"˙wčě˙ƒÄ¸/PčŒýƒÄ‹^‹Pčš˙ƒÄé—ů+Ŕčˆů‹ Hƒu ¸/Pčaýë˙6 HčŽ˙ƒÄ‹F=t=t'ƒ~t ¸-/Pč;ýƒÄéUů‹ H‹˙7¸/Pč&ýƒÄëً H‹˙7¸!/ëę¸č$ůżÇFúÇĚ;ÇĘ;čxř¸P˙6ô;¸P˙vúčrřƒÄ‹đ÷Ć˙t‹ÇO…ŔuÜ÷Ć˙tFÇĚ; ÇĘ;żč<ř¸P˙6ô;¸P˙vúč6řƒÄ‹đ÷Ć˙t‹ÇO…ŔuÜ÷Ć˙t ¸//PčýƒÄé¤ř¸ č”ř‹F+Ňš ŃŕŃŇâú‰Fô‰Vöƒ~u ‹F;Huéă‹FŁH‹Vö‹Fôš ŃúŃŘâú‹đÇFň‹Ć0H+҉Fř‰Vú…Ň|=˙˙v¸M/PčüƒÄ¸Pčp÷ƒÄ¸P˙6ô;‹Ć0HP˙vč„÷ƒÄ‹ř÷Ç˙twčj÷‹F+ŇRP9Vu¸’/븚/PW¸s/PčĚűƒÄ ¸P˙6ô;‹Ć0HP˙včA÷ƒÄ‹ř÷Ç˙t4ƒnňuşW‹F+ŇRP9Vu¸Č/ë¸Í/P˙6ä;¸˘/Pč‚űƒÄ ¸Ó/PčüƒÄé’÷+Ŕčƒ÷+ŔP+ҸRP˙v˙vč¨#PčŇţƒÄ˙v ˙v+ҸRP˙v˙včË#ô;Pč űƒÄéO÷+Ŕč@÷ƒ>$Hu ¸Ô/Pč¨űƒÄ~ t+ŔP+ҸRP˙v˙včM#PčwţƒÄ˙v +ҸRP˙v˙včs#ô;P˙včEűƒÄ¸P+ҸRP˙v˙vč#Pč;ţƒÄÇ HéÓö+ŔčÄöƒ~u‹Fë‹F P˙v˙vč–úƒÄé°ö¸Pč ö˙6Ň;¸î/PčúƒÄ¸PPFŹPčđűƒÄ…Ŕt FŹPčĺ!ƒÄŁŇ;˙6Ô;¸0PčRúƒÄ¸PPFŹPčĂűƒÄ…Ŕt FŹPč¸!ƒÄŁÔ;˙6Ö;¸0Pč%úƒÄ¸PPFŹPč–űƒÄ…Ŕt FŹPč‹!ƒÄŁÖ;˙6Ř;¸'0PčřůƒÄ¸PPFŹPčiűƒÄ…Ŕt FŹPč^!ƒÄŁŘ;˙6Ú;¸:0PčËůƒÄ¸PPFŹPč<űƒÄ…Ŕt FŹPč1!ƒÄŁÚ;˙6Ü;¸M0PčžůƒÄ¸PPFŹPčűƒÄ…Ŕt FŹPč!ƒÄŁÜ;˙6ŕ;˙6Ţ;¸`0PčmůƒÄ¸PPFŹPčŢúƒÄ…ŔtFŹPčÓ ƒÄŁŢ;‰ŕ;¸s0PčúƒÄ…Ŕt¸P¸Ň;P+ҸRPčřýƒÄë!¸z0PčńůƒÄ…Ŕté‡ţƒ>$Ht +ŔPčeôƒÄéő¸čőÇFřÇFúĄŇ;+Ňš ÷ń‹Ö;Ř;‹ř¸PĄÔ;HPčEüƒÄĆöC¸P¸öCP˙vú˙vřčýƒÄĆöCFřƒVúƒďuŮĄÚ;ŁĚ.¸ P¸ž.PĄÖ;Ř;+Ňš ŃŕŃŇâúƒŇRPč@ýƒÄ¸P¸öCPĄÚ;‹Ü;Óŕ+Ňš ŃŕŃŇâúRPčýƒÄ¸ P¸ž.PĄÚ;‹Ü;Óŕ+Ňš ŃŕŃŇâúRPčřüƒÄéAô¸Pč1ô¸“0PčřƒÄĄj.ŁÔ;˙6j.¸˝0PčřƒÄ¸PPFŹPčqůƒÄ…Ŕt FŹPčfƒÄŁÔ;ÇÜ;˙6Ü;¸Ô0PčÍ÷ƒÄ¸PPFŹPč>ůƒÄ…Ŕt FŹPč3ƒÄŁÜ;Ąl.ŁŇ;P¸đ0Pč÷ƒÄ¸PPFŹPčůƒÄ…Ŕt FŹPčƒÄŁŇ;ĄŇ;˙š ÓčŁÖ;ĄÔ;˙š ÓčŁŘ;ĄŇ;+Ňš ÷ń‹Ö;ƒÂŘ;Âş‹Ü;ÓâÂH‹Ü;ÓčŁÚ;ÇŢ;˙˙Çŕ;˙+ҸRP‹ŕ;ĄŢ;-ƒÚ‹Ü;+ö…Ű}÷֋˅ÉtŃúŃŘâúRPčAƒú|%=rĄÜ;™žť‹Č…ÉtŃăŃÖâú‰Ţ;‰6ŕ;Çâ;¸1PčźöƒÄÇ$Hč üÇ$H¸ 1Pčy÷ƒÄ…Ŕuč üë¸P¸Ň;P+ҸRPčVűƒÄčýéœň+Ŕčňƒ>,HtčLţë¸P¸Ň;P+ҸRPčçúƒÄƒ>*Htčźű>â;t ¸1PčÉöƒÄƒ>Ň; ¸41Pč¸öƒÄƒ>Ô;w ¸>1Pč§öƒÄƒ>Ö; ¸G1Pč–öƒÄƒ>Ř; ¸O1Pč…öƒÄƒ>Ú; ¸W1PčtöƒÄƒ>Ü;} ¸q1PčcöƒÄƒ>ŕ;|ƒ>Ţ;u ¸ˆ1PčIöƒÄé×ń¸čÇńĄŇ; š Óč‹ř>â;t ¸œ1Pč!öƒÄ9>Ö;} ¸ź1PčöƒÄ9>Ö;t!¸ó1P¸ň1PW¸Đ1PčšúƒÄ˙6Ö;¸ő1Pč^őƒÄĄÔ;˙š Óč‹ř9>Ř;} ¸2PčÍőƒÄ9>Ř;t!¸<2P¸;2PW¸2PčuúƒÄ˙6Ř;¸>2PčőƒÄĄÚ;;Ô;r ¸N2Pč“őƒÄƒ>Ü;r ¸h2Pč‚őƒÄƒ>Ü;~˙6Ü;¸€2PčáôƒÄĄŇ;+Ňš ÷ń‹Ö;ƒÂŘ;Âş‹Ü;ÓâÂH‹Ü;Óč‹ř9>Ú;} ¸Ł2Pč/őƒÄ9>Ú;tW¸˝2Pč’ôƒÄ˙6Ú;¸é2Pč„ôƒÄÇFř˙˙ÇFú˙+ҸRP‹Vú‹Fř-ƒÚ‹Ü;+ö…Ű}÷֋˅ÉtŃúŃŘâúRPč•ƒú|#=rĄÜ;™žť‹Č…ÉtŃăŃÖâú‰^ř‰vú‹ŕ;ĄŢ;;Vúu;Fřt"˙vú˙vř¸ř2PčôƒÄ˙6ŕ;˙6Ţ;¸3PčďóƒÄé đ+Ŕčúď¸P˙vč˝őƒÄ‹ř ‹Çéěď+ŔčÝď‹v+˙ë#¸PV‹F+Ňš ŃŕŃŇâúRPč6řƒÄG˙FĆ;~|؋^éŽď+ŔčŸď‹v+˙ë#¸PV‹F+Ňš ŃŕŃŇâúRPč;řƒÄG˙FĆ;~|Řéwď+Ŕčhďë!‹F%ş‹ČÓâ‹FšÓčŃŕF‹Ř ˙F÷Fu؋FšÓčŃŕF‹ř‹Fš ÓŕŃŕF‹đë ‹ßƒÇÇ˙˙;ţróéď+Ŕč ď˙6Ö;č˙ƒÄŁę;˙6Ř;čöţƒÄŁî;˙6Ö;čéţƒÄŁě;˙6Ř;čÜţƒÄŁđ;˙6Ö;čĎţƒÄŁň;éĎî+ŔčŔî鑋F3FŠt>‹^ ˙‹™š÷ů…Ňu-‹^ƒ?t%ƒ>$Htƒ>&Hu¸,3PčDóƒÄ…Ŕt ‹^Çë?‹^ƒ?t7÷Ft÷Fu ˙v˙v ¸>3ë÷Fu÷Ft˙v˙v ¸P3Pč"ňƒÄŃnŃn˙F‹F Ftéd˙é(î¸čî‹~‹vÇFúÇFřƒ>,Ht˙v ˙v ˙včQţƒÄéś˙v¸c3PčĎńƒÄ˙v ˙v ˙včôýƒÄ‹;tFúPFřP˙v˙v˙4˙5čóţƒÄ ƒÇƒĆƒF‹F;FrЃ>$Htƒ>&Htƒ~úu ¸t3PčrńƒÄƒ~řƒ~ř ~ ˙vř¸z3PčYńƒÄƒ~řt¸Œ3PčňƒÄ…Ŕt˙v ˙v ˙vč¨ýƒÄƒ~ř~ ¸ž3Pč&ńƒÄé@í¸č0íżƒ>,HtéѸ 3PčńƒÄ‹Ç%ş‹ČÓâ‹ÇšÓčŃŕę;‹Ř‹#Đt鏸PFúPE˙+ŇšŃŕŃŇâú‹Ö;_Ř;+öš ŃăŃÖâúĂÖRPč8őƒÄƒ~útQW¸ľ3Pč™đƒÄ¸Ď3PčeńƒÄ…Ŕt8¸ P¸öCPE˙+ŇšŃŕŃŇâú‹Ö;_Ř;+öš ŃăŃÖâúĂÖRPč$őƒÄG;>Ň;wéC˙¸×3Pč?đƒÄéYě+ŔčJě¸PĄŇ;@Pč ňƒÄŁöGé?ě¸ č/ěƒ>č;t¸Ů3Pč đƒÄÇč;¸ PFÜP‹F-+ŇšŃŕŃŇâú‹Ö;_Ř;+öš ŃăŃÖâúĂÖRPčXôƒÄŠF阋öGV‹ÚĄöGF‹ŘŠ˜PŠFé˜P˙v¸ě3PčďƒÄ¸ř3PčiđƒÄ…ŔtWĄöGF‹ŘŠ˜ˆFé…Ŕu ¸4Pč˙ďƒÄ¸ PFÜP‹F-+ŇšŃŕŃŇâú‹Ö;_Ř;+öš ŃăŃÖâúĂÖRPč ôƒÄéRë+ŔčCëżëĄöGNj؀?tWčůţƒÄG;>Ň;vćƒ>č;u ¸4PčďƒÄéë+Ŕč ë‹F‹NÓčŠt¸4ë¸ 4PčÜîƒÄ‹F‹NÓčŠt¸"4ë¸$4PčŔîƒÄ‹F…Ft˙v ¸&4PčŤîƒÄë‹F‹NÓčŠt¸)4ë¸+4PčîƒÄé§ę+Ŕč˜ęƒ>.HtÇ.H¸-4PčnîƒÄ˙v¸Q4PčaîƒÄ‹^‹%đ=€uéŞ= uéŽ=@ué =`u餸^4Pč/îƒÄ¸sP¸P¸P‹^˙7č˙ƒÄ¸sP¸P¸P‹^˙7č˙ƒÄ¸tP¸P+ŔP‹^˙7čńţƒÄ‹^ŠG ˜P¸`4PčŮíƒÄ‹^‹%đ= t==`t8˙w˙w¸q4PčˇíƒÄ¸P+ŔPč3đƒÄéÄé¸V4ék˙¸X4ée˙¸Z4é_˙¸\4éY˙‹^‹G+ÉÓč*äP‹GšÓč*äP¸f4ë´¸čé‹^‹%ş‹ČÓ⋚ÓčŃŕě;‹Ř ¸v4PčîƒÄ…Ŕt@‹^‹öG‹ŘţÇFřřG‹F‰FöÇFúë‹^řŠ˜‹^öˆ˙Fř˙Fö‹Fú˙Nú…Ŕuĺ¸éé+Ŕëů+Ŕčé‹^ ‹;F uéҋĂP¸…4PčŘěƒÄ+ŔP¸PčTďƒÄ‹^ ˙7‹ĂP¸4PčśěƒÄ˙v ¸¤4PčŠěƒÄ‹F%ş‹ČÓâ‹FšÓčŃŕě;‹Ř ‹^ ‹%ş‹ČÓ⋚ÓčŃŕě;‹Ř ‹F %ş‹ČÓâ‹F šÓčŃŕě;‹Ř ¸ł4PčíƒÄ…Ŕuéڋ^ ‹öG‹Řţ‹^ ‹F ‰ĄöGF ‹Řţ+Ŕé3č‹^ €t¸ë+Ŕ+Ň9Vu9Fué—˙v˙v‹F P¸ź4PčŕëƒÄ+ŔP¸Pč\îƒÄ‹^ ˙7‹ĂP¸Ú4PčžëƒÄ‹F%ş‹ČÓâ‹FšÓčŃŕě;‹Ř ‹^ ‹%ş‹ČÓ⋚ÓčŃŕě;‹Ř ‹F %ş‹ČÓâ‹F šÓčŃŕě;‹Ř ¸éA˙+Ŕčhçż‹F‹đ€<t顸ď4Pč8ëƒÄ+ŔPPčˇíƒÄ‹F%ş‹ČÓâ‹FšÓčŃŕě;‹Ř ˙vč—ýƒÄ…Ŕufëu¸5PčöęƒÄ+ŔP¸PčríƒÄ‹F%ş‹ČÓâ‹FšÓčŃŕě;‹Ř ¸&5PčŔęƒÄ‹FPčĐěƒÄ¸05PčŠęƒÄ˙vč1ýƒÄ…Ŕt+Ŕë€<t ‹ŢF€?/t‹ƒďuî¸éć¸čć‹^ ƒ?r ‹;Ň;wéÖ¸35Pč]ęƒÄ+ŔP¸PčŮěƒÄ‹^ ˙7¸Q5PčAęƒÄ¸b5Pč7ęƒÄ‹F PčGěƒÄ¸k5Pč ęƒÄ¸n5PčěęƒÄ…ŔuéiÇFúřG‹F ‰FřÇFöë‹^úŠ˜‹^řˆ˙Fú˙Fř‹Fö˙Nö…Ŕuĺ+Ŕéi‹^ ˙7¸}5PčÎéƒÄ¸—5PčÄéƒÄ‹F PčÔëƒÄ¸­5Pč­éƒÄ¸P+ŔPč)ěƒÄ˙v č(üƒÄ…Ŕt믋^ ‹öG‹ŘŠ˜=tĄ‹^ ‹öG‹Řţ¸˝5P‹F PčrƒÄ…ŔuA‹ H€O˙v˙v ˙v˙v˙včHüƒÄ éȋ H€Oƒ~u‹Fë ‹ H‹_‹‹Pëʸż5P‹F PčƒÄ…ŔtĘ˙v ˙včŁýƒÄ…ŔuUé˙¸Â5PčéčƒÄ+ŔP¸PčeëƒÄ¸ă5PčŇčƒÄ‹F PčâęƒÄ‹^ ˙7¸ě5PčśčƒÄ˙v č>űƒÄ…ŔtéÄţ¸ë-‹^ ‹%ş‹ČÓ⋚ÓčŃŕň;‹Ř‹#ĐuŠ˙v č’ƒÄéŽä¸ č~下Ü;ÓŕšÓŕ‹đ‹F ‹Ü;Óŕ+Ňš ŃŕŃŇâú‰†öţ‰–řţ¸P†üţP˙śřţ˙śöţčśěƒÄdžúţ†üţ‹řFü;řré‹^‹W‹G+FV …Ňc|=s\¸ý5PčîçƒÄ+ŔP¸PčjęƒÄ¸6Pč­čƒÄ…ŔuéϋF%ş‹ČÓâ‹FšÓčŃŕě;‹Ř ‹^‹V ‹F‰G‰Wdžúţƒ=tW˙v ˙v˙vč ýƒÄ…Ŕudžúţ‹^‹W‹G‰†ňţ‰–ôţƒFƒV ‹V ‹F;–ôţ|[;†ňţrSƒžúţt¸P†üţP˙śřţ˙śöţčěƒÄ†öţƒ–řţƒît‹^‹V ‹F;W}éŇţ;GséČţ¸éă+ŔëůƒÇéŰţ+Ŕčă˙v¸!6PčĺćƒÄ+ŔP¸PčaéƒÄ˙v¸-6PčËćƒÄ‹F=t'=t'=t'¸d6PčŻćƒÄ˙v ˙v ¸r6PčŸćƒÄéšâ¸?6ëá¸D6ëܸT6ë×+Ŕč›â‹F+Ú;@‹ř‹^Ńă˙‡H‹F;Ú;r;Ô;rI˙v ˙v ˙v˙v¸6Pč\˙ƒÄ +Ŕ鮋Ç%ş‹ČÓâ‹ÇšÓčŃŕđ;‹Ř ˙v ˙v ˙v˙v¸Œ6ëƋÇ%ş‹ČÓâ‹ÇšÓčŃŕî;‹Ř‹#Đuą˙H‹Ç%ş‹ČÓâ‹ÇšÓčŃŕđ;‹Ř‹#ĐtW˙v ˙v ˙v˙v˙v¸–6PčÉţƒÄ‹Ç%ş‹ČÓâ‹ÇšÓčŃŕî;‹Ř ¸éˇá¸č§áż‹F ‹Ü;Óŕ+Ňš ŃŕŃŇâú‰†řţ‰–úţ¸P†üţP˙śúţ˙śřţčěéƒÄ‹F HP¸€P†üţP˙v˙v˙vč×ƒÄ …Ŕu+ŔéU၆řţƒ–úţƒďt‹^‹W‹‹^;W|Ł;Grœ¸ëѸčḋÜ;Óŕ™‰FřżÁÂĂÄĹĆljVúƒ~t+ҸRPFřPčŻ ƒnuě‹Vú‹Fřéđŕ+Ŕčáŕƒ~ uD‹^‹%đ=@u ˙v ‹^˙w˙7˙v˙vč6üƒÄ …Ŕu+Ŕé¸ŕ¸‹Ü;Óŕ™‹^W¸ëć˙v ˙v ˙v˙v˙včŘţƒÄ ëϸčzŕż+öéƋ^‹W‹G‰Fř‰Vú‹^‹W‹;Vú~éŻ|;Fřr饋ĆŃŕF ‹Řƒ?u$˙vč˙ƒÄ‰Fř‰Vú‹^‹W‹FřVú‰‰Wëj‹^˙w˙7˙v‹ĆŃŕF ‹Ř˙7˙vč[ýƒÄ …Ŕu$˙včĎţƒÄ‰Fř‰Vú‹^‹W‹FřVú‰‰Wë!˙v‹ĆŃŕF ‹Ř˙7˙v˙v˙včĐţƒÄ …Ŕu+˙F;v }é2˙‹ÇéŠß¸č™ßÇFöÇFř+ŔP¸P‹FPFöP˙v˙včôţƒÄ ‹řžÇFú˙vú¸P‹F‹ÖŃâÂPFöP˙v˙včĆţƒÄ …Ŕu+˙F˙Fúƒţ |͋Çé9ß+Ŕč*ߋF%ş‹ČÓâ‹FšÓčŃŕň;‹Ř ‹^ƒ|!ˆv¸œ6PčÜâƒÄ¸P¸PčWĺƒÄ˙v˙vč9˙ƒÄ‹ř‹ HŠG˜Šu¸ś6PčŠâƒÄ¸P¸Pč$ĺƒÄ+˙‹ HŠG˜Šu¸Ä6Pč‚âƒÄ¸P¸PčýäƒÄ+˙‹ÇéŠŢ+Ŕč{ދ^‹%đ=€t>= tc=@tF=`tP˙H¸Ó6Pč>âƒÄ+ŔP¸PčşäƒÄ‹^˙7¸ŕ6Pč"âƒÄ+Ŕé:Ţ˙H˙v˙vč„ţƒÄëë˙H˙v˙včâţëě˙H¸ëÓ˙Hëő+Ŕčű݃~u3‹^‹%đ=@t&¸ë6PčËáƒÄ‹^˙7˙v¸ 7PčšáƒÄ¸!7Pč;âƒÄ‹^€ u¸"7PčœáƒÄ+ŔP¸PčäƒÄ+Ŕé§Ý˙H‹F%ş‹ČÓâ‹FšÓčŃŕę;‹Ř ‹^ŠG ˜=vU¸67PčQáƒÄ+ŔP¸PčÍăƒÄ‹^ŠG ˜P¸M7Pč2áƒÄĄöGF‹Ř€/‹F%ş‹ČÓâ‹FšÓčŃŕě;‹Ř ë‹^ŠG ˜‹öGV‹Ú(˙v˙vč~ţƒÄéX˙¸0čň܋^‹?‹F‰FÖĄ H‰F؍FÖŁ H‹Ç%ş‹ČÓâ‹ÇšÓčŃŕě;‹Ř‹#ĐtW¸X7PčœŕƒÄ¸P+ŔPčăƒÄ‹Ç%ş‹ČÓâ‹ÇšÓčŃŕę;‹Ř‹#Ћň…öt ƒ>(HuéAĄÖ;Ř;+Ňš ŃŕŃŇâú‰F̉Vθ PFÜPE˙+ŇšŃŕŃŇâúFĚVÎRPčŻäƒÄƒ>(Ht FÜPWčˆńƒÄ…ötééFÜPWčţƒÄ…Ŕté׋Ç%ş‹ČÓâ‹ÇšÓčŃŕě;‹Ř ¸i7PčĽŕƒÄ…Ŕu驊Fé˜H‹öG׋Ú‹Ç%ş‹ČÓâ÷ҋǹÓčŃŕę;‹Ř!ĄÖ;Ř;+Ňš ŃŕŃŇâú‰F̉Vθ P¸öCPE˙+ŇšŃŕŃŇâúFĚVÎRPč,äƒÄÇFÔřG‹F‰FŇÇFĐë‹^Ԋ˜‹^҈˙FÔ˙FҋFĐ˙NЅŔuĺ‹ H‹GŁ H+Ŕé<ۋ H‹GŁ H¸ëî¸čۃ>,HuĄŇ;ŁHĄÔ;+Ú;@ŁHÇFěĆFîFěPčýýƒÄ…Ŕu ¸p7Pč]߃ĸ7PčÇރÄéáÚ+ŔčŇÚ¸P¸7PčąŢƒÄ¸‹Ü;ÓŕP¸™7PčŢƒÄ¸Ş7Pč“ŢƒÄ¸Ä7P¸Ă7P˙6H¸Ź7PčĘăƒÄ¸Ű7P¸Ů7P˙6H¸Ć7Pč´ăƒÄ¸ý7P¸ü7P˙6H¸ß7PčžăƒÄ¸!8P¸ 8P˙6H¸˙7PčˆăƒÄƒ>Ht¸88P¸78P˙6H¸#8PčkăƒÄ¸P8P¸O8P˙6H¸:8PčUăƒÄ¸g8P¸f8P˙6H¸R8Pč?ăƒÄé Ú+Ŕčýك>&Huƒ>,HtÇ$H‹FŁć;čßÝčKçč ččÉę˙6Ö;ĄŇ;@P˙6ę;čZęƒÄ˙6Ř;ĄÔ;+Ú;@P˙6î;čCęƒÄč[íč„ţ¸i8P˙6Ô;˙6Ř;ĄÖ;PĄÚ;HP˙6đ;˙6î;čfëƒÄč6î¸n8PĄŇ;@P˙6Ö;¸P+ŔP˙6ě;˙6ę;čAëƒÄč#ěčţƒ> Ht ¸t8Pč2݃ÄéLٸč<Ů+˙+öÇFúƒ>f.tĄĚ;Łh.Çf.ƒ>Ě; |ƒ>Ę;} ¸ 8Pčő܃ÄÇô;ö;Çä;ź8¸Á8Pčß܃ĸĆ8PčŐ܃ĸÝ8PčË܃ĸ9PčÁ܃ĸU9PčˇÜƒÄ¸ 9Pč­ÜƒÄ¸í9PčŁÜƒÄ¸:Pč™ÜƒÄč؉Fř*ä‰FöP¸:PčƒÜƒÄÇ0HÇĐ;ÇÎ;‹Fö==uéç=fué„=ht=luéŠ=mu饸|:é]˙č΃>Đ;}¸€ë¸ŁÎ;ÇĘ;DÇĚ;¸n.P¸:Pč܃Äč …Ŕ}é+˙Ç$H˙vúVW¸:Pč ţƒÄÇ,HÇ*HÇ(HÇ$Héűţ¸n.P¸2:PčĚۃÄč˛Ţ뽸n.P¸J:PčšŰƒÄÇ*HÇ(Hč“Ţ뤸b:PčžŰƒÄč„ŢÇ,Hƒ>Ě;uŠÇj.°Çl.˙é{˙‹FřšÓř*äé×¸č׸˜:PčbۃÄë&éz׃>Đ;H€~ű1|B€~ű9<€~ű5t6ŠFű˜-0ŁĐ;č°ÖˆFűŠFű˜P¸ç:Pč%ۃÄ€~ű u¸ę:Pčۃă>Đ;ŽÇĐ;뚸&č×ÇFö˙Föƒ~ö~¸ě:Pččڃĸ˙˙é˙Ö¸P˙6ô;+ŔPPč]փĉFúŠ˙uÍÇFřéë‹FřšÓŕô;‹ŘЇĆ˜*䙉Fâ‰Vä‹FřšÓŕô;‹ŘЇÇ˜*䙉FމVŕ‹FřšÓŕô;‹ŘЇČ˜*䙉FډV܋FřšÓŕô;‹ŘЇÉ˜*䙉F։VŘšŃŕŃŇâú‹v܋^ÚšŃăŃÖâú à ֋vŕ‹^ŢšŃăŃÖâú Ă Ö Fâ Vä^ć‹vřšÓćމ‰WFć‹VřšÓâ‹؃|?˙˙v¸;PčâكĸPč9ՃÄ˙Fřƒ~ř}é ˙ƒ>Đ;|ĄĐ;-ëĄĐ;‰FřFćPč8ƒÄFć‹VřJšÓâ‹؋W‹Ł0H+Ňš÷ń…Ňt Ą0H+Ň÷ń@ŃŕŁ0H+Ŕé“ţ¸č…Ő‹ž+öÇFú霋FúšÓŕNj؃uƒ?u‹Fú@šÓŕNj؃uRƒ?uM‹Fú@šÓŕNj؋W‹‰Fö‰Vř‹FúšÓŕNj؋W‹;Vř|<;Föv5‹Fú@šÓŕNj؃uƒ?t‹Fú@šÓŕÇP‹FúšÓŕÇPčƒÄ˙Fúƒ~ú}é[˙Fƒţ}éJ˙éĐÔ¸čŔԋž‹ś‹U‹‰Fř‰Vú‹T‹‰‰U‹Vú‹Fř‰‰TéŸÔ¸ čŽÔ‹žÇFřÇFúÇFöëGŠ˜‹ŘЇI;˜Šuđ€=-u2GÇFöë*+Ҹ RPFřPč‹Ć+҉Fň‰Vô‹Vú‹FřFňVô‰Fř‰Vú‹ßGŠ˜-0‹đ= rƃ~öt‹Vú‹Fř÷Ú÷؃ÚéԋVú‹Fřëő+Ŕč˙Ӌž‹śŠ˜ŠšÓâÓú;ÂtŠ˜ŠšÓâÓú+Âë+ŔéÜӀ=töGFëŇU‹ěW+˙‹V‹F‹^ ‹N…Ňy ÷Ú÷؃Ú÷ׅŰy ÷Ű÷كŰ÷×č{…˙t÷Ú÷؃Ú_]ÂU‹ěW+˙‹V‹F‹^ ‹N…Ňy ÷Ú÷؃Ú÷ׅŰy÷Ű÷كŰč=‹Ó‹Á…˙t÷Ú÷؃Ú_]ÂU‹ě‹^‹F÷g‹Č‹G÷fȋF÷gщG‰W]Â…Űu‹Ř‹Â+Ň÷ń“÷ń‹Ę‹Ó+ŰĂUWV+˙„˙u&GWŠűŠÝŠé*ɋéŠč*ɊĊâŠÖ*öRPQ‹Í;Ór ¸˙˙ë WWRP‹Â+Ň÷ó‹č÷á_+řƒŇ‹ň‹Ă÷ĺƃŇ^+đƒŇX+Ây Můóëô‹Ď‹Ţ_…˙tŠÍŠëŠßŠř‹Ĺ+Ň^_]Ă h_Answer questions with y or n. Then hit RETURN...íA 0123456789ABCDEF%s fatal %s? yes --> %c// (ino = %u, (ino = %u) can't determine diskette-typeFsck cannot read beyond sector 65535 error 0x%x %s block %D, retry readingwriting%s: can't %s block %D (error = 0x%x) readwriteinternal error (devwrite)ninodes = %unzones = %uimap_blocks = %uzmap_blocks = %ufirstdatazone = %ulog_zone_size = %umaxsize = %Uok nowDo you want to try againHit RETURN key to select default values # zones (default: %d) log zonesize (default: %d) #inodes (default: %u) is this okbad magic number in super blockno inodesno zonesno imapno zmapfirst data zone too smallzone size < block sizemax. file size <= 0bad magic number in super blocktoo few imap blockswarning: expected %d imap_block%ss instead of %d too few zmap blockswarning: expected %d zmap_block%ss instead of %d first data zone too largelog_zone_size too largewarning: large log_zone_size (%d) first data zone too smallwarning: expected first data zone to be %d instead of %u warning: expected max size to be %D instead of %D stop this listing%s %u is missing %s %u is not free Checking %s map etc. %d errors found. install a new map Checking inode list mode inode %u not cleared. clear INODE NLINK COUNT %5u %5u %5u adjustinternal error (counterror) r-w-%cx- inode permission link size name %6u -dcb? %3u %2x,%2x %7D . remove entrybad %s in %s is linked to %u instead of %u). repairwarning: %s has offset %D in %s is linked to %u) null name found in found a '/' in entry of directory entry = '')bad inode found in directory ino found = %u, name = ''). remove entrytoo many links to ino %u discovered at entry '' in directory ...link to directory discovered in name = '', dir ino = %u)bad format in directory . truncate%s zone in zno = %u, type = DATASINGLE INDIRECTDOUBLE INDIRECTVERY INDIRECT, pos = %D) out-of-rangeduplicatefoundwarning: huge directory: . missing in .. missing in bad mode of mode = %o)root inode is not a directory (ino = %u, mode = %o) link count zero of link count too big in cnt = %u) found inode %u: removebad root inode blocksize = %5d zonesize = %5d %6u Regular file%s s%6u Director%s yies%6u Block special file%s s%6u Character special file%s s%6u Bad inode%s s%6u Free inode%s s%6u Free zone%s szoneinode----- FILE SYSTEM HAS BEEN MODIFIED ----- Bootblok gave bad tracksiz fsck Hit key as follows: = start MINIX (root file system in drive 0) f check the file system (first insert any file system diskette) l check and list file system (first insert any file system diskette) m make an (empty) file system (first insert blank, formatted diskette) h check hard disk file system # %c Checking hard disk. %s Checking diskette. %s Checking diskette. %s Making empty file system Illegal command disk(ette) Please enter partition number. Drive 0: 1-4, drive 1: 6-9, then hit RETURN: %c Disk errors. Can't read partition table Fsck can't handle partitions above sector 65535  AAAAAABBBBBB ...makefilebootblok.sfsck1.sl=/usr/lib CFLAGS = -F all: make init make bootblok make build make mkfs make fsck init: $l/libc.a init.s $l/head.s asld -o init $l/head.s init.s $l/libc.a $l/end.s @echo init done. # bootblok.s is the source of the MINIX boot block. The bootblock is the # first 512 bytes on the image file and on the boot diskette. When bootblok.s # is assembled, it generates a short binary file (less than 400 bytes) that # must be stripped of its header and copied to the file bootblok. The dd # command below does this. If everything has been done right, the bootblok # file should begin with the following 8 words, in hex: # c0b8 8e07 33d8 b8f6 2fe0 c08e ff33 00b9 # The exact procedure for going from bootblok.s to the binary file stripped of # its header is somewhat operating system dependent. Some assemblers make # an object (.s) file; others make an a.sut file directly. If your boot # diskette does not start out by printing 'Booting MINIX 1.0' the problem is # probably that you have not made a good boot block. bootblok: bootblok.s @asld bootblok.s @dd if=a.out of=bootblok bs=16w skip=1 count=16 2>/dev/null @rm a.out @echo bootblok done. build: build.s cc -o build build.s @echo build done. mkfs: mkfs.s cc -o mkfs mkfs.s @echo mkfs done. fsck: fsck.s fsck1.s @echo "Start linking fsck. /lib/cem will be removed to make space on RAM disk" asld -o fsck -T. fsck1.s fsck.s $l/libc.a $l/end.s @echo fsck done. Please restore /lib/cem manually. fsck.s: fsck.c cc -c -Di8088 -w -F -T. fsck.c # 'make image' combines the bootblock, kernel, memory manager, file # system, init and fsck into a single file, called image. Each of these pieces # appears in the image file just as the original does on the disk, except that # the header at the front is removed, and each piece is padded out to an # integral multiple of 16 bytes. Build also prints a message telling how big # the various pieces (except fsck) are. image: build bootblok kernel mm fs init fsck /etc/umount /dev/fd0 @getlf "Insert blank diskette in drive 0 and hit return" build bootblok kernel mm fs init fsck /dev/fd0 # 'make usr' builds a file system on a file called 'usr', and then # copies this file to the diskette (9 sectors per track). It builds the file # system using the program mkfs, which is functionally the same as the standard # UNIX mkfs program, except that sizes (in blocks) for block special files # must be provided. usr: mkfs proto.usr /etc/umount /dev/fd0 @getlf "Insert blank diskette in drive 0 and hit return" mkfs -dL /dev/fd0 proto.usr >log.usr user: mkfs proto.user /etc/umount /dev/fd0 @getlf "Insert blank diskette in drive 0 and hit return" mkfs -dL /dev/fd0 proto.user >log.user # 'make ram' builds the root file system on a file called 'ram'. This file # will be copied to the boot diskette when 'image' is made. During system boot # it is copied from 128K on the boot diskette to the RAM disk. ram: mkfs proto.ram rc /etc/umount /dev/fd0 @getlf "Insert blank disk in drive 0 and hit return" mkfs -dL /dev/fd0 proto.ram >log.ram # Make the distribution disks. disk5: mkfs proto.disk5 /etc/umount /dev/fd0 @getlf "Insert blank diskette in drive 0 and hit return" mkfs -dL /dev/fd0 proto.disk5 >log.disk5 disk6: mkfs proto.disk6 /etc/umount /dev/fd0 @getlf "Insert blank diskette in drive 0 and hit return" mkfs -dL /dev/fd0 proto.disk6 >log.disk6 disk7: mkfs proto.disk7 @rm -rf proto.a misc.a >/dev/null ar r proto.a proto.* ar r misc.a passwd rc ttys profile /etc/umount /dev/fd0 @getlf "Insert blank diskette in drive 0 and hit return" mkfs -dL /dev/fd0 proto.disk7 >log.disk7 disk8: mkfs proto.disk8 /etc/umount /dev/fd0 @getlf "Insert blank diskette in drive 0 and hit return" mkfs -dL /dev/fd0 proto.disk8 >log.disk8 disk9: mkfs proto.disk9 /etc/umount /dev/fd0 @getlf "Insert blank diskette in drive 0 and hit return" mkfs -dL /dev/fd0 proto.disk9 >log.disk9 at.ram: mkfs proto.at.ram if /etc/umount /dev/at0; then : ; else : ; fi @getlf "Insert blank diskette in drive 0 and hit return" mkfs -dL /dev/at0 proto.at.ram >log.at.ram at.usr: mkfs proto.at.usr if /etc/umount /dev/at0; then : ; else : ; fi @getlf "Insert blank diskette in drive 0 and hit return" mkfs -dL /dev/at0 proto.at.usr >log.at.usr at.disk4: mkfs proto.at.disk4 if /etc/umount /dev/at0; then : ; else : ; fi @getlf "Insert blank diskette in drive 0 and hit return" mkfs -dL /dev/at0 proto.at.disk4 >log.at.disk4 at.disk5: mkfs proto.at.disk5 if /etc/umount /dev/at0; then : ; else : ; fi @getlf "Insert blank diskette in drive 0 and hit return" mkfs -dL /dev/at0 proto.at.disk5 >log.at.disk5 at.disk6: mkfs proto.at.disk6 if /etc/umount /dev/at0; then : ; else : ; fi @getlf "Insert blank diskette in drive 0 and hit return" mkfs -dL /dev/at0 proto.at.disk6 >log.at.disk6 | When the PC is powered on, it reads the first block from the floppy | disk into address 0x7C00 and jumps to it. This boot block must contain | the boot program in this file. The boot program first copies itself to | address 192K - 512 (to get itself out of the way). Then it loads the | operating system from the boot diskette into memory, and then jumps to fsck. | Loading is not trivial because the PC is unable to read a track into | memory across a 64K boundary, so the positioning of everything is critical. | The number of sectors to load is contained at address 504 of this block. | The value is put there by the build program after it has discovered how | big the operating system is. When the bootblok program is finished loading, | it jumps indirectly to the program (fsck) which address is given by the | last two words in the boot block. | | Summary of the words patched into the boot block by build: | Word at 504: # sectors to load | Word at 506: # DS value for fsck | Word at 508: # PC value for fsck | Word at 510: # CS value for fsck | | This version of the boot block must be assembled without separate I & D | space. LOADSEG = 0x0060 | here the boot block will start loading BIOSSEG = 0x07C0 | here the boot block itself is loaded BOOTSEG = 0x2FE0 | here it will copy itself (192K-512b) DSKBASE = 120 | 120 = 4 * 0x1E = ptr to disk parameters final = 504 fsck_ds = 506 fsck_pc = 508 fsck_cs = 510 .globl begtext, begdata, begbss, endtext, enddata, endbss | asld needs these .text begtext: .data begdata: .bss begbss: .text | copy bootblock to bootseg mov ax,#BIOSSEG mov ds,ax xor si,si | ds:si - original block mov ax,#BOOTSEG mov es,ax xor di,di | es:di - new block mov cx,#256 | # words to move rep movw | copy loop | start boot procedure jmpi start,BOOTSEG | set cs to bootseg start: mov dx,cs mov ds,dx | set ds to cs xor ax,ax mov es,ax | set es to 0 mov ss,dx | set ss to cs i.e., stack in high core mov sp,#1536 | initialize sp to high core | initialize disk parameters mov ax,#atpar | tenatively assume 1.2M diskette seg es mov DSKBASE,ax seg es mov DSKBASE+2,dx | print greeting mov ax,#2 | reset video int 0x10 mov ax,#0x0200 | BIOS call in put cursor in ul corner xor bx,bx xor dx,dx int 0x10 mov bx,#greet call print | Determine if this is a 1.2M diskette by trying to read sector 15. xor ax,ax int 0x13 xor ax,ax mov es,ax mov ax,#0x0201 mov bx,#0x0600 mov cx,#0x000F mov dx,#0x0000 int 0x13 jnb L1 | Error. It wasn't 1.2M. Now set up for 360K. mov tracksiz,#9 | 360K uses 9 sectors/track xor ax,ax mov es,ax mov ax,#pcpar seg es mov DSKBASE,ax int 0x13 | diskette reset L1: | Load the operating system from diskette. load: call setreg | set up ah, cx, dx mov bx,disksec | bx = number of next sector to read add bx,#2 | diskette sector 1 goes at 1536 ("sector" 3) shl bx,#1 | multiply sector number by 32 shl bx,#1 | ditto shl bx,#1 | ditto shl bx,#1 | ditto shl bx,#1 | ditto mov es,bx | core address is es:bx (with bx = 0) xor bx,bx | see above add disksec,ax | ax tells how many sectors to read movb ah,#2 | opcode for read int 0x13 | call the BIOS for a read jb error | jump on diskette error mov ax,disksec | see if we are done loading cmp ax,final | ditto jb load | jump if there is more to load | Loading done. Finish up. mov dx,#0x03F2 | kill the motor mov ax,#0x000C out cli mov bx,tracksiz | fsck expects # sectors/track in bx mov ax,fsck_ds | set segment registers mov ds,ax | when sep I&D DS != CS mov es,ax | otherwise they are the same. mov ss,ax | words 504 - 510 are patched by build seg cs jmpi @fsck_pc | jmp to fsck | Given the number of the next disk block to read, disksec, compute the | cylinder, sector, head, and number of sectors to read as follows: | ah = # sectors to read; cl = sector #; ch = cyl; dh = head; dl = 0 setreg: mov si,tracksiz | 9 (PC) or 15 (AT) sectors per track mov ax,disksec | ax = next sector to read xor dx,dx | dx:ax = 32-bit dividend div si | divide sector # by track size mov cx,ax | cx = track #; dx = sector (0-origin) mov bx,dx | bx = sector number (0-origin) mov ax,disksec | ax = next sector to read add ax,si | ax = last sector to read + 1 dec ax | ax = last sector to read xor dx,dx | dx:ax = 32-bit dividend div tracksiz | divide last sector by track size cmpb al,cl | is starting track = ending track je set1 | jump if whole read on 1 cylinder sub si,dx | compute lower sector count dec si | si = # sectors to read | Check to see if this read crosses a 64K boundary (128 sectors). | Such calls must be avoided. The BIOS gets them wrong. set1: mov ax,disksec | ax = next sector to read add ax,#2 | disk sector 1 goes in core sector 3 mov dx,ax | dx = next sector to read add dx,si | dx = one sector beyond end of read dec dx | dx = last sector to read shl ax,#1 | ah = which 64K bank does read start at shl dx,#1 | dh = which 64K bank foes read end in cmpb ah,dh | ah != dh means read crosses 64K boundary je set2 | jump if no boundary crossed shrb dl,#1 | dl = excess beyond 64K boundary xorb dh,dh | dx = excess beyond 64K boundary sub si,dx | adjust si dec si | si = number of sectors to read set2: mov ax,si | ax = number of sectors to read xor dx,dx | dh = head, dl = drive movb dh,cl | dh = track andb dh,#0x01 | dh = head movb ch,cl | ch = track to read shrb ch,#1 | ch = cylinder movb cl,bl | cl = sector number (0-origin) incb cl | cl = sector number (1-origin) xorb dl,dl | dl = drive number (0) ret | return values in ax, cx, dx |-------------------------------+ | error & print routines | |-------------------------------+ error: push ax mov bx,#fderr call print | print msg xor cx,cx err1: mul 0 | delay loop err1 int 0x19 print: | print string (bx) movb al,(bx) | al contains char to be printed testb al,al | null char? jne prt1 | no ret | else return prt1: movb ah,*14 | 14 = print char inc bx | increment string pointer push bx | save bx movb bl,*1 | foreground color xorb bh,bh | page 0 int 0x10 | call BIOS VIDEO_IO pop bx | restore bx jmp print | next character disksec:.word 1 tracksiz: .word 15 | changed to 9 for 360K diskettes pcpar: .byte 0xDF, 0x02, 25, 2, 9, 0x2A, 0xFF, 0x50, 0xF6, 1, 3 | for PC atpar: .byte 0xDF, 0x02, 25, 2,15, 0x1B, 0xFF, 0x54, 0xF6, 1, 8 | for AT fderr: .asciz "Read error. Automatic reboot.\r\n" greet: .asciz "\rBooting MINIX 1.2. Copyright 1987 Prentice-Hall, Inc.\r\n" | Don't forget that words 504 - 510 are filled in by build. The regular | code had better not get that far. .text endtext: .data enddata: .bss endbss: ŐSTACKSIZE = 8192 .globl _main, _exit, _edata, _end, _putc, _getc, _reset_diskette, _diskio .globl csv, cret, begtext, begdata, begbss .globl _cylsiz, _tracksiz, _drive .text begtext: start: mov dx,bx | bootblok puts # sectors/track in bx xor ax,ax mov bx,#_edata | prepare to clear bss mov cx,#_end sub cx,bx sar cx,*1 st.1: mov (bx),ax | clear bss add bx,#2 loop st.1 mov _tracksiz,dx | dx (was bx) is # sectors/track add dx,dx mov _cylsiz,dx | # sectors/cylinder mov sp,#kerstack+STACKSIZE call _main mov bx,ax | put scan code for '=' in bx cli mov dx,#0x60 mov ds,dx mov es,dx mov ss,dx jmpi 0,0x60 | jmp to kernel _exit: mov bx,_tracksiz jmp start _putc: xor ax,ax call csv movb al,4(bp) | al contains char to be printed movb ah,#14 | 14 = print char movb bl,*1 | foreground color push bp | not preserved int 0x10 | call BIOS VIDEO_IO pop bp jmp cret _getc: xorb ah,ah int 0x16 ret _reset_diskette: xor ax,ax call csv push es | not preserved int 0x13 | call BIOS DISKETTE_IO pop es jmp cret | handle diskio(RW, sector_number, buffer, sector_count) call | Do not issue a BIOS call that crosses a track boundary _diskio: xor ax,ax call csv mov tmp1,#0 | tmp1 = # sectors actually transferred mov di,10(bp) | di = # sectors to transfer mov tmp2,di | di = # sectors to transfer d0: mov ax,6(bp) | ax = sector number to start at xor dx,dx | dx:ax is dividend div _cylsiz | ax = cylinder, dx = sector within cylinder movb cl,ah | cl = hi-order bits of cylinder rorb cl,#1 | BIOS expects hi bits in a funny place rorb cl,#1 | ditto movb ch,al | cx = sector # in BIOS format mov ax,dx | ax = sector offset within cylinder xor dx,dx | dx:ax is dividend div _tracksiz | ax = head, dx = sector movb dh,al | dh = head orb cl,dl | cl = 2 high-order cyl bits || sector incb cl | BIOS counts sectors starting at 1 movb dl,_drive | dl = drive code (0-3 or 0x80 - 0x81) mov bx,8(bp) | bx = address of buffer movb al,cl | al = sector # addb al,10(bp) | compute last sector decb al | al = last sector to transfer cmpb al,_tracksiz | see if last sector is on next track jle d1 | jump if last sector is on this track mov 10(bp),#1 | transfer 1 sector at a time d1: movb ah,4(bp) | ah = READING or WRITING addb ah,*2 | BIOS codes are 2 and 3, not 0 and 1 movb al,10(bp) | al = # sectors to transfer mov tmp,ax | al is # sectors to read/write push es | BIOS ruins es int 0x13 | issue BIOS call pop es | restore es cmpb ah,*0 | ah != 0 means BIOS detected error jne d2 | exit with error mov ax,tmp | fetch count of sectors transferred xorb ah,ah | count is in ax add tmp1,ax | tmp1 accumulates sectors transferred mov si,tmp1 | are we done yet? cmp si,tmp2 | ditto je d2 | jump if done inc 6(bp) | next time around, start 1 sector higher add 8(bp),#0x200 | move up in buffer by 512 bytes jmp d0 d2: jmp cret csv: pop bx push bp mov bp,sp push di push si sub sp,ax jmp (bx) cret: lea sp,*-4(bp) pop si pop di pop bp ret .data begdata: tmp: .word 0 tmp1: .word 0 tmp2: .word 0 .bss begbss: kerstack: .zerow STACKSIZE/2 | kernel stack ...makefilebootblok.sfsck1.sl=../lib CFLAGS = -O -DPCIX all: make init make bootblok make build make mkfs make fsck init: $l/libc.a init.o $l/head.o ld -o init $l/head.o init.o $l/libc.a $l/end.o @echo init done. # bootblok.s is the source of the MINIX boot block. The bootblock is the # first 512 bytes on the image file and on the boot diskette. When bootblok.s # is assembled, it generates a short binary file (less than 400 bytes) that # must be stripped of its header and copied to the file bootblok. The dd # command below does this. If everything has been done right, the bootblok # file should begin with the following 8 words, in hex: # c0b8 8e07 33d8 b8f6 2fe0 c08e ff33 00b9 # The exact procedure for going from bootblok.s to the binary file stripped of # its header is somewhat operating system dependent. Some assemblers make # an object (.o) file; others make an a.out file directly. If your boot # diskette does not start out by printing 'Booting MINIX 1.0' the problem is # probably that you have not made a good boot block. bootblok: bootblok.s as bootblok.s @strip a.out @dd if=a.out of=bootblok bs=16w skip=1 count=16 2>/dev/null @rm a.out @echo bootblok done. build: build.o cc -o build build.o @echo build done. mkfs: mkfs.o cc -o mkfs mkfs.o @echo mkfs done. mkfs.o: mkfs.c cc -c -O -DUNIX mkfs.c fsck: fsck.o fsck1.o @ld -o fsck fsck1.o fsck.o $l/libc.a @echo fsck done. fsck1.o: fsck1.s as -o fsck1.o fsck1.s # 'make image' combines the bootblock, kernel, memory manager, file # system, init and fsck into a single file, called image. Each of these pieces # appears in the image file just as the original does on the disk, except that # the header at the front is removed, and each piece is padded out to an # integral multiple of 16 bytes. Build also prints a message telling how big # the various pieces (except fsck) are. image: build bootblok ../kernel/kernel ../mm/mm ../fs/fs init fsck @build bootblok ../kernel/kernel ../mm/mm ../fs/fs init fsck image cp image /dev/fd0 # 'make usr' builds a file system on a file called 'usr', and then # copies this file to the diskette (9 sectors per track). It builds the file # system using the program mkfs, which is functionally the same as the standard # UNIX mkfs program, except that sizes (in blocks) for block special files # must be provided. usr: mkfs proto.usr mkfs -ld usr proto.usr >log.usr cp usr /dev/fd0 user: mkfs proto.user mkfs -ld user proto.user >log.user cp user /dev/fd0 # 'make ram' builds the root file system on a file called 'ram'. This file # will be copied to the boot diskette when 'image' is made. During system boot # it is copied from 128K on the boot diskette to the RAM disk. ram: mkfs proto.ram mkfs -ld ram proto.ram >log.ram cp ram /dev/fd0 disk5: mkfs proto.disk5 mkfs -ld disk5 proto.disk5 >log.disk5 cp disk5 /dev/fd0 disk6: mkfs proto.disk6 mkfs -ld disk6 proto.disk6 >log.disk6 cp disk6 /dev/fd0 disk7: mkfs proto.disk7 @rm -rf proto.a misc.a >/dev/null ar11 r proto.a proto.* ar11 r misc.a passwd rc ttys profile strip ../kernel/kernel ../mm/mm ../fs/fs init fsck mkfs -ld disk7 proto.disk7 >log.disk7 cp disk7 /dev/fd0 disk8: mkfs proto.disk8 mkfs -ld disk8 proto.disk8 >log.disk8 cp disk8 /dev/fd0 disk9: mkfs proto.disk9 mkfs -ld disk9 proto.disk9 >log.disk9 cp disk9 /dev/fd0 256.ram: mkfs proto.256.ram rc mkfs -ld 256.ram proto.256.ram >log.256.ram cp 256.ram /dev/fd0 256.usr: mkfs proto.256.usr mkfs -ld 256.usr proto.256.usr >log.256.usr cp 256.usr /dev/fd0 at.ram: mkfs proto.at.ram rc mkfs -ld at.ram proto.at.ram >log.at.ram cp at.ram /dev/fd0 at.usr: mkfs proto.at.usr rc mkfs -ld at.ram proto.at.ram >log.at.ram cp at.ram /dev/fd0 at.disk4: mkfs proto.at.disk4 rc mkfs -ld at.disk4 proto.at.disk4 >log.at.disk4 cp at.disk4 /dev/fd0 at.disk5: mkfs proto.at.disk5 rc mkfs -ld at.disk5 proto.at.disk5 >log.at.disk5 cp at.disk5 /dev/fd0 at.disk6: mkfs proto.at.disk6 rc mkfs -ld at.disk6 proto.at.disk6 >log.at.disk6 cp at.disk6 /dev/fd0 at.setup: mkfs proto.at.setup rc mkfs -ld at.setup proto.at.setup >log.at.setup cp at.setup /dev/fd0 ...dos2out.cbootblokbootblok.asmdiskio.asmfsck1.asmbatfiles.a/* dos2out - convert ms-dos exe-format to a.out format * december '85 * * * * * Description of file-structures: a.out .exe ------------------------- ------------------------- | header | | header | | | | + | +-----------------------+ | relocation | | text | | info | | + | +-----------------------+ | data | | | +-----------------------+ | | | relocation info | | text | +-----------------------+ | + | | symbol table | | data | +-----------------------+ | | | string table | | | +-----------------------+ +-----------------------+ For more information see MS-DOS programmers reference manual */ /* define the a.out header format (short form) */ /* define the formatted part of the header of an MS-DOS exe-file */ #define D_FMT_SIZE 28 /* size of formatted header part */ #define IS_EXE 0x5A4D /* valid linker signature; note that in a dump it shows as 4D 5A */ typedef struct d_reloctab { /* DOS relocation table entry */ unsigned int r_offset; /* offset to symbol in load-module */ unsigned int r_segment; /* segment relative to zero; real segment must now be added */ }; /* dos formatted part of the header */ typedef struct d_fmt_hdr { unsigned int ldsign; /* linker signature, 5A4Dh */ unsigned int last_page_size; /* size of last page */ unsigned int nr_of_pages; /* a page is 512 b */ unsigned int nr_of_relocs; /* nr of relocation items */ unsigned int hdr_size; /* header-size in *16b */ unsigned int min_free; /* min free mem required after prog */ unsigned int max_free; /* max free mem ever needed (FFFFh) */ unsigned int ss_seg; /* stack-segment; must be relocated */ unsigned int sp_reg; /* sp value to be loaded */ unsigned int chksum; /* neg. sum of all words in file */ unsigned int ip_reg; /* ip value (program entry-point) */ unsigned int cs_seg; /* offset of code-seg in load-module */ unsigned int reloc_table; /* start of reloc-table in hdr, 1Bh */ unsigned int overlay_num; /* overlay number - not used */ }; #define MAGIC0 0x01 /* magic number, byte 1 */ #define MAGIC1 0x03 /* and second byte */ #define A_SEP 0x20 /* seperate I&D flag */ #define A_EXEC 0x10 /* executable */ #define A_I8086 0x04 /* Intel 8088/86 cpu */ #define A_HDR_LEN 32 /* short form of header */ #define DOS 0xFFFF /* version for a.out is -1 */ typedef struct a_out_hdr { unsigned char a_magic[2]; /* magic number */ unsigned char a_flags; /* flags for sep I&D etc */ unsigned char a_cpu; /* cpu-type */ unsigned char a_hdrlen; /* length of header */ unsigned char a_unused; /* sic */ unsigned short a_version; /* version stamp */ long a_text; /* size of text segment in bytes */ long a_data; /* size of data-segment in bytes */ long a_bss; /* size of bss (stack) segment */ long a_entry; /* program entry-point */ long a_totb; /* other, eg initial stack-ptr */ long a_syms; /* symbol-table size */ /* END OF SHORT FORM */ }; /* bytes & words left to right? */ #define A_BLR(cputype) ((cputype&0x01)!=0) /* TRUE if bytes left-to-right */ #define A_WLR(cputype) ((cputype&0x02)!=0) /* TRUE if words left-to-right */ #include "/lib/C86/stdio.h" #define PH_SECTSIZE 512 /* size of a disk-block */ #define NOT_A_HDR_LEN (PH_SECTSIZE-A_HDR_LEN) /* complement */ #define FNAME 32 /* length of filename/path +1 */ unsigned char inbuf[PH_SECTSIZE]; unsigned char inbuf2[PH_SECTSIZE]; unsigned char outbuf[PH_SECTSIZE]; struct a_out_hdr *a_ptr= outbuf; struct d_fmt_hdr *d_ptr= inbuf; main (argc,argv) int argc; char *argv[]; { char *dptr, /* pointer to DOS-header */ *sptr, /* pointer to OUT-header */ in_name[FNAME], /* input filename */ out_name[FNAME]; /* output filename */ register int i; int in_cnt, /* # bytes read from input */ out_cnt, /* # bytes written to output */ block_cnt, /* # nr of bloks of load-module */ lastp_cnt, /* # bytes in last block */ inf, outf, /* filedescriptors */ print=0, /* switch: print information */ delete=0, /* delete exe file after processing */ sym, /* data-relocation symbol offset */ sym_blk, sym_off; /* load-module block & offset in blk */ long d_size, /* size of data-segment */ t_size, /* size of text-segment */ load_size; /* size of load-module in bytes */ /*================================================================ * process parameters *===============================================================*/ if (argc<2 || argc>3) { printf ("usage: dos2out [-pd] fname[.ext]\n"); exit (2); } while (--argc) switch (argv[argc][0]) { case '-': while (*++argv[argc]) switch (*argv[argc] & ~32) { case 'P' : print=1; break; case 'D' : delete =1; break; default : printf ("Bad switch %c, ignored\n",*argv[argc]); } break; default : /* make filenames */ dptr=in_name; sptr=out_name; while (*argv[argc] && *argv[argc]!='.') { *dptr++ = *argv[argc]; *sptr++ = *argv[argc]++; } /* is there an extension to the filename? */ if (*argv[argc]=='.') { while (*argv[argc]) *dptr++ = *argv[argc]++; *dptr=0; } else { *dptr=0; strcat(dptr,".exe"); } *sptr=0; strcat(sptr,".out"); } /* end switch */ /* open & create files */ if ((inf=open(in_name,BREAD)) <0) { printf ("input file %s not found\n",in_name); exit(2); } /* get first block and check conditions for conversion */ if ((in_cnt=read(inf,inbuf,PH_SECTSIZE))!=PH_SECTSIZE) { printf ("read %d bytes, should be %d - abort\n",in_cnt,PH_SECTSIZE); exit(2); } if (d_ptr->ldsign!=IS_EXE) { printf ("not a valid .exe file - stop\n"); exit(2); } if (d_ptr->nr_of_relocs>1) { printf ("Too many relocations - stop\n"); exit(2); } /* see documentation for explanation of this condition */ if (d_ptr->nr_of_relocs<1) { printf ("Exactly one relocation item required - can't process\n"); exit(2); } if (d_ptr->ip_reg) { printf ("Warning - program entry point not at zero\n"); } /* input file is ok, open output (possibly destroy existing file) */ if ((outf=creat(out_name,BWRITE)) <0) { printf ("cannot open output %s\n",out_name); exit(2); } /*========================= PROCESS FILE =============================*/ /* get reloc symbol's position in load-module */ sym = (int) inbuf[d_ptr->reloc_table+1] << 8; sym += (int) inbuf[d_ptr->reloc_table]; sym_blk = sym / PH_SECTSIZE; sym_off = sym % PH_SECTSIZE; /* get block with relocation symbol */ while (sym_blk>=0) { read(inf,inbuf2,PH_SECTSIZE); sym_blk--; } /* get symbol and calculate sizes */ t_size = inbuf2[sym_off+1] << 8; t_size+= inbuf2[sym_off]; t_size <<= 4; load_size = (d_ptr->nr_of_pages-2) * PH_SECTSIZE + d_ptr->last_page_size; d_size = load_size - t_size; /* reposition file */ close (inf); inf=open(in_name,BREAD); in_cnt=read(inf,inbuf2,PH_SECTSIZE); /* make a.out header */ a_ptr->a_magic[0] = MAGIC0; a_ptr->a_magic[1] = MAGIC1; a_ptr->a_flags = A_SEP; a_ptr->a_cpu = A_I8086; a_ptr->a_hdrlen = A_HDR_LEN; a_ptr->a_syms = 0; a_ptr->a_unused = 0; a_ptr->a_version = DOS; a_ptr->a_data = d_size; a_ptr->a_text = t_size; a_ptr->a_bss = (d_ptr->min_free<<4) - d_ptr->sp_reg; a_ptr->a_entry = d_ptr->ip_reg; a_ptr->a_totb = a_ptr->a_text + a_ptr->a_bss + a_ptr->a_data + d_ptr->sp_reg; if (print) printinfo(); /* void remainder of first block; it holds nothing */ /* determine nr of blocks to copy and copy them */ block_cnt = d_ptr->nr_of_pages-1; /* exclude header-block */ lastp_cnt = d_ptr->last_page_size; while (block_cnt--) { if ((in_cnt=read(inf,inbuf,PH_SECTSIZE))!=PH_SECTSIZE) if (block_cnt || (!block_cnt && in_cntnr_of_pages, d_ptr->nr_of_pages); printf (" bytes in last page: %4xh (%4d dec)\n", d_ptr->last_page_size, d_ptr->last_page_size); printf (" min. free mem *16: %4xh (%4d dec)\n", d_ptr->min_free, d_ptr->min_free); printf (" stack-size: %4xh (%4d dec)\n", d_ptr->ss_seg, d_ptr->ss_seg); printf (" stack-pointer val: %4xh (%4d dec)\n", d_ptr->sp_reg, d_ptr->sp_reg); printf (" program entry-point: %4xh (%4d dec)\n", d_ptr->ip_reg, d_ptr->ip_reg); printf (" code-segment val: %4xh (%4d dec)\n", d_ptr->cs_seg, d_ptr->cs_seg); printf ("\n\nOUT-header:\n"); printf (" text-size: %6lxh (%6ld dec)\n", a_ptr->a_text, a_ptr->a_text); printf (" data-size: %6lxh (%6ld dec)\n", a_ptr->a_data, a_ptr->a_data); printf (" bss-size: %6lxh (%6ld dec)\n", a_ptr->a_bss, a_ptr->a_bss); printf (" entry-point: %6lxh (%6ld dec)\n", a_ptr->a_entry, a_ptr->a_entry); printf (" totalbytes: %6lxh (%6ld dec)\n\n", a_ptr->a_totb, a_ptr->a_totb); } ¸ŔŽŘ3ö¸ŕ/ŽŔ3˙šóĽęŕ/ŒĘŽÚ3ŔŽŔŽĐź&Çxč&‰z¸3Ű3ŇÍťÔčm¸ťšž"3ŇSŢ[tr!ÍrH:.řt,ŢuşŽÂ¸ţĹąž$ëŐ°Ír'ť ŽĂ3۸ąž ëžşň¸ îúĄúŽŘŽŔŽĐ.˙.üPťŔčëţ.Š„ŔuĂ´CSłÍ[ëíread error Booting Minix 1.0 ß *˙Pöpage ,132 ; When the PC is powered on, it reads the first block from the floppy ; disk into address 0x7C00 and jumps to it. This boot block must contain ; the boot program in this file. The boot program first copies itself to ; address 192K - 512 (to get itself out of the way). Then it loads the ; operating system from the boot diskette into memory, and then jumps to fsck. ; Loading is not trivial because the PC is unable to read a track into ; memory across a 64K boundary, so the positioning of everything is critical. ; The number of sectors to load is contained at address 504 of this block. ; The value is put there by the build program after it has discovered how ; big the operating system is. When the bootblok program is finished loading, ; it jumps indirectly to the program (fsck) which address is given by the ; last two words in the boot block. ; ; Summary of the words patched into the boot block by build: ; Word at 504: # sectors to load ; Word at 506: # DS value for fsck ; Word at 508: # PC value for fsck ; Word at 510: # CS value for fsck ; ; This version of the boot block must be assembled without separate I & D ; space. LOADSEG = 0060h ; here the boot block will start loading BIOSSEG = 07C0h ; here the boot block itself is loaded BOOTSEG = 2FE0h ; here it will copy itself (192K-512b) DSKBASE = 120 ; 120 = 4 * 0x1E = ptr to disk parameters JMPI = 0EAh ; opcode for jmp inter-segment (far jmp) CODE SEGMENT ASSUME cs:CODE,ds:CODE ;-------------------------------+ ; bootblok ; ;-------------------------------+ ; ; copy bootblock to bootseg mov ax,BIOSSEG mov ds,ax xor si,si ; ds:si - original block mov ax,BOOTSEG mov es,ax xor di,di ; es:di - new block mov cx,256 ; # words to move rep movsw ; copy loop ; start boot procedure ; jmpi start,BOOTSEG ; set cs to bootseg DB JMPI ; normal MASM gets too complicated for this. DW OFFSET start ; Use a trick and pre-code the DW BOOTSEG ; instructions and addresses. start: ; start < 16 mov dx,cs mov ds,dx ; set ds to cs xor ax,ax mov es,ax ; set es to 0 mov ss,ax ; set ss to 0 mov sp,1024 ; initialize sp (top of vector table) ; initialize disk parameters mov ax,offset atpar mov es:DSKBASE,ax ; tentatively assume 1.2M diskette mov es:DSKBASE+2,dx ; print greeting mov ax,2 ; reset video int 10h mov ax,0200h ; BIOS call to move cursor to ul corner xor bx,bx xor dx,dx int 10h mov bx,offset greet call print ; Determine if this is a 1.2M diskette by trying to read sector 15. xor ax,ax int 13h xor ax,ax mov es,ax mov ax,0201h mov bx,0600h mov cx,000fh mov dx,0000h int 13h jnb L1 ; Error. It wasn't 1.2M. Now set up for 360K. mov tracksiz,9 ; 360K uses 9 sectors/track xor ax,ax mov es,ax mov ax,offset pcpar mov es:DSKBASE,ax int 13h ; diskette reset L1: ; Load the operating system from diskette. load: call setreg ; set up ah, cx, dx mov bx,disksec ; bx = number of next sector to read add bx,2 ; diskette sector 1 goes at 1536 ("sector" 3) shl bx,1 ; multiply sector number by 32 shl bx,1 ; ditto shl bx,1 ; ditto shl bx,1 ; ditto shl bx,1 ; ditto mov es,bx ; core address is es:bx (with bx = 0) xor bx,bx ; see above add disksec,ax ; ax tells how many sectors to read mov ah,2 ; opcode for read int 13h ; call the BIOS for a read jb error ; jump on diskette error mov ax,disksec ; see if we are done loading cmp ax,final ; ditto jb load ; jump if there is more to load ; Loading done. Finish up. mov dx,03F2h ; kill the motor mov ax,000Ch out dx,al cli mov bx,tracksiz ; fsck expects # sectors/track in bx mov ax,fsck_ds ; set segment registers mov ds,ax ; when sep I&D ds != cs mov es,ax ; otherwise they are the same. mov ss,ax ; This gets patched by 'build' jmp DWORD PTR cs:fsck_pc ; call the booted program ; its address is at 508 (dec) ; Given the number of the next disk block to read, disksec, compute the ; cylinder, sector, head, and number of sectors to read as follows: ; ah = # sectors to read; cl = sector #; ch = cyl; dh = head; dl = 0 setreg: mov si,tracksiz ; 9 (PC) or 15 (AT) sectors per track mov ax,disksec ; ax = next sector to read xor dx,dx ; dx:ax = 32-bit divident div si ; divide sector # by track size mov cx,ax ; cx = track #; dx = sector (0-origin) mov bx,dx ; bx = sector number (0-origin) mov ax,disksec ; ax = next sector to read add ax,si ; ax = last sector to read + 1 dec ax ; ax = last sector to read xor dx,dx ; dx:ax = 32-bit dividend div tracksiz ; divide last sector by track size cmp al,cl ; is starting cyl = ending cyl je set1 ; jump if whole read on 1 cylinder sub si,dx ; compute lower sector count dec si ; si = # sectors to read ; Check to see if this read crosses a 64K boundary (128 sectors). ; Such calls must be avoided. The BIOS gets them wrong. set1: mov ax,disksec ; ax = next sector to read add ax,2 ; disk sector 1 goes in core sector 3 mov dx,ax ; dx = next sector to read add dx,si ; dx = one sector beyond end of read dec dx ; dx = last sector to read shl ax,1 ; ah = which 64K bank does read start at shl dx,1 ; dh = which 64K bank foes read end in cmp ah,dh ; ah != dh means read crosses 64K boundary je set2 ; jump if no boundary crossed shr dl,1 ; dl = excess beyond 64K boundary xor dh,dh ; dx = excess beyond 64K boundary sub si,dx ; adjust si dec si ; si = number of sectors to read set2: mov ax,si ; ax = number of sectors to read xor dx,dx ; dh = head, dl = drive mov dh,cl ; dh = track and dh,1 ; dh = head mov ch,cl ; ch = track to read shr ch,1 ; ch = cylinder mov cl,bl ; cl = sector number (0-origin) inc cl ; cl = sector number (1-origin) xor dl,dl ; dl = drive number (0) ret ; return values in ax, cx, dx ;-------------------------------+ ; error & print routines ; ;-------------------------------+ ; error: push ax mov bx,offset fderr call print ; print msg xor cx,cx err1:mul bl ; delay loop err1 int 19h print: ; print string (bx), ax destroyed mov al,[bx] ; al contains char to be printed test al,al ; null char? jne prt1 ; no ret ; else return prt1: mov ah,14 ; 14 = print char inc bx ; increment string pointer push bx ; save bx mov bl,1 ; foreground color xor bh,bh ; page 0 int 10h ; call BIOS VIDEO_IO pop bx ; restore bx jmp print ; next character disksec DW 1 tracksiz DW 15 ; changed to 9 for 360K diskettes pcpar DB 0DFh, 2, 25, 2, 9, 02Ah, 0FFh, 050h, 0F6h, 1, 3 ; for PC atpar DB 0DFh, 2, 25, 2,15, 01Bh, 0FFh, 054h, 0F6h, 1, 8 ; for AT fderr DB "Read error. Please reboot ",0Dh,0Ah,0 greet DB "Booting Minix 1.1",0Dh,0Ah,0 ORG 504 ; NOTE: there will be no error reported if ; your code crosses this org-directive ! final DW 0 ; # sectors to read (patched in by build) fsck_ds DW 0 ; ds-value for sep I&D fsck_pc DW 0 ; build patches these locations to the fsck_cs DW 0 ; starting address of the booted program CODE ENDS END őTitle diskio - absolute disk read & write for MS-DOS page,132 ; ; int absread (disk,sector,&buffer) ; int disk, sector; ; char *buffer[PH_SECTSIZE]; ; and ; int abswrite (disk,sector,buffer) ; int disk, sector; ; char *buffer[PH_SECTSIZE]; INCLUDE \lib\C86\prologue.h PUBLIC absread, abswrite, dmaoverr disk equ [bp+4] sector equ [bp+6] buffer equ [bp+8] @CODE SEGMENT assume cs:@code,ds:dgroup ; These are the routines that do the DOS-interrupts; you can use ; them for any disk-drive in the system. ; absread PROC NEAR push bp mov bp,sp mov ax,disk mov bx,buffer mov cx,1 mov dx,sector int 25h ; abs disk-read jnc rd_ok ; carry ===> error in al xor ah,ah ; zero upper half inc al ; code 0 means something too jmp end_rd rd_ok: xor ax,ax ; no error end_rd: popf ; flags pushed by int pop bp ret absread ENDP abswrite PROC NEAR push bp mov bp,sp mov ax,disk mov bx,buffer mov cx,1 mov dx,sector int 26h ; abs disk-write jnc wr_ok xor ah,ah inc al jmp end_wr wr_ok: xor ax,ax end_wr: popf pop bp ret abswrite ENDP dmaoverr PROC NEAR ; dummy routine xor ax,ax ret dmaoverr ENDP @CODE ENDS END ; end of assembly file title fsck1 - additional stuff for fsck page,132 INCLUDE ..\lib\prologue.h ; Define STANDALONE if you need fsck to be part of Minix. STANDALONE EQU 1 XTSECTORS EQU 17 XTCYLS EQU 68 IFDEF STANDALONE PUBLIC $main, @end, edata, exit, kerstack,_prt EXTRN main:near ;EXTRN cinit:near, debug:near ENDIF PUBLIC reset_di, diskio, getc, putc, dmaoverr EXTRN cylsiz:word, tracksiz:word, drive:byte ;---------------------------------------+ ; Code | ;---------------------------------------+ ; @CODE SEGMENT assume cs:@code,ds:dgroup IFDEF STANDALONE $main: mov dx,bx ; bootblok puts # sectors/track in bx xor ax,ax mov bx,offset dgroup:edata ; prepare to clear bss mov cx,offset dgroup:@end sub cx,bx sar cx,1 st1:mov [bx],ax ; clear bss add bx,2 loop st1 mov dgroup:tracksiz,dx ; dx (was bx) is # sectors/track add dx,dx mov dgroup:cylsiz,dx ; # sectors/cylinder mov sp,offset dgroup:kerstack+STACKSIZE ; call cinit ; mov ax,offset fsckmsg ; push ax ; call debug ; pop ax call main mov bx,ax ; put scan code for '=' in bx cli mov dx,60h mov ds,dx mov es,dx mov ss,dx jmp far ptr kernel ; direct jmp to kernel & start Minix mov ax,DGROUP ; Force DOS-relocation (sep I&D) exit: mov bx,dgroup:tracksiz jmp $main _prt: push bp mov bp,sp push bx mov bx,[bp+4] call print pop bx pop bp ret print: ; print string (bx), ax destroyed mov al,[bx] ; al contains char to be printed test al,al ; null char? jne prt1 ; no ret ; else return prt1: mov ah,14 ; 14 = print char inc bx ; increment string pointer push bx ; save bx mov bl,1 ; foreground color xor bh,bh ; page 0 int 10h ; call BIOS VIDEO_IO pop bx ; restore bx jmp print ; next character ENDIF ; /* STANDALONE */ putc: xor ax,ax call csv mov al,4[bp] ; al contains char to be printed mov ah,14 ; 14 = print char mov bl,1 ; foreground color push bp ; not preserved int 10h ; call BIOS video-io pop bp jmp cret getc: xor ah,ah int 16h ret reset_di: ; reset_diskette xor ax,ax call csv push es ; not preserved int 13h ; call BIOS DISKETTE_IO pop es jmp cret ; handle diskio(RW, sector_number, buffer, sector_count) call ; Do not issue a BIOS call that crosses a track boundary diskio: xor ax,ax call csv mov tmp1,0 ; tmp1 = # sectors actually transferred mov di,10[bp] ; di = # sectors to transfer mov tmp2,di ; di = # sectors to transfer d0: mov ax,6[bp] ; ax = sector number to start at xor dx,dx ; dx:ax is dividend div dgroup:cylsiz ; ax = cylinder, dx = sector within cylinder mov cl,ah ; cl = hi-order bits of cylinder ror cl,1 ; BIOS expects hi bits in a funny place ror cl,1 ; ditto mov ch,al ; cx = sector # in BIOS format mov ax,dx ; ax = sector offset within cylinder xor dx,dx ; dx:ax is dividend div dgroup:tracksiz ; ax = head, dx = sector mov dh,al ; dh = head or cl,dl ; cl = 2 high-order cyl bits || sector inc cl ; BIOS counts sectors starting at 1 mov dl,dgroup:drive ; dl = drive code (0-3 or 0x80 - 0x81) mov bx,8[bp] ; bx = address of buffer mov al,cl ; al = sector # add al,10[bp] ; compute last sector dec al ; al = last sector to transfer cmp al,byte ptr dgroup:tracksiz ; see if last sector is on next track jle d1 ; jump if last sector is on this track mov word ptr 10[bp],1 ; transfer 1 sector at a time d1: mov ah,4[bp] ; ah = READING or WRITING add ah,2 ; BIOS codes are 2 and 3, not 0 and 1 mov al,10[bp] ; al = # sectors to transfer mov tmp,ax ; al is # sectors to read/write push es ; BIOS ruins es int 13h ; issue BIOS call pop es ; restore es cmp ah,0 ; ah != 0 means BIOS detected error jne d2 ; exit with error mov ax,tmp ; fetch count of sectors transferred xor ah,ah ; count is in ax add tmp1,ax ; tmp1 accumulates sectors transferred mov si,tmp1 ; are we done yet? cmp si,tmp2 ; ditto je d2 ; jump if done inc word ptr 6[bp] ; next time around, start 1 sector higher add 8[bp],200h ; move up in buffer by 512 bytes jmp d0 d2: jmp cret dmaoverr: ; test if &buffer causes a DMA overrun push bp mov bp,sp push bx push cx mov ax,ds mov cl,4 shl ax,cl mov bx,[bp+4] add ax,bx ; ax has absolute addres modulo 64K add ax,1023 ; add transfer size - 1 mov ax,0 jnc ok inc ax ; indicate error ok: pop cx pop bx pop bp ret csv: pop bx push bp mov bp,sp push di push si sub sp,ax jmp bx cret: lea sp,-4[bp] pop si pop di pop bp ret @CODE ENDS @DATAI SEGMENT tmp DW 0 tmp1 DW 0 tmp2 DW 0 fsckmsg DB "arrived at fsck1",0 @DATAI ENDS IFDEF STANDALONE ;---------------------------------------+ ; Set up memory lay-out for standalone | ;---------------------------------------+ ; STACKSIZE EQU 8192 LOWCORE SEGMENT AT 0 ; tell where BIOS-data etc is ORG 120 dskbase label word LOWCORE ENDS MINIX SEGMENT AT 60h ; This is where Minix is loaded kernel label byte ; absolute address 0000:1536d = 0060:0000h MINIX ENDS @DATAT SEGMENT ; DATAT holds nothing. The label tells us edata label byte ; where .data ends. @DATAT ENDS @DATAU SEGMENT ; allocate the stack in .bss kerstack DB STACKSIZE dup(?) @DATAU ENDS @DATAV SEGMENT ; DATAV holds nothing. The label tells us @end label byte ; where .data+.bss ends (first free memory) @DATAV ENDS @STACK SEGMENT BYTE STACK 'STACK' ; Satisfy DOS-linker @STACK ENDS ; (dummy stack-segment) ENDIF END ; end of assembly-file e˙_bootblo.batTŕ– ¤Šmasm bootblok,,nul,nul > bootblok.lst link bootblok,,nul,nul >>bootblok.lst exe2bin bootblok.exe bootblok.bin >>bootblok.lst del bootblok.exe >nul del bootblok.obj >nul _bootblok.batTŕ– ¤Ěmasm bootblok,,nul,nul > bootblok.lst link bootblok,,nul,nul >>bootblok.lst exe2bin bootblok.exe bootblok.bin >>bootblok.lst del bootblok.exe >nul del bootblok.obj >nul if "%batch%" == "MINIX" make minix _build.batTŕ– ¤‹if "%1" == "-l" goto link if exist diskio.obj goto cc masm diskio,,nul,nul >build.lst :cc if exist build.obj goto link cc1 -dMSDOS build >> build.lst if errorlevel 1 goto einde cc2 build >> build.lst if errorlevel 1 goto einde cc3 build >> build.lst if errorlevel 1 goto einde cc4 build >> build.lst if errorlevel 1 goto einde :link link/m build+diskio,,,\lib\c86\C86s2s.lib >> build.lst :einde _dos2out.batTŕ– ¤-if exist dos2out.obj goto link cc1 dos2out >> dos2out.lst if errorlevel 1 goto fout cc2 dos2out >> dos2out.lst if errorlevel 1 goto fout cc3 dos2out >> dos2out.lst if errorlevel 1 goto fout cc4 dos2out >> dos2out.lst if errorlevel 1 goto fout :link link/m dos2out,,,\lib\c86\C86s2s.lib >> dos2out.lst f_fsck.batTᖠ¤˛echo/ if "%1"=="-b" goto asm if "%1"=="-m" goto asm if "%1"=="-d" goto asm echo No switch specified for linkage. echo Switches are: echo -b link for boot-diskette echo -m link as a minix-program echo -d link as a dos-program echo Note that the appropriate symbol must be echo defined in both fsck.c and fsck1.asm echo Optionally you can specify '-l', which echo will only link fsck. goto eind :asm if "%2"=="-l" goto link if exist fsck1.obj goto c1 masm fsck1,,nul,nul >fsck.lst :c1 if exist fsck.obj goto link cc1 fsck >fsck.lst if errorlevel 1 goto fout cc2 fsck >>fsck.lst if errorlevel 1 goto fout cc3 fsck >>fsck.lst if errorlevel 1 goto fout cc4 fsck >>fsck.lst if errorlevel 1 goto fout :link if not "%1"=="-b" goto m echo Linking (boot version) link/m fsck1+fsck,fsck,fsck,..\lib\mxc86 >>fsck.lst dos2out -d fsck >>fsck.lst goto eind :m if not "%1"=="-m" goto d echo Linking (minix version) link/m ..\lib\crtso+fsck+fsck1,fsck,fsck,..\lib\mxc86 >>fsck.lst dos2out -d fsck >>fsck.lst goto eind :d if not "%1"=="-d" goto fout echo Linking (dos version) link/m fsck+fsck1,,,\lib\c86\c86s2s.lib >>fsck.lst goto eind :fout echo/ echo error in compilation :eind _image.batTᖠ¤Wbuild bootblok.bin ..\kernel\kernel.out ..\mm\mm.out ..\fs\fs.out init.out fsck.out %1 1_init.batTᖠ¤–if "%1"=="-l" goto link if exist init.obj goto link cc1 init >init.lst if errorlevel 1 goto fout cc2 init >>init.lst if errorlevel 1 goto fout cc3 init >>init.lst if errorlevel 1 goto fout cc4 init >>init.lst if errorlevel 1 goto fout :link link/m ..\lib\head+init,init,init,..\lib\mxc86 >>init.lst dos2out -d init >>init.lst echo/ echo Init done. Hit reurn to see list file. pause echo on type init.lst _mkfs.batT㖠¤ if "%1"=="-l" goto link cc1 -dDOS mkfs if errorlevel 1 goto fout cc2 mkfs if errorlevel 1 goto fout cc3 mkfs if errorlevel 1 goto fout cc4 mkfs if errorlevel 1 goto fout :link link mkfs+diskio,mkfs,nul,\lib\c86\c86s2s.lib goto ok :fout pause error in compilation :ok imake.batTé– ¤Eecho off echo/ echo Making: %1 echo/ _%1.bat %2 %3 %4 %5 %6 %7 %8 %9 m...const.hglo.hmproc.h param.h!type.h"alloc.c#break.c$exec.c%forkexit.c&getset.c'main.c(putc.c)signal.c*table.c+utility.c,MINIX.PCIX0C86/* Constants used by the Memory Manager. */ #define ZEROBUF_SIZE 1024 /* buffer size for erasing memory */ /* Size of MM's stack depends mostly on do_exec(). */ #if ZEROBUF_SIZE > MAX_PATH #define MM_STACK_BYTES MAX_ISTACK_BYTES + ZEROBUF_SIZE + 384 #else #define MM_STACK_BYTES MAX_ISTACK_BYTES + MAX_PATH + 384 #endif #define NO_MEM (phys_clicks)0 /* returned by alloc_mem() with mem is up */ #ifdef i8088 #define PAGE_SIZE 16 /* how many bytes in a page */ #define MAX_PAGES 4096 /* how many pages in the virtual addr space */ #define HDR_SIZE 32 /* # bytes in the exec file header */ #endif #define printf printk /* Global variables. */ EXTERN struct mproc *mp; /* ptr to 'mproc' slot of current process */ EXTERN int dont_reply; /* normally 0; set to 1 to inhibit reply */ EXTERN int procs_in_use; /* how many processes are marked as IN_USE */ /* The parameters of the call are kept here. */ EXTERN message mm_in; /* the incoming message itself is kept here. */ EXTERN message mm_out; /* the reply message is built up here. */ EXTERN int who; /* caller's proc number */ EXTERN int mm_call; /* caller's proc number */ /* The following variables are used for returning results to the caller. */ EXTERN int err_code; /* temporary storage for error number */ EXTERN int result2; /* secondary result */ EXTERN char *res_ptr; /* result, if pointer */ EXTERN char mm_stack[MM_STACK_BYTES]; /* MM's stack */ /* This table has one slot per process. It contains all the memory management * information for each process. Among other things, it defines the text, data * and stack segments, uids and gids, and various flags. The kernel and file * systems have tables that are also indexed by process, with the contents * of corresponding slots referring to the same process in all three. */ EXTERN struct mproc { struct mem_map mp_seg[NR_SEGS]; /* points to text, data, stack */ char mp_exitstatus; /* storage for status when process exits */ char mp_sigstatus; /* storage for signal # for killed processes */ int mp_pid; /* process id */ int mp_parent; /* index of parent process */ int mp_procgrp; /* process group (used for signals) */ /* Real and effective uids and gids. */ uid mp_realuid; /* process' real uid */ uid mp_effuid; /* process' effective uid */ gid mp_realgid; /* process' real gid */ gid mp_effgid; /* process' effective gid */ /* Bit maps for signals. */ unshort mp_ignore; /* 1 means ignore the signal, 0 means don't */ unshort mp_catch; /* 1 means catch the signal, 0 means don't */ int (*mp_func)(); /* all signals vectored to a single user fcn */ unsigned mp_flags; /* flag bits */ } mproc[NR_PROCS]; /* Flag values */ #define IN_USE 001 /* set when 'mproc' slot in use */ #define WAITING 002 /* set by WAIT system call */ #define HANGING 004 /* set by EXIT system call */ #define PAUSED 010 /* set by PAUSE system call */ #define ALARM_ON 020 /* set when SIGALRM timer started */ #define SEPARATE 040 /* set if file is separate I & D space */ /* The following names are synonyms for the variables in the input message. */ #define addr mm_in.m1_p1 #define exec_name mm_in.m1_p1 #define exec_len mm_in.m1_i1 #define func mm_in.m6_f1 #define grpid (gid) mm_in.m1_i1 #define kill_sig mm_in.m1_i2 #define namelen mm_in.m1_i1 #define pid mm_in.m1_i1 #define seconds mm_in.m1_i1 #define sig mm_in.m6_i1 #define stack_bytes mm_in.m1_i2 #define stack_ptr mm_in.m1_p2 #define status mm_in.m1_i1 #define usr_id (uid) mm_in.m1_i1 /* The following names are synonyms for the variables in the output message. */ #define reply_type mm_out.m_type #define reply_i1 mm_out.m2_i1 #define reply_p1 mm_out.m2_p1 /* If there were any type definitions local to the Memory Manager, they would * be here. This file is included only for symmetry with the kernel and File * System, which do have some local type definitions. */ #include "../h/type.h" /* This file is concerned with allocating and freeing arbitrary-size blocks of * physical memory on behalf of the FORK and EXEC system calls. The key data * structure used is the hole table, which maintains a list of holes in memory. * It is kept sorted in order of increasing memory address. The addresses * it contains refer to physical memory, starting at absolute address 0 * (i.e., they are not relative to the start of MM). During system * initialization, that part of memory containing the interrupt vectors, * kernel, and MM are "allocated" to mark them as not available and to * remove them from the hole list. * * The entry points into this file are: * alloc_mem: allocate a given sized chunk of memory * free_mem: release a previously allocated chunk of memory * mem_init: initialize the tables when MM start up * max_hole: returns the largest hole currently available */ #include "../h/const.h" #include "../h/type.h" #include "const.h" #define NR_HOLES 128 /* max # entries in hole table */ #define NIL_HOLE (struct hole *) 0 PRIVATE struct hole { phys_clicks h_base; /* where does the hole begin? */ phys_clicks h_len; /* how big is the hole? */ struct hole *h_next; /* pointer to next entry on the list */ } hole[NR_HOLES]; PRIVATE struct hole *hole_head; /* pointer to first hole */ PRIVATE struct hole *free_slots; /* ptr to list of unused table slots */ /*===========================================================================* * alloc_mem * *===========================================================================*/ PUBLIC phys_clicks alloc_mem(clicks) phys_clicks clicks; /* amount of memory requested */ { /* Allocate a block of memory from the free list using first fit. The block * consists of a sequence of contiguous bytes, whose length in clicks is * given by 'clicks'. A pointer to the block is returned. The block is * always on a click boundary. This procedure is called when memory is * needed for FORK or EXEC. */ register struct hole *hp, *prev_ptr; phys_clicks old_base; hp = hole_head; while (hp != NIL_HOLE) { if (hp->h_len >= clicks) { /* We found a hole that is big enough. Use it. */ old_base = hp->h_base; /* remember where it started */ hp->h_base += clicks; /* bite a piece off */ hp->h_len -= clicks; /* ditto */ /* If hole is only partly used, reduce size and return. */ if (hp->h_len != 0) return(old_base); /* The entire hole has been used up. Manipulate free list. */ del_slot(prev_ptr, hp); return(old_base); } prev_ptr = hp; hp = hp->h_next; } return(NO_MEM); } /*===========================================================================* * free_mem * *===========================================================================*/ PUBLIC free_mem(base, clicks) phys_clicks base; /* base address of block to free */ phys_clicks clicks; /* number of clicks to free */ { /* Return a block of free memory to the hole list. The parameters tell where * the block starts in physical memory and how big it is. The block is added * to the hole list. If it is contiguous with an existing hole on either end, * it is merged with the hole or holes. */ register struct hole *hp, *new_ptr, *prev_ptr; if ( (new_ptr = free_slots) == NIL_HOLE) panic("Hole table full", NO_NUM); new_ptr->h_base = base; new_ptr->h_len = clicks; free_slots = new_ptr->h_next; hp = hole_head; /* If this block's address is numerically less than the lowest hole currently * available, or if no holes are currently available, put this hole on the * front of the hole list. */ if (hp == NIL_HOLE || base <= hp->h_base) { /* Block to be freed goes on front of hole list. */ new_ptr->h_next = hp; hole_head = new_ptr; merge(new_ptr); return; } /* Block to be returned does not go on front of hole list. */ while (hp != NIL_HOLE && base > hp->h_base) { prev_ptr = hp; hp = hp->h_next; } /* We found where it goes. Insert block after 'prev_ptr'. */ new_ptr->h_next = prev_ptr->h_next; prev_ptr->h_next = new_ptr; merge(prev_ptr); /* sequence is 'prev_ptr', 'new_ptr', 'hp' */ } /*===========================================================================* * del_slot * *===========================================================================*/ PRIVATE del_slot(prev_ptr, hp) register struct hole *prev_ptr; /* pointer to hole entry just ahead of 'hp' */ register struct hole *hp; /* pointer to hole entry to be removed */ { /* Remove an entry from the hole list. This procedure is called when a * request to allocate memory removes a hole in its entirety, thus reducing * the numbers of holes in memory, and requiring the elimination of one * entry in the hole list. */ if (hp == hole_head) hole_head = hp->h_next; else prev_ptr->h_next = hp->h_next; hp->h_next = free_slots; free_slots = hp; } /*===========================================================================* * merge * *===========================================================================*/ PRIVATE merge(hp) register struct hole *hp; /* ptr to hole to merge with its successors */ { /* Check for contiguous holes and merge any found. Contiguous holes can occur * when a block of memory is freed, and it happens to abut another hole on * either or both ends. The pointer 'hp' points to the first of a series of * three holes that can potentially all be merged together. */ register struct hole *next_ptr; /* If 'hp' points to the last hole, no merging is possible. If it does not, * try to absorb its successor into it and free the successor's table entry. */ if ( (next_ptr = hp->h_next) == NIL_HOLE) return; if (hp->h_base + hp->h_len == next_ptr->h_base) { hp->h_len += next_ptr->h_len; /* first one gets second one's mem */ del_slot(hp, next_ptr); } else { hp = next_ptr; } /* If 'hp' now points to the last hole, return; otherwise, try to absorb its * succesor into it. */ if ( (next_ptr = hp->h_next) == NIL_HOLE) return; if (hp->h_base + hp->h_len == next_ptr->h_base) { hp->h_len += next_ptr->h_len; del_slot(hp, next_ptr); } } /*===========================================================================* * max_hole * *===========================================================================*/ PUBLIC phys_clicks max_hole() { /* Scan the hole list and return the largest hole. */ register struct hole *hp; register phys_clicks max; hp = hole_head; max = 0; while (hp != NIL_HOLE) { if (hp->h_len > max) max = hp->h_len; hp = hp->h_next; } return(max); } /*===========================================================================* * mem_init * *===========================================================================*/ PUBLIC mem_init(clicks) phys_clicks clicks; /* amount of memory available */ { /* Initialize hole lists. There are two lists: 'hole_head' points to a linked * list of all the holes (unused memory) in the system; 'free_slots' points to * a linked list of table entries that are not in use. Initially, the former * list has one entry, a single hole encompassing all of memory, and the second * list links together all the remaining table slots. As memory becomes more * fragmented in the course of time (i.e., the initial big hole breaks up into * many small holes), new table slots are needed to represent them. These * slots are taken from the list headed by 'free_slots'. */ register struct hole *hp; for (hp = &hole[0]; hp < &hole[NR_HOLES]; hp++) hp->h_next = hp + 1; hole[0].h_next = NIL_HOLE; /* only 1 big hole initially */ hole[NR_HOLES-1].h_next = NIL_HOLE; hole_head = &hole[0]; free_slots = &hole[1]; hole[0].h_base = 0; hole[0].h_len = clicks; } /* The MINIX model of memory allocation reserves a fixed amount of memory for * the combined text, data, and stack segements. The amount used for a child * process created by FORK is the same as the parent had. If the child does * an EXEC later, the new size is taken from the header of the file EXEC'ed. * * The layout in memory consists of the text segment, followed by the data * segment, followed by a gap (unused memory), followed by the stack segment. * The data segment grows upward and the stack grows downward, so each can * take memory from the gap. If they meet, the process must be killed. The * procedures in this file deal with the growth of the data and stack segments. * * The entry points into this file are: * do_brk: BRK/SBRK system calls to grow or shrink the data segment * adjust: see if a proposed segment adjustment is allowed * size_ok: see if the segment sizes are feasible * stack_fault: grow the stack segment */ #include "../h/const.h" #include "../h/type.h" #include "../h/error.h" #include "../h/signal.h" #include "const.h" #include "glo.h" #include "mproc.h" #include "param.h" #define DATA_CHANGED 1 /* flag value when data segment size changed */ #define STACK_CHANGED 2 /* flag value when stack size changed */ /*===========================================================================* * do_brk * *===========================================================================*/ PUBLIC int do_brk() { /* Perform the brk(addr) system call. * * The call is complicated by the fact that on some machines (e.g., 8088), * the stack pointer can grow beyond the base of the stack segment without * anybody noticing it. For a file not using separate I & D space, * the parameter, 'addr' is to the total size, text + data. For a file using * separate text and data spaces, it is just the data size. Files using * separate I & D space have the SEPARATE bit in mp_flags set. */ register struct mproc *rmp; int r; vir_bytes v, new_sp; vir_clicks new_clicks; rmp = mp; v = (vir_bytes) addr; /* 'addr' is the new data segment size */ new_clicks = (vir_clicks) ( ((long) v + CLICK_SIZE - 1) >> CLICK_SHIFT); sys_getsp(who, &new_sp); /* ask kernel for current sp value */ r = adjust(rmp, new_clicks, new_sp); res_ptr = (r == OK ? addr : (char *) -1); return(r); /* return new size or -1 */ } /*===========================================================================* * adjust * *===========================================================================*/ PUBLIC int adjust(rmp, data_clicks, sp) register struct mproc *rmp; /* whose memory is being adjusted? */ vir_clicks data_clicks; /* how big is data segment to become? */ vir_bytes sp; /* new value of sp */ { /* See if data and stack segments can coexist, adjusting them if need be. * Memory is never allocated or freed. Instead it is added or removed from the * gap between data segment and stack segment. If the gap size becomes * negative, the adjustment of data or stack fails and ENOMEM is returned. */ register struct mem_map *mem_sp, *mem_dp; vir_clicks sp_click, gap_base, lower, old_clicks; int changed, r, ft; long base_of_stack, delta; /* longs avoid certain problems */ mem_dp = &rmp->mp_seg[D]; /* pointer to data segment map */ mem_sp = &rmp->mp_seg[S]; /* pointer to stack segment map */ changed = 0; /* set when either segment changed */ /* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */ base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len; sp_click = sp >> CLICK_SHIFT; /* click containing sp */ if (sp_click >= base_of_stack) return(ENOMEM); /* sp too high */ /* Compute size of gap between stack and data segments. */ delta = (long) mem_sp->mem_vir - (long) sp_click; lower = (delta > 0 ? sp_click : mem_sp->mem_vir); gap_base = mem_dp->mem_vir + data_clicks; if (lower < gap_base) return(ENOMEM); /* data and stack collided */ /* Update data length (but not data orgin) on behalf of brk() system call. */ old_clicks = mem_dp->mem_len; if (data_clicks != mem_dp->mem_len) { mem_dp->mem_len = data_clicks; changed |= DATA_CHANGED; } /* Update stack length and origin due to change in stack pointer. */ if (delta > 0) { mem_sp->mem_vir -= delta; mem_sp->mem_phys -= delta; mem_sp->mem_len += delta; changed |= STACK_CHANGED; } /* Do the new data and stack segment sizes fit in the address space? */ ft = (rmp->mp_flags & SEPARATE); r = size_ok(ft, rmp->mp_seg[T].mem_len, rmp->mp_seg[D].mem_len, rmp->mp_seg[S].mem_len, rmp->mp_seg[D].mem_vir, rmp->mp_seg[S].mem_vir); if (r == OK) { if (changed) sys_newmap(rmp - mproc, rmp->mp_seg); return(OK); } /* New sizes don't fit or require too many page/segment registers. Restore.*/ if (changed & DATA_CHANGED) mem_dp->mem_len = old_clicks; if (changed & STACK_CHANGED) { mem_sp->mem_vir += delta; mem_sp->mem_phys += delta; mem_sp->mem_len -= delta; } return(ENOMEM); } /*===========================================================================* * size_ok * *===========================================================================*/ PUBLIC int size_ok(file_type, tc, dc, sc, dvir, s_vir) int file_type; /* SEPARATE or 0 */ vir_clicks tc; /* text size in clicks */ vir_clicks dc; /* data size in clicks */ vir_clicks sc; /* stack size in clicks */ vir_clicks dvir; /* virtual address for start of data seg */ vir_clicks s_vir; /* virtual address for start of stack seg */ { /* Check to see if the sizes are feasible and enough segmentation registers * exist. On a machine with eight 8K pages, text, data, stack sizes of * (32K, 16K, 16K) will fit, but (33K, 17K, 13K) will not, even though the * former is bigger (64K) than the latter (63K). Even on the 8088 this test * is needed, since the data and stack may not exceed 4096 clicks. */ int pt, pd, ps; /* segment sizes in pages */ pt = ( (tc << CLICK_SHIFT) + PAGE_SIZE - 1)/PAGE_SIZE; pd = ( (dc << CLICK_SHIFT) + PAGE_SIZE - 1)/PAGE_SIZE; ps = ( (sc << CLICK_SHIFT) + PAGE_SIZE - 1)/PAGE_SIZE; if (file_type == SEPARATE) { if (pt > MAX_PAGES || pd + ps > MAX_PAGES) return(ENOMEM); } else { if (pt + pd + ps > MAX_PAGES) return(ENOMEM); } if (dvir + dc > s_vir) return(ENOMEM); return(OK); } /*===========================================================================* * stack_fault * *===========================================================================*/ PUBLIC stack_fault(proc_nr) int proc_nr; /* tells who got the stack fault */ { /* Handle a stack fault by growing the stack segment until sp is inside of it. * If this is impossible because data segment is in the way, kill the process. */ register struct mproc *rmp; int r; vir_bytes new_sp; rmp = &mproc[proc_nr]; sys_getsp(rmp - mproc, &new_sp); r = adjust(rmp, rmp->mp_seg[D].mem_len, new_sp); if (r == OK) return; /* Stack has bumped into data segment. Kill the process. */ rmp->mp_catch = 0; /* don't catch this signal */ sig_proc(rmp, SIGSEGV); /* terminate process */ } /* This file handles the EXEC system call. It performs the work as follows: * - see if the permissions allow the file to be executed * - read the header and extract the sizes * - fetch the initial args and environment from the user space * - allocate the memory for the new process * - copy the initial stack from MM to the process * - read in the text and data segments and copy to the process * - take care of setuid and setgid bits * - fix up 'mproc' table * - tell kernel about EXEC * * The only entry point is do_exec. */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/error.h" #include "../h/stat.h" #include "const.h" #include "glo.h" #include "mproc.h" #include "param.h" #define MAGIC 0x04000301L /* magic number with 2 bits masked off */ #define SEP 0x00200000L /* value for separate I & D */ #define TEXTB 2 /* location of text size in header */ #define DATAB 3 /* location of data size in header */ #define BSSB 4 /* location of bss size in header */ #define TOTB 6 /* location of total size in header */ /*===========================================================================* * do_exec * *===========================================================================*/ PUBLIC int do_exec() { /* Perform the exece(name, argv, envp) call. The user library builds a * complete stack image, including pointers, args, environ, etc. The stack * is copied to a buffer inside MM, and then to the new core image. */ register struct mproc *rmp; int m, r, fd, ft; char mbuf[MAX_ISTACK_BYTES]; /* buffer for stack and zeroes */ union u { char name_buf[MAX_PATH]; /* the name of the file to exec */ char zb[ZEROBUF_SIZE]; /* used to zero bss */ } u; char *new_sp; vir_bytes src, dst, text_bytes, data_bytes, bss_bytes, stk_bytes, vsp; phys_bytes tot_bytes; /* total space for program, including gap */ vir_clicks sc; struct stat s_buf; /* Do some validity checks. */ rmp = mp; stk_bytes = (vir_bytes) stack_bytes; if (stk_bytes > MAX_ISTACK_BYTES) return(ENOMEM); /* stack too big */ if (exec_len <= 0 || exec_len > MAX_PATH) return(EINVAL); /* Get the exec file name and see if the file is executable. */ src = (vir_bytes) exec_name; dst = (vir_bytes) u.name_buf; r = mem_copy(who, D, (long) src, MM_PROC_NR, D, (long) dst, (long) exec_len); if (r != OK) return(r); /* file name not in user data segment */ tell_fs(CHDIR, who, 0, 0); /* temporarily switch to user's directory */ fd = allowed(u.name_buf, &s_buf, X_BIT); /* is file executable? */ tell_fs(CHDIR, 0, 1, 0); /* switch back to MM's own directory */ if (fd < 0) return(fd); /* file was not executable */ /* Read the file header and extract the segment sizes. */ sc = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; m = read_header(fd, &ft, &text_bytes, &data_bytes, &bss_bytes, &tot_bytes,sc); if (m < 0) { close(fd); /* something wrong with header */ return(ENOEXEC); } /* Fetch the stack from the user before destroying the old core image. */ src = (vir_bytes) stack_ptr; dst = (vir_bytes) mbuf; r = mem_copy(who, D, (long) src, MM_PROC_NR, D, (long) dst, (long) stk_bytes); if (r != OK) { close(fd); /* can't fetch stack (e.g. bad virtual addr) */ return(EACCES); } /* Allocate new memory and release old memory. Fix map and tell kernel. */ r = new_mem(text_bytes, data_bytes, bss_bytes, stk_bytes, tot_bytes, u.zb, ZEROBUF_SIZE); if (r != OK) { close(fd); /* insufficient core or program too big */ return(r); } /* Patch up stack and copy it from MM to new core image. */ vsp = (vir_bytes) rmp->mp_seg[S].mem_vir << CLICK_SHIFT; patch_ptr(mbuf, vsp); src = (vir_bytes) mbuf; r = mem_copy(MM_PROC_NR, D, (long) src, who, D, (long) vsp, (long) stk_bytes); if (r != OK) panic("do_exec stack copy err", NO_NUM); /* Read in text and data segments. */ load_seg(fd, T, text_bytes); load_seg(fd, D, data_bytes); close(fd); /* don't need exec file any more */ /* Take care of setuid/setgid bits. */ if (s_buf.st_mode & I_SET_UID_BIT) { rmp->mp_effuid = s_buf.st_uid; tell_fs(SETUID, who, (int) rmp->mp_realuid, (int) rmp->mp_effuid); } if (s_buf.st_mode & I_SET_GID_BIT) { rmp->mp_effgid = s_buf.st_gid; tell_fs(SETGID, who, (int) rmp->mp_realgid, (int) rmp->mp_effgid); } /* Fix up some 'mproc' fields and tell kernel that exec is done. */ rmp->mp_catch = 0; /* reset all caught signals */ rmp->mp_flags &= ~SEPARATE; /* turn off SEPARATE bit */ rmp->mp_flags |= ft; /* turn it on for separate I & D files */ new_sp = (char *) vsp; sys_exec(who, new_sp); return(OK); } /*===========================================================================* * read_header * *===========================================================================*/ PRIVATE int read_header(fd, ft, text_bytes, data_bytes, bss_bytes, tot_bytes,sc) int fd; /* file descriptor for reading exec file */ int *ft; /* place to return ft number */ vir_bytes *text_bytes; /* place to return text size */ vir_bytes *data_bytes; /* place to return initialized data size */ vir_bytes *bss_bytes; /* place to return bss size */ phys_bytes *tot_bytes; /* place to return total size */ vir_clicks sc; /* stack size in clicks */ { /* Read the header and extract the text, data, bss and total sizes from it. */ int m, ct; vir_clicks tc, dc, s_vir, dvir; phys_clicks totc; long buf[HDR_SIZE/sizeof(long)]; /* Read the header and check the magic number. The standard MINIX header * consists of 8 longs, as follows: * 0: 0x04100301L (combined I & D space) or 0x04200301L (separate I & D) * 1: 0x00000020L * 2: size of text segments in bytes * 3: size of initialized data segment in bytes * 4: size of bss in bytes * 5: 0x00000000L * 6: total memory allocated to program (text, data and stack, combined) * 7: 0x00000000L * The longs are represented low-order byte first and high-order byte last. * The first byte of the header is always 0x01, followed by 0x03. * The header is followed directly by the text and data segments, whose sizes * are given in the header. */ if (read(fd, buf, HDR_SIZE) != HDR_SIZE) return(ENOEXEC); if ( (buf[0] & 0xFF0FFFFFL) != MAGIC) return(ENOEXEC); *ft = (buf[0] & SEP ? SEPARATE : 0); /* separate I & D or not */ /* Get text and data sizes. */ *text_bytes = (vir_bytes) buf[TEXTB]; /* text size in bytes */ *data_bytes = (vir_bytes) buf[DATAB]; /* data size in bytes */ if (*ft != SEPARATE) { /* If I & D space is not separated, it is all considered data. Text=0 */ *data_bytes += *text_bytes; *text_bytes = 0; } /* Get bss and total sizes. */ *bss_bytes = (vir_bytes) buf[BSSB]; /* bss size in bytes */ *tot_bytes = buf[TOTB]; /* total bytes to allocate for program */ if (*tot_bytes == 0) return(ENOEXEC); /* Check to see if segment sizes are feasible. */ tc = (*text_bytes + CLICK_SHIFT - 1) >> CLICK_SHIFT; dc = (*data_bytes + *bss_bytes + CLICK_SHIFT - 1) >> CLICK_SHIFT; totc = (*tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; if (dc >= totc) return(ENOEXEC); /* stack must be at least 1 click */ dvir = (*ft == SEPARATE ? 0 : tc); s_vir = dvir + (totc - sc); m = size_ok(*ft, tc, dc, sc, dvir, s_vir); ct = buf[1] & BYTE; /* header length */ if (ct > HDR_SIZE) read(fd, buf, ct - HDR_SIZE); /* skip unused hdr */ return(m); } /*===========================================================================* * new_mem * *===========================================================================*/ PRIVATE int new_mem(text_bytes, data_bytes, bss_bytes,stk_bytes,tot_bytes,bf,zs) vir_bytes text_bytes; /* text segment size in bytes */ vir_bytes data_bytes; /* size of initialized data in bytes */ vir_bytes bss_bytes; /* size of bss in bytes */ vir_bytes stk_bytes; /* size of initial stack segment in bytes */ phys_bytes tot_bytes; /* total memory to allocate, including gap */ char bf[ZEROBUF_SIZE]; /* buffer to use for zeroing data segment */ int zs; $&'()*+ /* true size of 'bf' */ { /* Allocate new memory and release the old memory. Change the map and report * the new map to the kernel. Zero the new core image's bss, gap and stack. */ register struct mproc *rmp; char *rzp; vir_bytes vzb; vir_clicks text_clicks, data_clicks, gap_clicks, stack_clicks, tot_clicks; phys_clicks new_base, old_clicks; phys_bytes bytes, base, count, bss_offset; extern phys_clicks alloc_mem(); extern phys_clicks max_hole(); /* Acquire the new memory. Each of the 4 parts: text, (data+bss), gap, * and stack occupies an integral number of clicks, starting at click * boundary. The data and bss parts are run together with no space. */ text_clicks = (text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; data_clicks = (data_bytes + bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; stack_clicks = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; tot_clicks = (tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT; gap_clicks = tot_clicks - data_clicks - stack_clicks; if ( (int) gap_clicks < 0) return(ENOMEM); /* Check to see if there is a hole big enough. If so, we can risk first * releasing the old core image before allocating the new one, since we * know it will succeed. If there is not enough, return failure. */ if (text_clicks + tot_clicks > max_hole()) return(EAGAIN); /* There is enough memory for the new core image. Release the old one. */ rmp = mp; old_clicks = (phys_clicks) rmp->mp_seg[S].mem_vir + rmp->mp_seg[S].mem_len; if (rmp->mp_flags & SEPARATE) old_clicks += rmp->mp_seg[T].mem_len; free_mem(rmp->mp_seg[T].mem_phys, old_clicks); /* free the memory */ /* We have now passed the point of no return. The old core image has been * forever lost. The call must go through now. Set up and report new map. */ new_base = alloc_mem(text_clicks + tot_clicks); /* new core image */ if (new_base == NO_MEM) panic("MM hole list is inconsistent", NO_NUM); rmp->mp_seg[T].mem_vir = 0; rmp->mp_seg[T].mem_len = text_clicks; rmp->mp_seg[T].mem_phys = new_base; rmp->mp_seg[D].mem_vir = 0; rmp->mp_seg[D].mem_len = data_clicks; rmp->mp_seg[D].mem_phys = new_base + text_clicks; rmp->mp_seg[S].mem_vir = rmp->mp_seg[D].mem_vir + data_clicks + gap_clicks; rmp->mp_seg[S].mem_len = stack_clicks; rmp->mp_seg[S].mem_phys = rmp->mp_seg[D].mem_phys + data_clicks + gap_clicks; sys_newmap(who, rmp->mp_seg); /* report new map to the kernel */ /* Zero the bss, gap, and stack segment. Start just above text. */ for (rzp = &bf[0]; rzp < &bf[zs]; rzp++) *rzp = 0; /* clear buffer */ bytes = (phys_bytes) (data_clicks + gap_clicks + stack_clicks) << CLICK_SHIFT; vzb = (vir_bytes) bf; base = (long) rmp->mp_seg[T].mem_phys + rmp->mp_seg[T].mem_len; base = base << CLICK_SHIFT; bss_offset = (data_bytes >> CLICK_SHIFT) << CLICK_SHIFT; base += bss_offset; bytes -= bss_offset; while (bytes > 0) { count = (long) MIN(bytes, (phys_bytes) zs); if (mem_copy(MM_PROC_NR, D, (long) vzb, ABS, 0, base, count) != OK) panic("new_mem can't zero", NO_NUM); base += count; bytes -= count; } return(OK); } /*===========================================================================* * patch_ptr * *===========================================================================*/ PRIVATE patch_ptr(stack, base) char stack[MAX_ISTACK_BYTES]; /* pointer to stack image within MM */ vir_bytes base; /* virtual address of stack base inside user */ { /* When doing an exec(name, argv, envp) call, the user builds up a stack * image with arg and env pointers relative to the start of the stack. Now * these pointers must be relocated, since the stack is not positioned at * address 0 in the user's address space. */ char **ap, flag; vir_bytes v; flag = 0; /* counts number of 0-pointers seen */ ap = (char **) stack; /* points initially to 'nargs' */ ap++; /* now points to argv[0] */ while (flag < 2) { if (ap >= (char **) &stack[MAX_ISTACK_BYTES]) return; /* too bad */ if (*ap != NIL_PTR) { v = (vir_bytes) *ap; /* v is relative pointer */ v += base; /* relocate it */ *ap = (char *) v; /* put it back */ } else { flag++; } ap++; } } /*===========================================================================* * load_seg * *===========================================================================*/ PRIVATE load_seg(fd, seg, seg_bytes) int fd; /* file descriptor to read from */ int seg; /* T or D */ vir_bytes seg_bytes; /* how big is the segment */ { /* Read in text or data from the exec file and copy to the new core image. * This procedure is a little bit tricky. The logical way to load a segment * would be to read it block by block and copy each block to the user space * one at a time. This is too slow, so we do something dirty here, namely * send the user space and virtual address to the file system in the upper * 10 bits of the file descriptor, and pass it the user virtual address * instead of a MM address. The file system copies the whole segment * directly to user space, bypassing MM completely. */ int new_fd, bytes; char *ubuf_ptr; if (seg_bytes == 0) return; /* text size for combined I & D is 0 */ new_fd = (who << 8) | (seg << 6) | fd; ubuf_ptr = (char *) (mp->mp_seg[seg].mem_vir << CLICK_SHIFT); bytes = (int) seg_bytes; read(new_fd, ubuf_ptr, bytes); } /* This file deals with creating processes (via FORK) and deleting them (via * EXIT/WAIT). When a process forks, a new slot in the 'mproc' table is * allocated for it, and a copy of the parent's core image is made for the * child. Then the kernel and file system are informed. A process is removed * from the 'mproc' table when two events have occurred: (1) it has exited or * been killed by a signal, and (2) the parent has done a WAIT. If the process * exits first, it continues to occupy a slot until the parent does a WAIT. * * The entry points into this file are: * do_fork: perform the FORK system call * do_mm_exit: perform the EXIT system call (by calling mm_exit()) * mm_exit: actually do the exiting * do_wait: perform the WAIT system call */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/error.h" #include "const.h" #include "glo.h" #include "mproc.h" #include "param.h" #define LAST_FEW 2 /* last few slots reserved for superuser */ PRIVATE next_pid = INIT_PROC_NR+1; /* next pid to be assigned */ PRIVATE process_group = 1; /* next process grp to be assigned */ /* Some C compilers require static declarations to precede their first use. */ /*===========================================================================* * do_fork * *===========================================================================*/ PUBLIC int do_fork() { /* The process pointed to by 'mp' has forked. Create a child process. */ register struct mproc *rmp; /* pointer to parent */ register struct mproc *rmc; /* pointer to child */ int i, child_nr, t; char *sptr, *dptr; long prog_bytes; phys_clicks prog_clicks, child_base; long parent_abs, child_abs; extern phys_clicks alloc_mem(); /* If tables might fill up during FORK, don't even start since recovery half * way through is such a nuisance. */ rmp = mp; if (procs_in_use == NR_PROCS) return(EAGAIN); if (procs_in_use >= NR_PROCS - LAST_FEW && rmp->mp_effuid != 0)return(EAGAIN); /* Determine how much memory to allocate. */ prog_clicks = (phys_clicks) rmp->mp_seg[T].mem_len + rmp->mp_seg[D].mem_len + rmp->mp_seg[S].mem_len; #ifdef i8088 prog_clicks += rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_len; /* gap too */ #endif prog_bytes = (long) prog_clicks << CLICK_SHIFT; if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(EAGAIN); /* Create a copy of the parent's core image for the child. */ child_abs = (long) child_base << CLICK_SHIFT; parent_abs = (long) rmp->mp_seg[T].mem_phys << CLICK_SHIFT; i = mem_copy(ABS, 0, parent_abs, ABS, 0, child_abs, prog_bytes); if ( i < 0) panic("do_fork can't copy", i); /* Find a slot in 'mproc' for the child process. A slot must exist. */ for (rmc = &mproc[0]; rmc < &mproc[NR_PROCS]; rmc++) if ( (rmc->mp_flags & IN_USE) == 0) break; /* Set up the child and its memory map; copy its 'mproc' slot from parent. */ child_nr = rmc - mproc; /* slot number of the child */ procs_in_use++; sptr = (char *) rmp; /* pointer to parent's 'mproc' slot */ dptr = (char *) rmc; /* pointer to child's 'mproc' slot */ i = sizeof(struct mproc); /* number of bytes in a proc slot. */ while (i--) *dptr++ = *sptr++;/* copy from parent slot to child's */ /* Set process group. */ if (who == INIT_PROC_NR) rmc->mp_procgrp = process_group++; rmc->mp_parent = who; /* record child's parent */ rmc->mp_seg[T].mem_phys = child_base; rmc->mp_seg[D].mem_phys = child_base + rmc->mp_seg[T].mem_len; rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys + (rmp->mp_seg[S].mem_phys - rmp->mp_seg[D].mem_phys); rmc->mp_exitstatus = 0; rmc->mp_sigstatus = 0; /* Find a free pid for the child and put it in the table. */ do { t = 0; /* 't' = 0 means pid still free */ next_pid = (next_pid < 30000 ? next_pid + 1 : INIT_PROC_NR + 1); for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) if (rmp->mp_pid == next_pid) { t = 1; break; } rmc->mp_pid = next_pid; /* assign pid to child */ } while (t); /* Tell kernel and file system about the (now successful) FORK. */ sys_fork(who, child_nr, rmc->mp_pid); tell_fs(FORK, who, child_nr, 0); /* Report child's memory map to kernel. */ sys_newmap(child_nr, rmc->mp_seg); /* Reply to child to wake it up. */ reply(child_nr, 0, 0, NIL_PTR); return(next_pid); /* child's pid */ } /*===========================================================================* * do_mm_exit * *===========================================================================*/ PUBLIC int do_mm_exit() { /* Perform the exit(status) system call. The real work is done by mm_exit(), * which is also called when a process is killed by a signal. */ mm_exit(mp, status); dont_reply = TRUE; /* don't reply to newly terminated process */ return(OK); /* pro forma return code */ } /*===========================================================================* * mm_exit * *===========================================================================*/ PUBLIC mm_exit(rmp, exit_status) register struct mproc *rmp; /* pointer to the process to be terminated */ int exit_status; /* the process' exit status (for parent) */ { /* A process is done. If parent is waiting for it, clean it up, else hang. */ /* How to terminate a process is determined by whether or not the * parent process has already done a WAIT. Test to see if it has. */ rmp->mp_exitstatus = (char) exit_status; /* store status in 'mproc' */ if (mproc[rmp->mp_parent].mp_flags & WAITING) cleanup(rmp); /* release parent and tell everybody */ else rmp->mp_flags |= HANGING; /* Parent not waiting. Suspend proc */ /* If the exited process has a timer pending, kill it. */ if (rmp->mp_flags & ALARM_ON) set_alarm(rmp - mproc, (unsigned) 0); /* Tell the kernel and FS that the process is no longer runnable. */ sys_xit(rmp->mp_parent, rmp - mproc); tell_fs(EXIT, rmp - mproc, 0, 0); /* file system can free the proc slot */ } /*===========================================================================* * do_wait * *===========================================================================*/ PUBLIC int do_wait() { /* A process wants to wait for a child to terminate. If one is already waiting, * go clean it up and let this WAIT call terminate. Otherwise, really wait. */ register struct mproc *rp; register int children; /* A process calling WAIT never gets a reply in the usual way via the * reply() in the main loop. If a child has already exited, the routine * cleanup() sends the reply to awaken the caller. */ /* Is there a child waiting to be collected? */ children = 0; for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) { if ( (rp->mp_flags & IN_USE) && rp->mp_parent == who) { children++; if (rp->mp_flags & HANGING) { cleanup(rp); /* a child has already exited */ dont_reply = TRUE; return(OK); } } } /* No child has exited. Wait for one, unless none exists. */ if (children > 0) { /* does this process have any children? */ mp->mp_flags |= WAITING; dont_reply = TRUE; return(OK); /* yes - wait for one to exit */ } else return(ECHILD); /* no - parent has no children */ } /*===========================================================================* * cleanup * *===========================================================================*/ PRIVATE cleanup(child) register struct mproc *child; /* tells which process is exiting */ { /* Clean up the remains of a process. This routine is only called if two * conditions are satisfied: * 1. The process has done an EXIT or has been killed by a signal. * 2. The process' parent has done a WAIT. * * It releases the memory, if that has not been done yet. Whether it has or * has not been done depends on the order of the EXIT and WAIT calls. */ register struct mproc *parent, *rp; int init_waiting, child_nr; unsigned int r; phys_clicks s; child_nr = child - mproc; parent = &mproc[child->mp_parent]; /* Wakeup the parent. */ r = child->mp_sig356status & 0377; r = r | (child->mp_exitstatus << 8); reply(child->mp_parent, child->mp_pid, r, NIL_PTR); /* Release the memory occupied by the child. */ s = (phys_clicks) child->mp_seg[S].mem_vir + child->mp_seg[S].mem_len; if (child->mp_flags & SEPARATE) s += child->mp_seg[T].mem_len; free_mem(child->mp_seg[T].mem_phys, s); /* free the memory */ /* Update flags. */ child->mp_flags &= ~HANGING; /* turn off HANGING bit */ child->mp_flags &= ~PAUSED; /* turn off PAUSED bit */ parent->mp_flags &= ~WAITING; /* parent is no longer waiting */ child->mp_flags &= ~IN_USE; /* release the table slot */ procs_in_use--; /* If exiting process has children, disinherit them. INIT is new parent. */ init_waiting = (mproc[INIT_PROC_NR].mp_flags & WAITING ? 1 : 0); for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) { if (rp->mp_parent == child_nr) { /* 'rp' points to a child to be disinherited. */ rp->mp_parent = INIT_PROC_NR; /* init takes over */ if (init_waiting && (rp->mp_flags & HANGING) ) { /* Init was waiting. */ cleanup(rp); /* recursive call */ init_waiting = 0; } } } } /* This file handles the 4 system calls that get and set uids and gids. * It also handles getpid(). The code for each one is so tiny that it hardly * seemed worthwhile to make each a separate function. */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/error.h" #include "const.h" #include "glo.h" #include "mproc.h" #include "param.h" /*===========================================================================* * do_getset * *===========================================================================*/ PUBLIC int do_getset() { /* Handle GETUID, GETGID, GETPID, SETUID, SETGID. The three GETs return * their primary results in 'r'. GETUID and GETGID also return secondary * results (the effective IDs) in 'result2', which is returned to the user. */ register struct mproc *rmp = mp; register int r; switch(mm_call) { case GETUID: r = rmp->mp_realuid; result2 = rmp->mp_effuid; break; case GETGID: r = rmp->mp_realgid; result2 = rmp->mp_effgid; break; case GETPID: r = mproc[who].mp_pid; result2 = mproc[rmp->mp_parent].mp_pid; break; case SETUID: if (rmp->mp_realuid != usr_id && rmp->mp_effuid != SUPER_USER) return(EPERM); rmp->mp_realuid = usr_id; rmp->mp_effuid = usr_id; tell_fs(SETUID, who, usr_id, usr_id); r = OK; break; case SETGID: if (rmp->mp_realgid != grpid && rmp->mp_effuid != SUPER_USER) return(EPERM); rmp->mp_realgid = grpid; rmp->mp_effgid = grpid; tell_fs(SETGID, who, grpid, grpid); r = OK; break; } return(r); } /* This file contains the main program of the memory manager and some related * procedures. When MINIX starts up, the kernel runs for a little while, * initializing itself and its tasks, and then it runs MM. MM at this point * does not know where FS is in memory and how big it is. By convention, FS * must start at the click following MM, so MM can deduce where it starts at * least. Later, when FS runs for the first time, FS makes a pseudo-call, * BRK2, to tell MM how big it is. This allows MM to figure out where INIT * is. * * The entry points into this file are: * main: starts MM running * reply: reply to a process making an MM system call * do_brk2: pseudo-call for FS to report its size */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/com.h" #include "../h/error.h" #include "const.h" #include "glo.h" #include "mproc.h" #include "param.h" #define ENOUGH (phys_clicks) 4096 /* any # > max(FS size, INIT size) */ #define CLICK_TO_K (1024L/CLICK_SIZE) /* convert clicks to K */ PRIVATE phys_clicks tot_mem; extern (*call_vec[])(); /*===========================================================================* * main * *===========================================================================*/ PUBLIC main() { /* Main routine of the memory manager. */ int error; mm_init(); /* initialize memory manager tables */ /* This is MM's main loop- get work and do it, forever and forever. */ while (TRUE) { /* Wait for message. */ get_work(); /* wait for an MM system call */ mp = &mproc[who]; /* Set some flags. */ error = OK; dont_reply = FALSE; err_code = -999; /* If the call number is valid, perform the call. */ if (mm_call < 0 || mm_call >= NCALLS) error = E_BAD_CALL; else error = (*call_vec[mm_call])(); /* Send the results back to the user to indicate completion. */ if (dont_reply) continue; /* no reply for EXIT and WAIT */ if (mm_call == EXEC && error == OK) continue; reply(who, error, result2, res_ptr); } } /*===========================================================================* * get_work * *===========================================================================*/ PRIVATE get_work() { /* Wait for the next message and extract useful information from it. */ if (receive(ANY, &mm_in) != OK) panic("MM receive error", NO_NUM); who = mm_in.m_source; /* who sent the message */ if (who < HARDWARE || who >= NR_PROCS) panic("MM called by", who); mm_call = mm_in.m_type; /* system call number */ } /*===========================================================================* * reply * *===========================================================================*/ PUBLIC reply(proc_nr, result, res2, respt) int proc_nr; /* process to reply to */ int result; /* result of the call (usually OK or error #)*/ int res2; /* secondary result */ char *respt; /* result if pointer */ { /* Send a reply to a user process. */ register struct mproc *proc_ptr; /* To make MM robust, check to see if destination is still alive. */ proc_ptr = &mproc[proc_nr]; if ( (proc_ptr->mp_flags&IN_USE) == 0 || (proc_ptr->mp_flags&HANGING)) return; reply_type = result; reply_i1 = res2; reply_p1 = respt; if (send(proc_nr, &mm_out) != OK) panic("MM can't reply", NO_NUM); } /*===========================================================================* * mm_init * *===========================================================================*/ PRIVATE mm_init() { /* Initialize the memory manager. */ extern phys_clicks get_tot_mem(), alloc_mem(); /* Find out how much memory the machine has and set up core map. MM and FS * are part of the map. Tell the kernel. */ tot_mem = get_tot_mem(); /* # clicks in mem starting at absolute 0 */ mem_init(tot_mem); /* initialize tables to all physical mem */ /* Initialize MM's tables. */ mproc[MM_PROC_NR].mp_flags |= IN_USE; mproc[FS_PROC_NR].mp_flags |= IN_USE; mproc[INIT_PROC_NR].mp_flags |= IN_USE; procs_in_use = 3; /* Set stack limit, which is checked on every procedure call. */ } /*===========================================================================* * do_brk2 * *===========================================================================*/ PUBLIC do_brk2() { /* This "call" is made once by FS during system initialization and then never * again by anyone. It contains the origin and size of INIT, and the combined * size of the 1536 bytes of unused mem, MINIX and RAM disk. * m1_i1 = size of INIT text in clicks * m1_i2 = size of INIT data in clicks * m1_i3 = number of bytes for MINIX + RAM DISK * m1_p1 = origin of INIT in clicks */ int mem1, mem2, mem3; register struct mproc *rmp; phys_clicks init_org, init_clicks, ram_base, ram_clicks, tot_clicks; phys_clicks init_text_clicks, init_data_clicks; if (who != FS_PROC_NR) return(EPERM); /* only FS make do BRK2 */ /* Remove the memory used by MINIX and RAM disk from the memory map. */ init_text_clicks = mm_in.m1_i1; /* size of INIT in clicks */ init_data_clicks = mm_in.m1_i2; /* size of INIT in clicks */ tot_clicks = mm_in.m1_i3; /* total size of MINIX + RAM disk */ init_org = (phys_clicks) mm_in.m1_p1; /* addr where INIT begins in memory */ init_clicks = init_text_clicks + init_data_clicks; ram_base = init_org + init_clicks; /* start of RAM disk */ ram_clicks = tot_clicks - ram_base; /* size of RAM disk */ alloc_mem(tot_clicks); /* remove RAM disk from map */ /* Print memory information. */ mem1 = tot_mem/CLICK_TO_K; mem2 = (ram_base + 512/CLICK_SIZE)/CLICK_TO_K; /* MINIX, rounded */ mem3 = ram_clicks/CLICK_TO_K; printf("%c 8%c~0",033, 033); /* go to top of screen and clear screen */ printf("Memory size = %dK ", mem1); printf("MINIX = %dK ", mem2); printf("RAM disk = %dK ", mem3); printf("Available = %dK\n\n", mem1 - mem2 - mem3); if (mem1 - mem2 - mem3 < 32) { printf("\nNot enough memory to run MINIX\n\n", NO_NUM); sys_abort(); } /* Initialize INIT's table entry. */ rmp = &mproc[INIT_PROC_NR]; rmp->mp_seg[T].mem_phys = init_org; rmp->mp_seg[T].mem_len = init_text_clicks; rmp->mp_seg[D].mem_phys = init_org + init_text_clicks; rmp->mp_seg[D].mem_len = init_data_clicks; rmp->mp_seg[S].mem_vir = init_clicks; rmp->mp_seg[S].mem_phys = init_org + init_clicks; if (init_text_clicks != 0) rmp->mp_flags |= SEPARATE; return(OK); } /*===========================================================================* * set_map * *===========================================================================*/ PRIVATE set_map(proc_nr, base, clicks) int proc_nr; /* whose map to set? */ phys_clicks base; /* where in memory does the process start? */ phys_clicks clicks; /* total size in clicks (sep I & D not used) */ { /* Set up the memory map as part of the system initialization. */ register struct mproc *rmp; vir_clicks vclicks; rmp = &mproc[proc_nr]; vclicks = (vir_clicks) clicks; rmp->mp_seg[T].mem_vir = 0; rmp->mp_seg[T].mem_len = 0; rmp->mp_seg[T].mem_phys = base; rmp->mp_seg[D].mem_vir = 0; rmp->mp_seg[D].mem_len = vclicks; rmp->mp_seg[D].mem_phys = base; rmp->mp_seg[S].mem_vir = vclicks; rmp->mp_seg[S].mem_len = 0; rmp->mp_seg[S].mem_phys = base + vclicks; sys_newmap(proc_nr, rmp->mp_seg); } @/* MM must occasionally print some message. It uses the standard library * routine prink(). (The name "printf" is really a macro defined as "printk"). * Printing is done by calling the TTY task directly, not going through FS. */ #include "../h/const.h" #include "../h/type.h" #include "../h/com.h" #define STD_OUTPUT 1 /* file descriptor for standard output */ #define BUF_SIZE 100 /* print buffer size */ PRIVATE int buf_count; /* # characters in the buffer */ PRIVATE char print_buf[BUF_SIZE]; /* output is buffered here */ PRIVATE message putch_msg; /* used for message to TTY task */ /*===========================================================================* * putc * *===========================================================================*/ PUBLIC putc(c) char c; { /* Accumulate another character. If '\n' or buffer full, print it. */ print_buf[buf_count++] = c; if (buf_count == BUF_SIZE) F_l_u_s_h(); if (c == '\n') F_l_u_s_h(); } /*===========================================================================* * F_l_u_s_h * *===========================================================================*/ PRIVATE F_l_u_s_h() { /* Flush the print buffer by calling TTY task. */ if (buf_count == 0) return; putch_msg.m_type = TTY_WRITE; putch_msg.PROC_NR = 0; putch_msg.TTY_LINE = 0; putch_msg.ADDRESS = print_buf; putch_msg.COUNT = buf_count; sendrec(TTY, &putch_msg); buf_count = 0; } /* This file handles signals, which are asynchronous events and are generally * a messy and unpleasant business. Signals can be generated by the KILL * system call, or from the keyboard (SIGINT) or from the clock (SIGALRM). * In all cases control eventually passes to check_sig() to see which processes * can be signalled. The actual signalling is done by sig_proc(). * * The entry points into this file are: * do_signal: perform the SIGNAL system call * do_kill: perform the KILL system call * do_ksig: accept a signal originating in the kernel (e.g., SIGINT) * sig_proc: interrupt or terminate a signalled process * do_alarm: perform the ALARM system call by calling set_alarm() * set_alarm: tell the clock task to start or stop a timer * do_pause: perform the PAUSE system call * unpause: check to see if process is suspended on anything */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/com.h" #include "../h/error.h" #include "../h/signal.h" #include "../h/stat.h" #include "const.h" #include "glo.h" #include "mproc.h" #include "param.h" #define DUMP_SIZE 256 /* buffer size for core dumps */ #define CORE_MODE 0777 /* mode to use on core image files */ #define DUMPED 0200 /* bit set in status when core dumped */ PRIVATE message m_sig; /*===========================================================================* * do_signal * *===========================================================================*/ PUBLIC int do_signal() { /* Perform the signal(sig, func) call by setting bits to indicate that a signal * is to be caught or ignored. */ int mask; if (sig < 1 || sig > NR_SIGS) return(EINVAL); if (sig == SIGKILL) return(OK); /* SIGKILL may not ignored/caught */ mask = 1 << (sig - 1); /* singleton set with 'sig' bit on */ /* All this func does is set the bit maps for subsequent sig processing. */ if (func == SIG_IGN) { mp->mp_ignore |= mask; mp->mp_catch &= ~mask; } else if (func == SIG_DFL) { mp->mp_ignore &= ~mask; mp->mp_catch &= ~mask; } else { mp->mp_ignore &= ~mask; mp->mp_catch |= mask; mp->mp_func = func; } return(OK); } /*===========================================================================* * do_kill * *===========================================================================*/ PUBLIC int do_kill() { /* Perform the kill(pid, kill_sig) system call. */ return check_sig(pid, kill_sig, mp->mp_effuid); } /*===========================================================================* * do_ksig * *===========================================================================*/ PUBLIC int do_ksig() { /* Certain signals, such as segmentation violations and DEL, originate in the * kernel. When the kernel detects such signals, it sets bits in a bit map. * As soon is MM is awaiting new work, the kernel sends MM a message containing * the process slot and bit map. That message comes here. The File System * also uses this mechanism to signal writing on broken pipes (SIGPIPE). */ register struct mproc *rmp; int i, proc_id, proc_nr, id; unshort sig_map; /* bits 0 - 15 for sigs 1 - 16 */ /* Only kernel and FS may make this call. */ if (who != HARDWARE && who != FS_PROC_NR) return(EPERM); proc_nr = mm_in.PROC1; rmp = &mproc[proc_nr]; if ( (rmp->mp_flags & IN_USE) == 0 || (rmp->mp_flags & HANGING) ) return(OK); proc_id = rmp->mp_pid; sig_map = (unshort) mm_in.SIG_MAP; mp = &mproc[0]; /* pretend kernel signals are from MM */ mp->mp_procgrp = rmp->mp_procgrp; /* get process group right */ /* Stack faults are passed from kernel to MM as pseudo-signal 16. */ if (sig_map == 1 << (STACK_FAULT - 1)) { stack_fault(proc_nr); return(OK); } /* Check each bit in turn to see if a signal is to be sent. Unlike * kill(), the kernel may collect several unrelated signals for a process * and pass them to MM in one blow. Thus loop on the bit map. For SIGINT * and SIGQUIT, use proc_id 0, since multiple processes may have to signalled. */ for (i = 0; i < NR_SIGS; i++) { id= (i+1 == SIGINT || i+1 == SIGQUIT ? 0 : proc_id); if (i + 1 == SIGKILL) id = -1; /* simulate kill -1 9 */ if ( (sig_map >> i) & 1) check_sig(id, i + 1, SUPER_USER); } dont_reply = TRUE; /* don't reply to the kernel */ return(OK); } /*===========================================================================* * check_sig * *===========================================================================*/ PRIVATE int check_sig(proc_id, sig_nr, send_uid) int proc_id; /* pid of process to signal, or 0 or -1 */ int sig_nr; /* which signal to send (1-16) */ uid send_uid; /* identity of process sending the signal */ { /* Check to see if it is possible to send a signal. The signal may have to be * sent to a group of processes. This routine is invoked by the KILL system * call, and also when the kernel catches a DEL or other signal. SIGALRM too. */ register struct mproc *rmp; int count, send_sig; unshort mask; extern unshort core_bits; if (sig_nr < 1 || sig_nr > NR_SIGS) return(EINVAL); count = 0; /* count # of signals sent */ mask = 1 << (sig_nr - 1); /* Search the proc table for processes to signal. Several tests are made: * - if proc's uid != sender's, and sender is not superuser, don't signal * - if specific process requested (i.e., 'procpid' > 0, check for match * - if a process has already exited, it can't receive signals * - if 'proc_id' is 0 signal everyone in same process group except caller */ for (rmp = &mproc[INIT_PROC_NR + 1]; rmp < &mproc[NR_PROCS]; rmp++ ) { if ( (rmp->mp_flags & IN_USE) == 0) continue; send_sig = TRUE; /* if it's FALSE at end of loop, don't signal */ if (send_uid != rmp->mp_effuid && send_uid != SUPER_USER)send_sig=FALSE; if (proc_id > 0 && proc_id != rmp->mp_pid) send_sig = FALSE; if (rmp->mp_flags & HANGING) send_sig = FALSE; /*don't wake the dead*/ if (proc_id == 0 && mp->mp_procgrp != rmp->mp_procgrp) send_sig = FALSE; if (send_uid == SUPER_USER && proc_id == -1) send_sig = TRUE; /* SIGALARM is a little special. When a process exits, a clock signal * can arrive just as the timer is being turned off. Also, turn off * ALARM_ON bit when timer goes off to keep it accurate. */ if (sig_nr == SIGALRM) { if ( (rmp->mp_flags & ALARM_ON) == 0) continue; rmp->mp_flags &= ~ALARM_ON; } if (send_sig == FALSE || rmp->mp_ignore & mask) continue; count++; /* Send the signal or kill the process, possibly with core dump. */ sig_proc(rmp, sig_nr); /* If process is hanging on PAUSE, WAIT, tty, pipe, etc. release it. */ unpause(rmp - mproc); /* check to see if process is paused */ if (proc_id > 0) break; /* only one process being signalled */ } /* If the calling process has killed itself, don't reply. */ if ((mp->mp_flags & IN_USE) == 0 || (mp->mp_flags & HANGING))dont_reply =TRUE; return(count > 0 ? OK : ESRCH); } /*===========================================================================* * sig_proc * *===========================================================================*/ PUBLIC sig_proc(rmp, sig_nr) register struct mproc *rmp; /* pointer to the process to be signalled */ int sig_nr; /* signal to send to process (1-16) */ { /* Send a signal to a process. Check to see if the signal is to be caught. * If so, the pc, psw, and signal number are to be pushed onto the process' * stack. If the stack cannot grow or the signal is not to be caught, kill * the process. */ unshort mask; int core_file; vir_bytes new_sp; extern unshort core_bits; if ( (rmp->mp_flags & IN_USE) == 0) return; /* if already dead forget it */ mask = 1 << (sig_nr - 1); if (rmp->mp_catch & mask) { /* Signal should be caught. */ rmp->mp_catch &= ~mask; /* disable further signals */ sys_getsp(rmp - mproc, &new_sp); new_sp -= SIG_PUSH_BYTES; if (adjust(rmp, rmp->mp_seg[D].mem_len, new_sp) == OK) { sys_sig(rmp - mproc, sig_nr, rmp->mp_func); return; /* successful signal */ } } /* Signal should not or cannot be caught. Take default KMNOPQRaction. */ core_file = ( core_bits >> (sig_nr - 1 )) & 1; rmp->mp_sigstatus = (char) sig_nr; if (core_file) dump_core(rmp); /* dump core */ mm_exit(rmp, 0); /* terminate process */ } /*===========================================================================* * do_alarm * *===========================================================================*/ PUBLIC int do_alarm() { /* Perform the alarm(seconds) system call. */ register int r; unsigned sec; sec = (unsigned) seconds; r = set_alarm(who, sec); return(r); } /*===========================================================================* * set_alarm * *===========================================================================*/ PUBLIC int set_alarm(proc_nr, sec) int proc_nr; /* process that wants the alarm */ unsigned sec; /* how many seconds delay before the signal */ { /* This routine is used by do_alarm() to set the alarm timer. It is also * to turn the timer off when a process exits with the timer still on. */ int remaining; m_sig.m_type = SET_ALARM; m_sig.CLOCK_PROC_NR = proc_nr; m_sig.DELTA_TICKS = HZ * sec; if (sec != 0) mproc[proc_nr].mp_flags |= ALARM_ON; /* turn ALARM_ON bit on */ else mproc[proc_nr].mp_flags &= ~ALARM_ON; /* turn ALARM_ON bit off */ /* Tell the clock task to provide a signal message when the time comes. */ if (sendrec(CLOCK, &m_sig) != OK) panic("alarm er", NO_NUM); remaining = (int) m_sig.SECONDS_LEFT; return(remaining); } /*===========================================================================* * do_pause * *===========================================================================*/ PUBLIC int do_pause() { /* Perform the pause() system call. */ mp->mp_flags |= PAUSED; /* turn on PAUSE bit */ dont_reply = TRUE; return(OK); } /*===========================================================================* * unpause * *===========================================================================*/ PUBLIC unpause(pro) int pro; /* which process number */ { /* A signal is to be sent to a process. It that process is hanging on a * system call, the system call must be terminated with EINTR. Possible * calls are PAUSE, WAIT, READ and WRITE, the latter two for pipes and ttys. * First check if the process is hanging on PAUSE or WAIT. If not, tell FS, * so it can check for READs and WRITEs from pipes, ttys and the like. */ register struct mproc *rmp; rmp = &mproc[pro]; /* Check to see if process is hanging on PAUSE call. */ if ( (rmp->mp_flags & PAUSED) && (rmp->mp_flags & HANGING) == 0) { rmp->mp_flags &= ~PAUSED; /* turn off PAUSED bit */ reply(pro, EINTR, 0, NIL_PTR); return; } /* Check to see if process is hanging on a WAIT call. */ if ( (rmp->mp_flags & WAITING) && (rmp->mp_flags & HANGING) == 0) { rmp->mp_flags &= ~ WAITING; /* turn off WAITING bit */ reply(pro, EINTR, 0, NIL_PTR); return; } /* Process is not hanging on an MM call. Ask FS to take a look. */ tell_fs(UNPAUSE, pro, 0, 0); return; } /*===========================================================================* * dump_core * *===========================================================================*/ PRIVATE dump_core(rmp) register struct mproc *rmp; /* whose core is to be dumped */ { /* Make a core dump on the file "core", if possible. */ struct stat s_buf, d_buf; char buf[DUMP_SIZE]; int i, r, s, er1, er2, slot; vir_bytes v_buf; long len, a, c, ct, dest; struct mproc *xmp; extern char core_name[]; /* Change to working directory of dumpee. */ slot = rmp - mproc; tell_fs(CHDIR, slot, 0, 0); /* Can core file be written? */ if (rmp->mp_realuid != rmp->mp_effuid) { tell_fs(CHDIR, 0, 1, 0); /* go back to MM's directory */ return; } xmp = mp; /* allowed() looks at 'mp' */ mp = rmp; r = allowed(core_name, &s_buf, W_BIT); /* is core_file writable */ s = allowed(".", &d_buf, W_BIT); /* is directory writable? */ mp = xmp; if (r >= 0) close(r); if (s >= 0) close(s); if (rmp->mp_effuid == SUPER_USER) r = 0; /* su can always dump core */ if (s >= 0 && (r >= 0 || r == ENOENT)) { /* Either file is writable or it doesn't exist & dir is writable */ r = creat(core_name, CORE_MODE); tell_fs(CHDIR, 0, 1, 0); /* go back to MM's own dir */ if (r < 0) return; rmp->mp_sigstatus |= DUMPED; /* First loop through segments and write each length on core file. */ for (i = 0; i < NR_SEGS; i++) { len = rmp->mp_seg[i].mem_len << CLICK_SHIFT; if (write(r, (char *) &len, sizeof len) < 0) { close(r); return; } } /* Now loop through segments and write the segments themselves out. */ v_buf = (vir_bytes) buf; dest = (long) v_buf; for (i = 0; i < NR_SEGS; i++) { a = (phys_bytes) rmp->mp_seg[i].mem_vir << CLICK_SHIFT; c = (phys_bytes) rmp->mp_seg[i].mem_len << CLICK_SHIFT; /* Loop through a segment, dumping it. */ while (c > 0) { ct = MIN(c, DUMP_SIZE); er1 = mem_copy(slot, i, a, MM_PROC_NR, D, dest, ct); er2 = write(r, buf, (int) ct); if (er1 < 0 || er2 < 0) { close(r); return; } a += ct; c -= ct; } } } else { tell_fs(CHDIR, 0, 1, 0); /* go back to MM's own dir */ close(r); return; } close(r); } /* This file contains the table used to map system call numbers onto the * routines that perform them. */ #include "../h/const.h" #include "../h/type.h" #include "const.h" #undef EXTERN #define EXTERN #include "../h/callnr.h" #include "glo.h" #include "mproc.h" #include "param.h" /* Miscellaneous */ char core_name[] = {"core"}; /* file name where core images are produced */ unshort core_bits = 0x0EFC; /* which signals cause core images */ extern char mm_stack[]; char *stackpt = &mm_stack[MM_STACK_BYTES]; /* initial stack pointer */ extern do_mm_exit(), do_fork(), do_wait(), do_brk(), do_getset(), do_exec(); extern do_signal(), do_kill(), do_pause(), do_alarm(); extern no_sys(), unpause(), do_ksig(), do_brk2(); int (*call_vec[NCALLS])() = { no_sys, /* 0 = unused */ do_mm_exit, /* 1 = exit */ do_fork, /* 2 = fork */ no_sys, /* 3 = read */ no_sys, /* 4 = write */ no_sys, /* 5 = open */ no_sys, /* 6 = close */ do_wait, /* 7 = wait */ no_sys, /* 8 = creat */ no_sys, /* 9 = link */ no_sys, /* 10 = unlink */ no_sys, /* 11 = exec */ no_sys, /* 12 = chdir */ no_sys, /* 13 = time */ no_sys, /* 14 = mknod */ no_sys, /* 15 = chmod */ no_sys, /* 16 = chown */ do_brk, /* 17 = break */ no_sys, /* 18 = stat */ no_sys, /* 19 = lseek */ do_getset, /* 20 = getpid */ no_sys, /* 21 = mount */ no_sys, /* 22 = umount */ do_getset, /* 23 = setuid */ do_getset, /* 24 = getuid */ no_sys, /* 25 = stime */ no_sys, /* 26 = (ptrace)*/ do_alarm, /* 27 = alarm */ no_sys, /* 28 = fstat */ do_pause, /* 29 = pause */ no_sys, /* 30 = utime */ no_sys, /* 31 = (stty) */ no_sys, /* 32 = (gtty) */ no_sys, /* 33 = access */ no_sys, /* 34 = (nice) */ no_sys, /* 35 = (ftime) */ no_sys, /* 36 = sync */ do_kill, /* 37 = kill */ no_sys, /* 38 = unused */ no_sys, /* 39 = unused */ no_sys, /* 40 = unused */ no_sys, /* 41 = dup */ no_sys, /* 42 = pipe */ no_sys, /* 43 = times */ no_sys, /* 44 = (prof) */ no_sys, /* 45 = unused */ do_getset, /* 46 = setgid */ do_getset, /* 47 = getgid */ do_signal, /* 48 = sig */ no_sys, /* 49 = unused */ no_sys, /* 50 = unused */ no_sys, /* 51 = (acct) */ no_sys, /* 52 = (phys) */ no_sys, /* 53 = (lock) */ no_sys, /* 54 = ioctl */ no_sys, /* 55 = unused */ no_sys, /* 56 = (mpx) */ no_sys, /* 57 = unused */ no_sys, /* 58 = unused */ do_exec, /* 59 = exece */ no_sys, /* 60 = umask */ no_sys, /* 61 = chroot */ no_sys, /* 62 = unused */ no_sys, /* 63 = unused */ do_ksig, /* 64 = KSIG: signals originating in the kernel */ no_sys, /* 65 = UNPAUSE */ do_brk2, /* 66 = BRK2 (used to tell MM size of FS,INIT) */ no_sys, /* 67 = REVIVE */ no_sys /* 68 = TASK_REPLY */ }; /* This file contains some useful utility routines used by MM. * * The entries into the file are: * allowed: see if an access is permitted * mem_copy: copy data from somewhere in memory to somewhere else * no_sys: this routine is called for invalid system call numbers * panic: MM has run aground of a fatal error and cannot continue */ #include "../h/const.h" #include "../h/type.h" #include "../h/callnr.h" #include "../h/com.h" #include "../h/error.h" #include "../h/stat.h" #include "const.h" #include "glo.h" #include "mproc.h" PRIVATE message copy_mess; /*===========================================================================* * allowed * *===========================================================================*/ PUBLIC int allowed(name_buf, s_buf, mask) char *name_buf; /* pointer to file name to be EXECed */ struct stat *s_buf; /* buffer for doing and returning stat struct */ int mask; /* R_BIT, W_BIT, or X_BIT */ { /* Check to see if file can be accessed. Return EACCES or ENOENT if the access * is prohibited. If it is legal open the file and return a file descriptor. */ register int fd, shift; int mode; extern errno; /* Open the file and stat it. */ if ( (fd = open(name_buf, 0)) < 0) return(-errno); if (fstat(fd, s_buf) < 0) panic("allowed: fstat failed", NO_NUM); /* Only regular files can be executed. */ mode = s_buf->st_mode & I_TYPE; if (mask == X_BIT && mode != I_REGULAR) { close(fd); return(EACCES); } /* Even for superuser, at least 1 X bit must be on. */ if (mp->mp_effuid == SUPER_USER && mask == X_BIT && (s_buf->st_mode & (X_BIT << 6 | X_BIT << 3 | X_BIT))) return(fd); /* Right adjust the relevant set of permission bits. */ if (mp->mp_effuid == s_buf->st_uid) shift = 6; else if (mp->mp_effgid == s_buf->st_gid) shift = 3; else shift = 0; if (mp->mp_effuid == SUPER_USER && mask != X_BIT) return(fd); if (s_buf->st_mode >> shift & mask) /* test the relevant bits */ return(fd); /* permission granted */ else { close(fd); /* permission denied */ return(EACCES); } } /*===========================================================================* * mem_copy * *===========================================================================*/ PUBLIC int mem_copy(src_proc,src_seg, src_vir, dst_proc,dst_seg, dst_vir, bytes) int src_proc; /* source process */ int src_seg; /* source segment: T, D, or S */ long src_vir; /* source virtual address (clicks for ABS) */ int dst_proc; /* dest process */ int dst_seg; /* dest segment: T, D, or S */ long dst_vir; /* dest virtual address (clicks for ABS) */ long bytes; /* how many bytes (clicks for ABS) */ { /* Transfer a block of data. The source and destination can each either be a * process (including MM) or absolute memory, indicate by setting 'src_proc' * or 'dst_proc' to ABS. */ if (bytes == 0L) return(OK); copy_mess.SRC_SPACE = (char) src_seg; copy_mess.SRC_PROC_NR = src_proc; copy_mess.SRC_BUFFER = src_vir; copy_mess.DST_SPACE = (char) dst_seg; copy_mess.DST_PROC_NR = dst_proc; copy_mess.DST_BUFFER = dst_vir; copy_mess.COPY_BYTES = bytes; sys_copy(©_mess); return(copy_mess.m_type); } /*===========================================================================* * no_sys * *===========================================================================*/ PUBLIC int no_sys() { /* A system call number not implemented by MM has been requested. */ return(EINVAL); } /*===========================================================================* * panic * *===========================================================================*/ PUBLIC panic(format, num) char *format; /* format string */ int num; /* number to go with format string */ { /* Something awful has happened. Panics are caused when an internal * inconsistency is detected, e.g., a programm_ing error or illegal value of a * defined constant. */ printf("Memory manager panic: %s ", format); if (num != NO_NUM) printf("%d",num); printf("\n"); tell_fs(SYNC, 0, 0, 0); /* flush the cache to the disk */ sys_abort(); } ,...-makefileCFLAGS = -Di8088 -w -F -T. h=../h l=/usr/lib obj = main.s forkexit.s break.s exec.s signal.s getset.s \ alloc.s utility.s table.s putc.s mm: makefile $l/head.s $(obj) $l/libc.a $l/end.s @echo "Start linking MM." @echo "If RAM disk fills up, edit makefile to use asld -T. " @echo "On a PC, /lib/* will be removed to make space on RAM disk" @rm -f /lib/cem /tmp/* @asld -o mm $l/head.s $(obj) $l/libc.a $l/end.s @echo "MM done. On a PC, please restore /lib/cem manually" alloc.s: const.h $h/const.h $h/type.h break.s: const.h $h/const.h $h/type.h break.s: $h/error.h break.s: $h/signal.h break.s: glo.h break.s: mproc.h break.s: param.h exec.s: const.h $h/const.h $h/type.h exec.s: $h/callnr.h exec.s: $h/error.h exec.s: $h/stat.h exec.s: glo.h exec.s: mproc.h exec.s: param.h forkexit.s: const.h $h/const.h $h/type.h forkexit.s: $h/callnr.h forkexit.s: $h/error.h forkexit.s: glo.h forkexit.s: mproc.h forkexit.s: param.h getset.s: const.h $h/const.h $h/type.h getset.s: $h/callnr.h getset.s: $h/error.h getset.s: glo.h getset.s: mproc.h getset.s: param.h main.s: const.h $h/const.h $h/type.h main.s: $h/callnr.h main.s: $h/com.h main.s: $h/error.h main.s: glo.h main.s: mproc.h main.s: param.h putc.s: $h/const.h $h/type.h putc.s: $h/com.h signal.s: const.h $h/const.h $h/type.h signal.s: $h/callnr.h signal.s: $h/com.h signal.s: $h/error.h signal.s: $h/signal.h signal.s: $h/stat.h signal.s: glo.h signal.s: mproc.h signal.s: param.h table.s: const.h $h/const.h $h/type.h table.s: $h/callnr.h table.s: glo.h table.s: mproc.h table.s: param.h utility.s: const.h $h/const.h $h/type.h utility.s: $h/callnr.h utility.s: $h/com.h utility.s: $h/error.h utility.s: $h/stat.h utility.s: glo.h utility.s: mproc.h ..../makefileCFLAGS= -Di8088 -O h=../h l=../lib obj = main.o forkexit.o break.o exec.o signal.o getset.o \ alloc.o utility.o table.o putc.o mm: makefile $l/head.o $(obj) $l/libc.a $l/end.o @echo "Start linking MM" @ld -o mm $l/head.o $(obj) $l/libc.a $l/end.o @echo "MM done" alloc.o: const.h $h/const.h $h/type.h break.o: const.h $h/const.h $h/type.h break.o: $h/error.h break.o: $h/signal.h break.o: glo.h break.o: mproc.h break.o: param.h exec.o: const.h $h/const.h $h/type.h exec.o: $h/callnr.h exec.o: $h/error.h exec.o: $h/stat.h exec.o: glo.h exec.o: mproc.h exec.o: param.h forkexit.o: const.h $h/const.h $h/type.h forkexit.o: $h/callnr.h forkexit.o: $h/error.h forkexit.o: glo.h forkexit.o: mproc.h forkexit.o: param.h getset.o: const.h $h/const.h $h/type.h getset.o: $h/callnr.h getset.o: $h/error.h getset.o: glo.h getset.o: mproc.h getset.o: param.h main.o: const.h $h/const.h $h/type.h main.o: $h/callnr.h main.o: $h/com.h main.o: $h/error.h main.o: glo.h main.o: mproc.h main.o: param.h putc.o: $h/const.h $h/type.h putc.o: $h/com.h signal.o: const.h $h/const.h $h/type.h signal.o: $h/callnr.h signal.o: $h/com.h signal.o: $h/error.h signal.o: $h/signal.h signal.o: $h/stat.h signal.o: glo.h signal.o: mproc.h signal.o: param.h table.o: const.h $h/const.h $h/type.h table.o: $h/callnr.h table.o: glo.h table.o: mproc.h table.o: param.h utility.o: const.h $h/const.h $h/type.h utility.o: $h/callnr.h utility.o: $h/com.h utility.o: $h/error.h utility.o: $h/stat.h utility.o: glo.h utility.o: mproc.h 0...1batch.ae˙_link.batT֖ ¤Îecho Linking memory manager link/m ..\lib\head+ link.lst dos2out mm >dos2out.lst >dos2out.lst echo/ echo MM done. Check the .lst-files for errors. pause echo on for %%f in (*.lst) do type %%f linklistT֖ ¤Tmain+forkexit+break+exec+signal+ getset+alloc+utility+table+putc mm mm ..\lib\mxc86 make.batč /} ¤Ň echo off if "%1"=="-l" _link.bat echo/ echo Making Memory Manager echo/ echo To re-make the memory manager after you changed echo a module, just delete the .OBJ file for that module. echo Specifying a '-l' switch will only do the linking echo/ cd ..\lib if exist head.OBJ goto cc masm head,,nul,nul >head.lst :cc cd ..\mm if exist EXEC.OBJ goto fout echo compiling: exec cc1 -di8088 exec >exec.lst if errorlevel 1 goto fout cc2 exec >>exec.lst if errorlevel 1 goto fout cc3 exec>>exec.lst if errorlevel 1 goto fout cc4 exec>>exec.lst :fout if exist ALLOC.OBJ goto fout2 echo compiling: alloc cc1 -di8088 alloc>alloc.lst if errorlevel 1 goto fout2 cc2 alloc>>alloc.lst if errorlevel 1 goto fout2 cc3 alloc>>alloc.lst if errorlevel 1 goto fout2 cc4 alloc>>alloc.lst :fout2 if exist BREAK.OBJ goto fout3 echo compiling: break cc1 -di8088 break>break.lst if errorlevel 1 goto fout3 cc2 break >>break.lst if errorlevel 1 goto fout3 cc3 break >>break.lst if errorlevel 1 goto fout3 cc4 break >>break.lst :fout3 rem if exist FORKEXIT.OBJ goto fout4 echo compiling: forkexit cc1 -di8088 forkexit >forkexit.lst if errorlevel 1 goto fout4 cc2 forkexit >>forkexit.lst if errorlevel 1 goto fout4 cc3 forkexit >>forkexit.lst if errorlevel 1 goto fout4 cc4 forkexit >>forkexit.lst :fout4 if exist getset.OBJ goto fout5 echo compiling: getset cc1 -di8088 getset >getset.lst if errorlevel 1 goto fout5 cc2 getset >>getset.lst if errorlevel 1 goto fout5 cc3 getset >>getset.lst if errorlevel 1 goto fout5 cc4 getset >>getset.lst :fout5 if exist main.OBJ goto fout6 echo compiling: main cc1 -di8088 main >>main.lst if errorlevel 1 goto fout6 cc2 main >>main.lst if errorlevel 1 goto fout6 cc3 main >>main.lst if errorlevel 1 goto fout6 cc4 main >>main.lst :fout6 if exist putc.OBJ goto fout7 echo compiling: putc cc1 -di8088 putc >putc.lst if errorlevel 1 goto fout7 cc2 putc >>putc.lst if errorlevel 1 goto fout7 cc3 putc >>putc.lst if errorlevel 1 goto fout7 cc4 putc >>putc.lst :fout7 if exist signal.OBJ goto fout8 echo compiling: signal cc1 -di8088 signal >signal.lst if errorlevel 1 goto fout8 cc2 signal >>signal.lst if errorlevel 1 goto fout8 cc3 signal >>signal.lst if errorlevel 1 goto fout8 cc4 signal >>signal.lst :fout8 if exist table.OBJ goto fout9 echo compiling: table cc1 -di8088 table >table.lst if errorlevel 1 goto fout9 cc2 table >>table.lst if errorlevel 1 goto fout9 cc3 table >>table.lst if errorlevel 1 goto fout9 cc4 table >>table.lst :fout9 if exist utility.OBJ goto fout10 echo compiling: utility cc1 -di8088 utility >utility.lst if errorlevel 1 goto fout10 cc2 utility >>utility.lst if errorlevel 1 goto fout10 cc3 utility >>utility.lst if errorlevel 1 goto fout10 cc4 utility >>utility.lst :fout10 _link.bat l 18 -rw-r--r-- 2 bin 7503 Sep 1 09:00 bootblok.s -rw-r--r-- 2 bin 3158 Sep 1 09:00 fsck1.s -rw-r--r-- 1 bin 4850 Sep 1 09:05 makefile tools/PCIX: total 18 -rw-r--r-- 2 bin 7503 Sep 1 09:00 bootblok.s -rw-r--r-- 2 bin 3158 Sep 1 09:00 fsck1.s -rw-r--r-- 1 bin 4148 Sep 1 09:00 makefile E2˙d--75511