From 4f02227b21480c3b83b805f894e227221c5e5b4c Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 31 Oct 2014 12:13:21 +0000 Subject: [PATCH] fuzix: Halloween Release First cut of the development tree. Not terribly useful but hey its hackable and boots. --- Applications/ASM/init.s | 38 + Applications/util/Makefile | 92 + Applications/util/basename.c | 58 + Applications/util/bd.c | 67 + Applications/util/cal.c | 493 ++++ Applications/util/cat.c | 102 + Applications/util/chgrp.c | 56 + Applications/util/chmod.c | 263 ++ Applications/util/chown.c | 56 + Applications/util/cp.c | 183 ++ Applications/util/cut.c | 339 +++ Applications/util/date.c | 12 + Applications/util/dd.c | 289 ++ Applications/util/df.c | 124 + Applications/util/dirent.h | 24 + Applications/util/dirname.c | 37 + Applications/util/du.c | 228 ++ Applications/util/dumb.c | 4 + Applications/util/echo.c | 53 + Applications/util/ed.c | 1170 ++++++++ Applications/util/false.c | 6 + Applications/util/fsck.c | 797 +++++ Applications/util/grep.c | 161 + Applications/util/grp.h | 37 + Applications/util/id.c | 52 + Applications/util/init.c | 212 ++ Applications/util/kill.c | 63 + Applications/util/ll.c | 131 + Applications/util/ln.c | 119 + Applications/util/ls.c | 342 +++ Applications/util/mkdir.c | 53 + Applications/util/mkfs.c | 175 ++ Applications/util/mknod.c | 42 + Applications/util/more.c | 122 + Applications/util/mount.c | 82 + Applications/util/mv.c | 209 ++ Applications/util/od.c | 308 ++ Applications/util/passwd.c | 140 + Applications/util/patchcpm.c | 93 + Applications/util/printenv.c | 37 + Applications/util/prtroot.c | 71 + Applications/util/ps.c | 131 + Applications/util/pwd.c | 14 + Applications/util/pwd.h | 40 + Applications/util/rm.c | 28 + Applications/util/rmdir.c | 47 + Applications/util/sleep.c | 76 + Applications/util/ssh.c | 166 ++ Applications/util/su.c | 97 + Applications/util/sync.c | 6 + Applications/util/termcap.c | 504 ++++ Applications/util/termcap.h | 11 + Applications/util/tget.c | 99 + Applications/util/touch.c | 30 + Applications/util/tr.c | 172 ++ Applications/util/true.c | 6 + Applications/util/umount.c | 89 + Applications/util/uniq.c | 192 ++ Applications/util/uud.c | 437 +++ Applications/util/uue.c | 192 ++ Applications/util/wc.c | 148 + Applications/util/which.c | 48 + Applications/util/whoami.c | 18 + Kernel/BUGS | 2 + Kernel/COPYING | 339 +++ Kernel/Makefile | 163 ++ Kernel/PORTING | 606 ++++ Kernel/README | 929 ++++++ Kernel/TODO | 47 + Kernel/bank16k.c | 135 + Kernel/bank32k.c | 122 + Kernel/bankfixed.c | 52 + Kernel/cpm-emulator/README.WRS | 3 + Kernel/cpm-emulator/emulator.s | 1547 ++++++++++ Kernel/cpu-6502/cpu.h | 21 + Kernel/cpu-6809/cpu.h | 22 + Kernel/cpu-z80/cpu.h | 29 + Kernel/devio.c | 526 ++++ Kernel/devsys.c | 93 + Kernel/filesys.c | 1076 +++++++ Kernel/font4x6.c | 139 + Kernel/font8x8.c | 2579 +++++++++++++++++ Kernel/include/devsys.h | 3 + Kernel/include/kdata.h | 68 + Kernel/include/kernel.h | 771 +++++ Kernel/include/printf.h | 8 + Kernel/include/syscall_name.h | 64 + Kernel/include/timer.h | 13 + Kernel/include/tty.h | 227 ++ Kernel/include/version.h | 7 + Kernel/include/vt.h | 17 + Kernel/inode.c | 236 ++ Kernel/kdata.c | 99 + Kernel/kernel.def | 32 + Kernel/kernel02.def | 32 + Kernel/kernel09.def | 32 + Kernel/lowlevel-6502.s | 30 + Kernel/lowlevel-6809.s | 464 +++ Kernel/lowlevel-z80.s | 523 ++++ Kernel/makeversion | 27 + Kernel/mm.c | 31 + Kernel/platform-6502test/Makefile | 32 + Kernel/platform-6502test/commonmem.s | 25 + Kernel/platform-6502test/config.h | 60 + Kernel/platform-6502test/crt0.s | 42 + Kernel/platform-6502test/device.h | 6 + Kernel/platform-6502test/devices.c | 43 + Kernel/platform-6502test/devlpr.c | 54 + Kernel/platform-6502test/devlpr.h | 8 + Kernel/platform-6502test/devrd.c | 69 + Kernel/platform-6502test/devrd.h | 13 + Kernel/platform-6502test/devtty.c | 67 + Kernel/platform-6502test/devtty.h | 7 + Kernel/platform-6502test/kernel.def | 7 + Kernel/platform-6502test/ld65.cfg | 15 + Kernel/platform-6502test/libc.c | 17 + Kernel/platform-6502test/main.c | 50 + Kernel/platform-6502test/p6502.s | 199 ++ Kernel/platform-6502test/tricks.s | 191 ++ Kernel/platform-6809test/Makefile | 32 + Kernel/platform-6809test/commonmem.s | 27 + Kernel/platform-6809test/config.h | 55 + Kernel/platform-6809test/crt0.s | 44 + Kernel/platform-6809test/device.h | 6 + Kernel/platform-6809test/devices.c | 43 + Kernel/platform-6809test/devlpr.c | 54 + Kernel/platform-6809test/devlpr.h | 8 + Kernel/platform-6809test/devrd.c | 69 + Kernel/platform-6809test/devrd.h | 13 + Kernel/platform-6809test/devtty.c | 65 + Kernel/platform-6809test/devtty.h | 7 + Kernel/platform-6809test/kernel.def | 5 + Kernel/platform-6809test/libc.c | 34 + Kernel/platform-6809test/main.c | 50 + Kernel/platform-6809test/p6809.s | 223 ++ Kernel/platform-6809test/tricks.s | 201 ++ Kernel/platform-micropack/Makefile | 25 + Kernel/platform-micropack/README | 8 + Kernel/platform-micropack/bootblock.s | 80 + Kernel/platform-micropack/commonmem.s | 47 + Kernel/platform-micropack/config.h | 47 + Kernel/platform-micropack/crt0.s | 64 + Kernel/platform-micropack/devfd.c | 149 + Kernel/platform-micropack/devfd.h | 15 + Kernel/platform-micropack/devices.c | 43 + Kernel/platform-micropack/devlpr.c | 38 + Kernel/platform-micropack/devlpr.h | 8 + Kernel/platform-micropack/devtty.c | 90 + Kernel/platform-micropack/devtty.h | 7 + Kernel/platform-micropack/kernel.def | 4 + Kernel/platform-micropack/main.c | 28 + Kernel/platform-micropack/tricks.s | 223 ++ Kernel/platform-micropack/uzi.lnk | 36 + Kernel/platform-micropack/z80pack.s | 147 + Kernel/platform-nc100/Makefile | 26 + Kernel/platform-nc100/README | 53 + Kernel/platform-nc100/bootblock.s | 55 + Kernel/platform-nc100/commonmem.s | 49 + Kernel/platform-nc100/config.h | 45 + Kernel/platform-nc100/crt0.s | 66 + Kernel/platform-nc100/device.h | 6 + Kernel/platform-nc100/devices.c | 49 + Kernel/platform-nc100/devlpr.c | 56 + Kernel/platform-nc100/devlpr.h | 8 + Kernel/platform-nc100/devrd.c | 69 + Kernel/platform-nc100/devrd.h | 13 + Kernel/platform-nc100/devtty.c | 261 ++ Kernel/platform-nc100/devtty.h | 7 + Kernel/platform-nc100/kernel.def | 5 + Kernel/platform-nc100/main.c | 40 + Kernel/platform-nc100/nc100.s | 581 ++++ Kernel/platform-nc100/nc100emu.s | 43 + Kernel/platform-nc100/tricks.s | 240 ++ Kernel/platform-nc100/uzi.lnk | 38 + Kernel/platform-pcw8256/BOOTBLOCK/765.s | 302 ++ Kernel/platform-pcw8256/BOOTBLOCK/765.s.old | 282 ++ Kernel/platform-pcw8256/BOOTBLOCK/765.s~ | 302 ++ Kernel/platform-pcw8256/BOOTBLOCK/bootcsum | Bin 0 -> 41484 bytes Kernel/platform-pcw8256/BOOTBLOCK/bootcsum.c | 21 + Kernel/platform-pcw8256/BOOTBLOCK/sector2.s | 60 + Kernel/platform-pcw8256/BOOTBLOCK/sector2.s~ | 60 + .../platform-pcw8256/BOOTBLOCK/zout/765.ams | Bin 0 -> 640 bytes .../platform-pcw8256/BOOTBLOCK/zout/765.bds | 588 ++++ .../platform-pcw8256/BOOTBLOCK/zout/765.cas | Bin 0 -> 857 bytes .../platform-pcw8256/BOOTBLOCK/zout/765.cim | Bin 0 -> 512 bytes .../platform-pcw8256/BOOTBLOCK/zout/765.cmd | Bin 0 -> 520 bytes .../platform-pcw8256/BOOTBLOCK/zout/765.hex | 33 + .../platform-pcw8256/BOOTBLOCK/zout/765.lcas | Bin 0 -> 791 bytes .../BOOTBLOCK/zout/sector2.ams | Bin 0 -> 265 bytes .../BOOTBLOCK/zout/sector2.bds | 122 + .../BOOTBLOCK/zout/sector2.cas | Bin 0 -> 429 bytes .../BOOTBLOCK/zout/sector2.cim | Bin 0 -> 136 bytes .../BOOTBLOCK/zout/sector2.cmd | Bin 0 -> 140 bytes .../BOOTBLOCK/zout/sector2.hex | 10 + .../BOOTBLOCK/zout/sector2.lcas | Bin 0 -> 410 bytes Kernel/platform-pcw8256/Makefile | 25 + Kernel/platform-pcw8256/README | 13 + Kernel/platform-pcw8256/commonmem.s | 50 + Kernel/platform-pcw8256/config.h | 54 + Kernel/platform-pcw8256/crt0.s | 150 + Kernel/platform-pcw8256/devfd.c | 220 ++ Kernel/platform-pcw8256/devfd.h | 28 + Kernel/platform-pcw8256/devices.c | 64 + Kernel/platform-pcw8256/devlpr.c | 38 + Kernel/platform-pcw8256/devlpr.h | 8 + Kernel/platform-pcw8256/devtty.c | 243 ++ Kernel/platform-pcw8256/devtty.h | 8 + Kernel/platform-pcw8256/fdc765.s | 248 ++ Kernel/platform-pcw8256/kernel.def | 4 + Kernel/platform-pcw8256/main.c | 52 + Kernel/platform-pcw8256/pcw8256.h | 52 + Kernel/platform-pcw8256/pcw8256.s | 467 +++ Kernel/platform-pcw8256/tricks.s | 272 ++ Kernel/platform-trs80/Makefile | 25 + Kernel/platform-trs80/README | 53 + Kernel/platform-trs80/commonmem.s | 48 + Kernel/platform-trs80/config.h | 54 + Kernel/platform-trs80/crt0.s | 80 + Kernel/platform-trs80/devfd.c | 249 ++ Kernel/platform-trs80/devfd.h | 9 + Kernel/platform-trs80/devices.c | 36 + Kernel/platform-trs80/devlpr.c | 38 + Kernel/platform-trs80/devlpr.h | 8 + Kernel/platform-trs80/devtty.c | 55 + Kernel/platform-trs80/devtty.h | 6 + Kernel/platform-trs80/kernel.def | 5 + Kernel/platform-trs80/main.c | 27 + Kernel/platform-trs80/tricks.s | 192 ++ Kernel/platform-trs80/trs80.s | 358 +++ Kernel/platform-trs80/trsfd.s | 123 + Kernel/platform-trs80/uzi.lnk | 37 + Kernel/platform-z80pack-lite/Makefile | 25 + Kernel/platform-z80pack-lite/README | 6 + Kernel/platform-z80pack-lite/bootblock.s | 80 + Kernel/platform-z80pack-lite/commonmem.s | 48 + Kernel/platform-z80pack-lite/config.h | 31 + Kernel/platform-z80pack-lite/crt0.s | 71 + Kernel/platform-z80pack-lite/devfd.c | 125 + Kernel/platform-z80pack-lite/devfd.h | 11 + Kernel/platform-z80pack-lite/devices.c | 50 + Kernel/platform-z80pack-lite/devlpr.c | 38 + Kernel/platform-z80pack-lite/devlpr.h | 8 + Kernel/platform-z80pack-lite/devtty.c | 78 + Kernel/platform-z80pack-lite/devtty.h | 60 + Kernel/platform-z80pack-lite/kernel.def | 4 + Kernel/platform-z80pack-lite/main.c | 14 + Kernel/platform-z80pack-lite/tricks.s | 257 ++ Kernel/platform-z80pack-lite/usermem.s | 327 +++ Kernel/platform-z80pack-lite/uzi.lnk | 36 + Kernel/platform-z80pack-lite/z80pack.s | 352 +++ Kernel/platform-z80pack/Makefile | 25 + Kernel/platform-z80pack/README | 45 + Kernel/platform-z80pack/bootblock.s | 80 + Kernel/platform-z80pack/commonmem.s | 55 + Kernel/platform-z80pack/config.h | 47 + Kernel/platform-z80pack/crt0.s | 67 + Kernel/platform-z80pack/devfd.c | 152 + Kernel/platform-z80pack/devfd.h | 15 + Kernel/platform-z80pack/devices.c | 43 + Kernel/platform-z80pack/devlpr.c | 38 + Kernel/platform-z80pack/devlpr.h | 8 + Kernel/platform-z80pack/devtty.c | 90 + Kernel/platform-z80pack/devtty.h | 7 + Kernel/platform-z80pack/kernel.def | 6 + Kernel/platform-z80pack/main.c | 52 + Kernel/platform-z80pack/tricks.s | 315 ++ Kernel/platform-z80pack/uzi.lnk | 36 + Kernel/platform-z80pack/z80pack.s | 207 ++ Kernel/process.c | 592 ++++ Kernel/select.c | 116 + Kernel/simple.c | 39 + Kernel/single.c | 306 ++ Kernel/start.c | 163 ++ Kernel/swap.c | 224 ++ Kernel/syscall_fs.c | 501 ++++ Kernel/syscall_fs2.c | 656 +++++ Kernel/syscall_other.c | 775 +++++ Kernel/syscall_proc.c | 539 ++++ Kernel/timer.c | 63 + Kernel/tools/analysemap.c | 84 + Kernel/tools/binman.c | 169 ++ Kernel/tools/filesizes.c | 45 + Kernel/tools/make4x6.c | 2170 ++++++++++++++ Kernel/tty.c | 523 ++++ Kernel/unbanked.c | 312 ++ Kernel/usermem.c | 178 ++ Kernel/usermem_std-6502.s | 6 + Kernel/usermem_std-6809.s | 8 + Kernel/usermem_std-z80.s | 193 ++ Kernel/vt.c | 238 ++ LICENSE | 3 + Library/Makefile | 5 + Library/include/alloc.h | 3 + Library/include/ar.h | 18 + Library/include/assert.h | 28 + Library/include/ctype.h | 48 + Library/include/curses.h | 229 ++ Library/include/dirent.h | 55 + Library/include/errno.h | 60 + Library/include/fcntl.h | 55 + Library/include/features.h | 37 + Library/include/float.h | 79 + Library/include/ftw.h | 9 + Library/include/fuzix.h | 351 +++ Library/include/getopt.h | 13 + Library/include/grp.h | 35 + Library/include/limits.h | 28 + Library/include/malloc.h | 13 + Library/include/math.h | 34 + Library/include/memory.h | 3 + Library/include/ncurses.h | 7 + Library/include/paths.h | 27 + Library/include/poll.h | 17 + Library/include/pwd.h | 37 + Library/include/regexp.h | 27 + Library/include/regmagic.h | 5 + Library/include/search.h | 55 + Library/include/setjmp.h | 13 + Library/include/sgtty.h | 42 + Library/include/signal.h | 69 + Library/include/stdio.h | 151 + Library/include/stdlib.h | 92 + Library/include/string.h | 59 + Library/include/strings.h | 3 + Library/include/sys/cdefs.h | 20 + Library/include/sys/errno.h | 58 + Library/include/sys/exec.h | 4 + Library/include/sys/file.h | 15 + Library/include/sys/fp.h | 8 + Library/include/sys/ioctl.h | 5 + Library/include/sys/lock.h | 6 + Library/include/sys/mman.h | 7 + Library/include/sys/mount.h | 7 + Library/include/sys/param.h | 14 + Library/include/sys/resource.h | 7 + Library/include/sys/seek.h | 19 + Library/include/sys/signal.h | 1 + Library/include/sys/stat.h | 59 + Library/include/sys/statfs.h | 16 + Library/include/sys/time.h | 1 + Library/include/sys/times.h | 15 + Library/include/sys/types.h | 60 + Library/include/sys/utsname.h | 18 + Library/include/sys/wait.h | 49 + Library/include/syscalls.h | 143 + Library/include/termcap.h | 22 + Library/include/termio.h | 3 + Library/include/termios.h | 156 + Library/include/time.h | 55 + Library/include/types.h | 11 + Library/include/unistd.h | 100 + Library/include/utime.h | 14 + Library/include/utmp.h | 45 + Library/include/utsname.h | 19 + Library/include/varargs.h | 14 + Library/include/wait.h | 1 + Library/libs/Makefile | 83 + Library/libs/README.regexp | 84 + Library/libs/TODO | 165 ++ Library/libs/__getgrent.c | 168 ++ Library/libs/__getpwent.c | 99 + Library/libs/abort.c | 16 + Library/libs/abs.c | 7 + Library/libs/asctime.c | 54 + Library/libs/assert.c | 25 + Library/libs/atexit.c | 62 + Library/libs/atof.c | 11 + Library/libs/atoi.c | 11 + Library/libs/atol.c | 22 + Library/libs/bcmp.c | 11 + Library/libs/bcopy.c | 13 + Library/libs/bsearch.c | 37 + Library/libs/bzero.c | 11 + Library/libs/calloc.c | 20 + Library/libs/cfmakeraw.c | 11 + Library/libs/cfree.c | 7 + Library/libs/cfspeed.c | 31 + Library/libs/clock.c | 18 + Library/libs/closedir.c | 24 + Library/libs/config-getent.h | 60 + Library/libs/config-grp.h | 57 + Library/libs/confstr.c | 8 + Library/libs/creat.c | 11 + Library/libs/crt0.s | 79 + Library/libs/crypt.c | 69 + Library/libs/ctime.c | 9 + Library/libs/ctype.c | 58 + Library/libs/difftime.c | 22 + Library/libs/errno.c | 3 + Library/libs/error.c | 54 + Library/libs/execl.c | 62 + Library/libs/execv.c | 15 + Library/libs/execvp.c | 13 + Library/libs/exit.c | 15 + Library/libs/fclose.c | 45 + Library/libs/fflush.c | 70 + Library/libs/fgetc.c | 33 + Library/libs/fgetgrent.c | 35 + Library/libs/fgetpos.c | 16 + Library/libs/fgetpwent.c | 35 + Library/libs/fgets.c | 30 + Library/libs/fopen.c | 110 + Library/libs/fprintf.c | 26 + Library/libs/fputc.c | 31 + Library/libs/fputs.c | 14 + Library/libs/fread.c | 53 + Library/libs/free.c | 149 + Library/libs/fscanf.c | 28 + Library/libs/fsetpos.c | 7 + Library/libs/ftell.c | 9 + Library/libs/fuzix/Makefile | 82 + Library/libs/fuzix/syscall.s | 15 + Library/libs/fwrite.c | 68 + Library/libs/getcwd.c | 99 + Library/libs/getenv.c | 22 + Library/libs/getgrgid.c | 48 + Library/libs/getgrnam.c | 51 + Library/libs/gethostname.c | 43 + Library/libs/getopt.c | 117 + Library/libs/getpass.c | 58 + Library/libs/getpw.c | 53 + Library/libs/getpwnam.c | 52 + Library/libs/getpwuid.c | 44 + Library/libs/gets.c | 31 + Library/libs/gmtime.c | 66 + Library/libs/grent.c | 57 + Library/libs/index.c | 11 + Library/libs/initgroups.c | 80 + Library/libs/isatty.c | 14 + Library/libs/itoa.c | 22 + Library/libs/killpg.c | 21 + Library/libs/labs.c | 12 + Library/libs/localtim.c | 9 + Library/libs/lsearch.c | 41 + Library/libs/lseek.c | 11 + Library/libs/lstat.c | 16 + Library/libs/ltoa.c | 32 + Library/libs/ltostr.c | 37 + Library/libs/malloc-l.h | 44 + Library/libs/malloc.c | 281 ++ Library/libs/memccpy.c | 17 + Library/libs/memchr.c | 20 + Library/libs/memcmp.c | 61 + Library/libs/memcpy.c | 31 + Library/libs/memset.c | 44 + Library/libs/mkfifo.c | 12 + Library/libs/opendir.c | 35 + Library/libs/pause.c | 6 + Library/libs/perror.c | 26 + Library/libs/popen.c | 37 + Library/libs/printf.c | 27 + Library/libs/printf.h | 20 + Library/libs/putenv.c | 54 + Library/libs/putgetch.c | 22 + Library/libs/putpwent.c | 39 + Library/libs/pwent.c | 64 + Library/libs/qsort.c | 157 + Library/libs/raise.c | 11 + Library/libs/rand.c | 34 + Library/libs/readdir.c | 39 + Library/libs/readlink.c | 16 + Library/libs/realloc.c | 29 + Library/libs/regerror.c | 13 + Library/libs/regexp.c | 1137 ++++++++ Library/libs/regexp.h | 21 + Library/libs/regmagic.h | 5 + Library/libs/regsub.c | 80 + Library/libs/remove.c | 19 + Library/libs/revoke.c | 7 + Library/libs/rewind.c | 43 + Library/libs/rindex.c | 11 + Library/libs/scanf.c | 28 + Library/libs/setbuffer.c | 24 + Library/libs/setenv.c | 79 + Library/libs/setjmp.c | 147 + Library/libs/setvbuf.c | 34 + Library/libs/sleep.c | 17 + Library/libs/sprintf.c | 37 + Library/libs/sscanf.c | 35 + Library/libs/stat.c | 36 + Library/libs/stdio-l.h | 21 + Library/libs/stdio0.c | 50 + Library/libs/strcasecmp.c | 23 + Library/libs/strcat.c | 14 + Library/libs/strchr.c | 22 + Library/libs/strcmp.c | 16 + Library/libs/strcpy.c | 13 + Library/libs/strcspn.c | 30 + Library/libs/strdup.c | 21 + Library/libs/stricmp.c | 23 + Library/libs/strlen.c | 25 + Library/libs/strncasecmp.c | 24 + Library/libs/strncat.c | 22 + Library/libs/strncpy.c | 26 + Library/libs/strnicmp.c | 24 + Library/libs/strpbrk.c | 19 + Library/libs/strrchr.c | 22 + Library/libs/strsep.c | 35 + Library/libs/strspn.c | 41 + Library/libs/strstr.c | 25 + Library/libs/strtod.c | 99 + Library/libs/strtok.c | 68 + Library/libs/strtol.c | 111 + Library/libs/sysconf.c | 60 + Library/libs/system.c | 48 + Library/libs/tcdrain.c | 10 + Library/libs/tcflow.c | 7 + Library/libs/tcflush.c | 7 + Library/libs/tcgetattr.c | 8 + Library/libs/tcsetattr.c | 14 + Library/libs/time.c | 18 + Library/libs/tmpnam.c | 55 + Library/libs/ttyname.c | 48 + Library/libs/tzset.c | 29 + Library/libs/ultoa.c | 16 + Library/libs/ungetc.c | 22 + Library/libs/utent.c | 150 + Library/libs/utsname.c | 33 + Library/libs/vfprintf.c | 267 ++ Library/libs/vfscanf.c | 463 +++ Library/libs/vprintf.c | 20 + Library/libs/vscanf.c | 23 + Library/libs/vsscanf.c | 30 + Library/libs/wait.c | 6 + Library/libs/xitoa.c | 10 + Library/tools/TODO | 9 + Library/tools/binman.c | 95 + Library/tools/fcc.c | 458 +++ Library/tools/fsize.c | 44 + Library/tools/libclean | 17 + Library/tools/syscall.c | 68 + 531 files changed, 53021 insertions(+) create mode 100644 Applications/ASM/init.s create mode 100644 Applications/util/Makefile create mode 100644 Applications/util/basename.c create mode 100644 Applications/util/bd.c create mode 100644 Applications/util/cal.c create mode 100644 Applications/util/cat.c create mode 100644 Applications/util/chgrp.c create mode 100644 Applications/util/chmod.c create mode 100644 Applications/util/chown.c create mode 100644 Applications/util/cp.c create mode 100644 Applications/util/cut.c create mode 100644 Applications/util/date.c create mode 100644 Applications/util/dd.c create mode 100644 Applications/util/df.c create mode 100644 Applications/util/dirent.h create mode 100644 Applications/util/dirname.c create mode 100644 Applications/util/du.c create mode 100644 Applications/util/dumb.c create mode 100644 Applications/util/echo.c create mode 100644 Applications/util/ed.c create mode 100644 Applications/util/false.c create mode 100644 Applications/util/fsck.c create mode 100644 Applications/util/grep.c create mode 100644 Applications/util/grp.h create mode 100644 Applications/util/id.c create mode 100644 Applications/util/init.c create mode 100644 Applications/util/kill.c create mode 100644 Applications/util/ll.c create mode 100644 Applications/util/ln.c create mode 100644 Applications/util/ls.c create mode 100644 Applications/util/mkdir.c create mode 100644 Applications/util/mkfs.c create mode 100644 Applications/util/mknod.c create mode 100644 Applications/util/more.c create mode 100644 Applications/util/mount.c create mode 100644 Applications/util/mv.c create mode 100644 Applications/util/od.c create mode 100644 Applications/util/passwd.c create mode 100644 Applications/util/patchcpm.c create mode 100644 Applications/util/printenv.c create mode 100644 Applications/util/prtroot.c create mode 100644 Applications/util/ps.c create mode 100644 Applications/util/pwd.c create mode 100644 Applications/util/pwd.h create mode 100644 Applications/util/rm.c create mode 100644 Applications/util/rmdir.c create mode 100644 Applications/util/sleep.c create mode 100644 Applications/util/ssh.c create mode 100644 Applications/util/su.c create mode 100644 Applications/util/sync.c create mode 100644 Applications/util/termcap.c create mode 100644 Applications/util/termcap.h create mode 100644 Applications/util/tget.c create mode 100644 Applications/util/touch.c create mode 100644 Applications/util/tr.c create mode 100644 Applications/util/true.c create mode 100644 Applications/util/umount.c create mode 100644 Applications/util/uniq.c create mode 100644 Applications/util/uud.c create mode 100644 Applications/util/uue.c create mode 100644 Applications/util/wc.c create mode 100644 Applications/util/which.c create mode 100644 Applications/util/whoami.c create mode 100644 Kernel/BUGS create mode 100644 Kernel/COPYING create mode 100644 Kernel/Makefile create mode 100644 Kernel/PORTING create mode 100644 Kernel/README create mode 100644 Kernel/TODO create mode 100644 Kernel/bank16k.c create mode 100644 Kernel/bank32k.c create mode 100644 Kernel/bankfixed.c create mode 100644 Kernel/cpm-emulator/README.WRS create mode 100644 Kernel/cpm-emulator/emulator.s create mode 100644 Kernel/cpu-6502/cpu.h create mode 100644 Kernel/cpu-6809/cpu.h create mode 100644 Kernel/cpu-z80/cpu.h create mode 100644 Kernel/devio.c create mode 100644 Kernel/devsys.c create mode 100644 Kernel/filesys.c create mode 100644 Kernel/font4x6.c create mode 100644 Kernel/font8x8.c create mode 100644 Kernel/include/devsys.h create mode 100644 Kernel/include/kdata.h create mode 100644 Kernel/include/kernel.h create mode 100644 Kernel/include/printf.h create mode 100644 Kernel/include/syscall_name.h create mode 100644 Kernel/include/timer.h create mode 100644 Kernel/include/tty.h create mode 100644 Kernel/include/version.h create mode 100644 Kernel/include/vt.h create mode 100644 Kernel/inode.c create mode 100644 Kernel/kdata.c create mode 100644 Kernel/kernel.def create mode 100644 Kernel/kernel02.def create mode 100644 Kernel/kernel09.def create mode 100644 Kernel/lowlevel-6502.s create mode 100644 Kernel/lowlevel-6809.s create mode 100644 Kernel/lowlevel-z80.s create mode 100755 Kernel/makeversion create mode 100644 Kernel/mm.c create mode 100644 Kernel/platform-6502test/Makefile create mode 100644 Kernel/platform-6502test/commonmem.s create mode 100644 Kernel/platform-6502test/config.h create mode 100644 Kernel/platform-6502test/crt0.s create mode 100644 Kernel/platform-6502test/device.h create mode 100644 Kernel/platform-6502test/devices.c create mode 100644 Kernel/platform-6502test/devlpr.c create mode 100644 Kernel/platform-6502test/devlpr.h create mode 100644 Kernel/platform-6502test/devrd.c create mode 100644 Kernel/platform-6502test/devrd.h create mode 100644 Kernel/platform-6502test/devtty.c create mode 100644 Kernel/platform-6502test/devtty.h create mode 100644 Kernel/platform-6502test/kernel.def create mode 100644 Kernel/platform-6502test/ld65.cfg create mode 100644 Kernel/platform-6502test/libc.c create mode 100644 Kernel/platform-6502test/main.c create mode 100644 Kernel/platform-6502test/p6502.s create mode 100644 Kernel/platform-6502test/tricks.s create mode 100644 Kernel/platform-6809test/Makefile create mode 100644 Kernel/platform-6809test/commonmem.s create mode 100644 Kernel/platform-6809test/config.h create mode 100644 Kernel/platform-6809test/crt0.s create mode 100644 Kernel/platform-6809test/device.h create mode 100644 Kernel/platform-6809test/devices.c create mode 100644 Kernel/platform-6809test/devlpr.c create mode 100644 Kernel/platform-6809test/devlpr.h create mode 100644 Kernel/platform-6809test/devrd.c create mode 100644 Kernel/platform-6809test/devrd.h create mode 100644 Kernel/platform-6809test/devtty.c create mode 100644 Kernel/platform-6809test/devtty.h create mode 100644 Kernel/platform-6809test/kernel.def create mode 100644 Kernel/platform-6809test/libc.c create mode 100644 Kernel/platform-6809test/main.c create mode 100644 Kernel/platform-6809test/p6809.s create mode 100644 Kernel/platform-6809test/tricks.s create mode 100644 Kernel/platform-micropack/Makefile create mode 100644 Kernel/platform-micropack/README create mode 100644 Kernel/platform-micropack/bootblock.s create mode 100644 Kernel/platform-micropack/commonmem.s create mode 100644 Kernel/platform-micropack/config.h create mode 100644 Kernel/platform-micropack/crt0.s create mode 100644 Kernel/platform-micropack/devfd.c create mode 100644 Kernel/platform-micropack/devfd.h create mode 100644 Kernel/platform-micropack/devices.c create mode 100644 Kernel/platform-micropack/devlpr.c create mode 100644 Kernel/platform-micropack/devlpr.h create mode 100644 Kernel/platform-micropack/devtty.c create mode 100644 Kernel/platform-micropack/devtty.h create mode 100644 Kernel/platform-micropack/kernel.def create mode 100644 Kernel/platform-micropack/main.c create mode 100644 Kernel/platform-micropack/tricks.s create mode 100644 Kernel/platform-micropack/uzi.lnk create mode 100644 Kernel/platform-micropack/z80pack.s create mode 100644 Kernel/platform-nc100/Makefile create mode 100644 Kernel/platform-nc100/README create mode 100644 Kernel/platform-nc100/bootblock.s create mode 100644 Kernel/platform-nc100/commonmem.s create mode 100644 Kernel/platform-nc100/config.h create mode 100644 Kernel/platform-nc100/crt0.s create mode 100644 Kernel/platform-nc100/device.h create mode 100644 Kernel/platform-nc100/devices.c create mode 100644 Kernel/platform-nc100/devlpr.c create mode 100644 Kernel/platform-nc100/devlpr.h create mode 100644 Kernel/platform-nc100/devrd.c create mode 100644 Kernel/platform-nc100/devrd.h create mode 100644 Kernel/platform-nc100/devtty.c create mode 100644 Kernel/platform-nc100/devtty.h create mode 100644 Kernel/platform-nc100/kernel.def create mode 100644 Kernel/platform-nc100/main.c create mode 100644 Kernel/platform-nc100/nc100.s create mode 100644 Kernel/platform-nc100/nc100emu.s create mode 100644 Kernel/platform-nc100/tricks.s create mode 100644 Kernel/platform-nc100/uzi.lnk create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/765.s create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/765.s.old create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/765.s~ create mode 100755 Kernel/platform-pcw8256/BOOTBLOCK/bootcsum create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/bootcsum.c create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/sector2.s create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/sector2.s~ create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/765.ams create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/765.bds create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cas create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cim create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/765.cmd create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/765.hex create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/765.lcas create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.ams create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.bds create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cas create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cim create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.cmd create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.hex create mode 100644 Kernel/platform-pcw8256/BOOTBLOCK/zout/sector2.lcas create mode 100644 Kernel/platform-pcw8256/Makefile create mode 100644 Kernel/platform-pcw8256/README create mode 100644 Kernel/platform-pcw8256/commonmem.s create mode 100644 Kernel/platform-pcw8256/config.h create mode 100644 Kernel/platform-pcw8256/crt0.s create mode 100644 Kernel/platform-pcw8256/devfd.c create mode 100644 Kernel/platform-pcw8256/devfd.h create mode 100644 Kernel/platform-pcw8256/devices.c create mode 100644 Kernel/platform-pcw8256/devlpr.c create mode 100644 Kernel/platform-pcw8256/devlpr.h create mode 100644 Kernel/platform-pcw8256/devtty.c create mode 100644 Kernel/platform-pcw8256/devtty.h create mode 100644 Kernel/platform-pcw8256/fdc765.s create mode 100644 Kernel/platform-pcw8256/kernel.def create mode 100644 Kernel/platform-pcw8256/main.c create mode 100644 Kernel/platform-pcw8256/pcw8256.h create mode 100644 Kernel/platform-pcw8256/pcw8256.s create mode 100644 Kernel/platform-pcw8256/tricks.s create mode 100644 Kernel/platform-trs80/Makefile create mode 100644 Kernel/platform-trs80/README create mode 100644 Kernel/platform-trs80/commonmem.s create mode 100644 Kernel/platform-trs80/config.h create mode 100644 Kernel/platform-trs80/crt0.s create mode 100644 Kernel/platform-trs80/devfd.c create mode 100644 Kernel/platform-trs80/devfd.h create mode 100644 Kernel/platform-trs80/devices.c create mode 100644 Kernel/platform-trs80/devlpr.c create mode 100644 Kernel/platform-trs80/devlpr.h create mode 100644 Kernel/platform-trs80/devtty.c create mode 100644 Kernel/platform-trs80/devtty.h create mode 100644 Kernel/platform-trs80/kernel.def create mode 100644 Kernel/platform-trs80/main.c create mode 100644 Kernel/platform-trs80/tricks.s create mode 100644 Kernel/platform-trs80/trs80.s create mode 100644 Kernel/platform-trs80/trsfd.s create mode 100644 Kernel/platform-trs80/uzi.lnk create mode 100644 Kernel/platform-z80pack-lite/Makefile create mode 100644 Kernel/platform-z80pack-lite/README create mode 100644 Kernel/platform-z80pack-lite/bootblock.s create mode 100644 Kernel/platform-z80pack-lite/commonmem.s create mode 100644 Kernel/platform-z80pack-lite/config.h create mode 100644 Kernel/platform-z80pack-lite/crt0.s create mode 100644 Kernel/platform-z80pack-lite/devfd.c create mode 100644 Kernel/platform-z80pack-lite/devfd.h create mode 100644 Kernel/platform-z80pack-lite/devices.c create mode 100644 Kernel/platform-z80pack-lite/devlpr.c create mode 100644 Kernel/platform-z80pack-lite/devlpr.h create mode 100644 Kernel/platform-z80pack-lite/devtty.c create mode 100644 Kernel/platform-z80pack-lite/devtty.h create mode 100644 Kernel/platform-z80pack-lite/kernel.def create mode 100644 Kernel/platform-z80pack-lite/main.c create mode 100644 Kernel/platform-z80pack-lite/tricks.s create mode 100644 Kernel/platform-z80pack-lite/usermem.s create mode 100644 Kernel/platform-z80pack-lite/uzi.lnk create mode 100644 Kernel/platform-z80pack-lite/z80pack.s create mode 100644 Kernel/platform-z80pack/Makefile create mode 100644 Kernel/platform-z80pack/README create mode 100644 Kernel/platform-z80pack/bootblock.s create mode 100644 Kernel/platform-z80pack/commonmem.s create mode 100644 Kernel/platform-z80pack/config.h create mode 100644 Kernel/platform-z80pack/crt0.s create mode 100644 Kernel/platform-z80pack/devfd.c create mode 100644 Kernel/platform-z80pack/devfd.h create mode 100644 Kernel/platform-z80pack/devices.c create mode 100644 Kernel/platform-z80pack/devlpr.c create mode 100644 Kernel/platform-z80pack/devlpr.h create mode 100644 Kernel/platform-z80pack/devtty.c create mode 100644 Kernel/platform-z80pack/devtty.h create mode 100644 Kernel/platform-z80pack/kernel.def create mode 100644 Kernel/platform-z80pack/main.c create mode 100644 Kernel/platform-z80pack/tricks.s create mode 100644 Kernel/platform-z80pack/uzi.lnk create mode 100644 Kernel/platform-z80pack/z80pack.s create mode 100644 Kernel/process.c create mode 100644 Kernel/select.c create mode 100644 Kernel/simple.c create mode 100644 Kernel/single.c create mode 100644 Kernel/start.c create mode 100644 Kernel/swap.c create mode 100644 Kernel/syscall_fs.c create mode 100644 Kernel/syscall_fs2.c create mode 100644 Kernel/syscall_other.c create mode 100644 Kernel/syscall_proc.c create mode 100644 Kernel/timer.c create mode 100644 Kernel/tools/analysemap.c create mode 100644 Kernel/tools/binman.c create mode 100644 Kernel/tools/filesizes.c create mode 100644 Kernel/tools/make4x6.c create mode 100644 Kernel/tty.c create mode 100644 Kernel/unbanked.c create mode 100644 Kernel/usermem.c create mode 100644 Kernel/usermem_std-6502.s create mode 100644 Kernel/usermem_std-6809.s create mode 100644 Kernel/usermem_std-z80.s create mode 100644 Kernel/vt.c create mode 100644 Library/Makefile create mode 100644 Library/include/alloc.h create mode 100644 Library/include/ar.h create mode 100644 Library/include/assert.h create mode 100644 Library/include/ctype.h create mode 100644 Library/include/curses.h create mode 100644 Library/include/dirent.h create mode 100644 Library/include/errno.h create mode 100644 Library/include/fcntl.h create mode 100644 Library/include/features.h create mode 100644 Library/include/float.h create mode 100644 Library/include/ftw.h create mode 100644 Library/include/fuzix.h create mode 100644 Library/include/getopt.h create mode 100644 Library/include/grp.h create mode 100644 Library/include/limits.h create mode 100644 Library/include/malloc.h create mode 100644 Library/include/math.h create mode 100644 Library/include/memory.h create mode 100644 Library/include/ncurses.h create mode 100644 Library/include/paths.h create mode 100644 Library/include/poll.h create mode 100644 Library/include/pwd.h create mode 100644 Library/include/regexp.h create mode 100644 Library/include/regmagic.h create mode 100644 Library/include/search.h create mode 100644 Library/include/setjmp.h create mode 100644 Library/include/sgtty.h create mode 100644 Library/include/signal.h create mode 100644 Library/include/stdio.h create mode 100644 Library/include/stdlib.h create mode 100644 Library/include/string.h create mode 100644 Library/include/strings.h create mode 100755 Library/include/sys/cdefs.h create mode 100644 Library/include/sys/errno.h create mode 100755 Library/include/sys/exec.h create mode 100644 Library/include/sys/file.h create mode 100644 Library/include/sys/fp.h create mode 100755 Library/include/sys/ioctl.h create mode 100644 Library/include/sys/lock.h create mode 100644 Library/include/sys/mman.h create mode 100644 Library/include/sys/mount.h create mode 100644 Library/include/sys/param.h create mode 100644 Library/include/sys/resource.h create mode 100755 Library/include/sys/seek.h create mode 100644 Library/include/sys/signal.h create mode 100755 Library/include/sys/stat.h create mode 100644 Library/include/sys/statfs.h create mode 100644 Library/include/sys/time.h create mode 100644 Library/include/sys/times.h create mode 100644 Library/include/sys/types.h create mode 100755 Library/include/sys/utsname.h create mode 100755 Library/include/sys/wait.h create mode 100644 Library/include/syscalls.h create mode 100644 Library/include/termcap.h create mode 100644 Library/include/termio.h create mode 100644 Library/include/termios.h create mode 100644 Library/include/time.h create mode 100644 Library/include/types.h create mode 100644 Library/include/unistd.h create mode 100644 Library/include/utime.h create mode 100644 Library/include/utmp.h create mode 100644 Library/include/utsname.h create mode 100644 Library/include/varargs.h create mode 100644 Library/include/wait.h create mode 100644 Library/libs/Makefile create mode 100644 Library/libs/README.regexp create mode 100644 Library/libs/TODO create mode 100644 Library/libs/__getgrent.c create mode 100644 Library/libs/__getpwent.c create mode 100644 Library/libs/abort.c create mode 100644 Library/libs/abs.c create mode 100644 Library/libs/asctime.c create mode 100644 Library/libs/assert.c create mode 100644 Library/libs/atexit.c create mode 100644 Library/libs/atof.c create mode 100644 Library/libs/atoi.c create mode 100644 Library/libs/atol.c create mode 100644 Library/libs/bcmp.c create mode 100644 Library/libs/bcopy.c create mode 100644 Library/libs/bsearch.c create mode 100644 Library/libs/bzero.c create mode 100644 Library/libs/calloc.c create mode 100644 Library/libs/cfmakeraw.c create mode 100644 Library/libs/cfree.c create mode 100644 Library/libs/cfspeed.c create mode 100644 Library/libs/clock.c create mode 100644 Library/libs/closedir.c create mode 100644 Library/libs/config-getent.h create mode 100644 Library/libs/config-grp.h create mode 100644 Library/libs/confstr.c create mode 100644 Library/libs/creat.c create mode 100644 Library/libs/crt0.s create mode 100644 Library/libs/crypt.c create mode 100644 Library/libs/ctime.c create mode 100644 Library/libs/ctype.c create mode 100644 Library/libs/difftime.c create mode 100644 Library/libs/errno.c create mode 100644 Library/libs/error.c create mode 100644 Library/libs/execl.c create mode 100644 Library/libs/execv.c create mode 100644 Library/libs/execvp.c create mode 100644 Library/libs/exit.c create mode 100644 Library/libs/fclose.c create mode 100644 Library/libs/fflush.c create mode 100644 Library/libs/fgetc.c create mode 100644 Library/libs/fgetgrent.c create mode 100644 Library/libs/fgetpos.c create mode 100644 Library/libs/fgetpwent.c create mode 100644 Library/libs/fgets.c create mode 100644 Library/libs/fopen.c create mode 100644 Library/libs/fprintf.c create mode 100644 Library/libs/fputc.c create mode 100644 Library/libs/fputs.c create mode 100644 Library/libs/fread.c create mode 100644 Library/libs/free.c create mode 100644 Library/libs/fscanf.c create mode 100644 Library/libs/fsetpos.c create mode 100644 Library/libs/ftell.c create mode 100644 Library/libs/fuzix/Makefile create mode 100644 Library/libs/fuzix/syscall.s create mode 100644 Library/libs/fwrite.c create mode 100644 Library/libs/getcwd.c create mode 100644 Library/libs/getenv.c create mode 100644 Library/libs/getgrgid.c create mode 100644 Library/libs/getgrnam.c create mode 100644 Library/libs/gethostname.c create mode 100644 Library/libs/getopt.c create mode 100644 Library/libs/getpass.c create mode 100644 Library/libs/getpw.c create mode 100644 Library/libs/getpwnam.c create mode 100644 Library/libs/getpwuid.c create mode 100644 Library/libs/gets.c create mode 100644 Library/libs/gmtime.c create mode 100644 Library/libs/grent.c create mode 100644 Library/libs/index.c create mode 100644 Library/libs/initgroups.c create mode 100644 Library/libs/isatty.c create mode 100644 Library/libs/itoa.c create mode 100644 Library/libs/killpg.c create mode 100644 Library/libs/labs.c create mode 100644 Library/libs/localtim.c create mode 100644 Library/libs/lsearch.c create mode 100644 Library/libs/lseek.c create mode 100644 Library/libs/lstat.c create mode 100644 Library/libs/ltoa.c create mode 100644 Library/libs/ltostr.c create mode 100644 Library/libs/malloc-l.h create mode 100644 Library/libs/malloc.c create mode 100644 Library/libs/memccpy.c create mode 100644 Library/libs/memchr.c create mode 100644 Library/libs/memcmp.c create mode 100644 Library/libs/memcpy.c create mode 100644 Library/libs/memset.c create mode 100644 Library/libs/mkfifo.c create mode 100644 Library/libs/opendir.c create mode 100644 Library/libs/pause.c create mode 100644 Library/libs/perror.c create mode 100644 Library/libs/popen.c create mode 100644 Library/libs/printf.c create mode 100644 Library/libs/printf.h create mode 100644 Library/libs/putenv.c create mode 100644 Library/libs/putgetch.c create mode 100644 Library/libs/putpwent.c create mode 100644 Library/libs/pwent.c create mode 100644 Library/libs/qsort.c create mode 100644 Library/libs/raise.c create mode 100644 Library/libs/rand.c create mode 100644 Library/libs/readdir.c create mode 100644 Library/libs/readlink.c create mode 100644 Library/libs/realloc.c create mode 100644 Library/libs/regerror.c create mode 100644 Library/libs/regexp.c create mode 100644 Library/libs/regexp.h create mode 100644 Library/libs/regmagic.h create mode 100644 Library/libs/regsub.c create mode 100644 Library/libs/remove.c create mode 100644 Library/libs/revoke.c create mode 100644 Library/libs/rewind.c create mode 100644 Library/libs/rindex.c create mode 100644 Library/libs/scanf.c create mode 100644 Library/libs/setbuffer.c create mode 100644 Library/libs/setenv.c create mode 100644 Library/libs/setjmp.c create mode 100644 Library/libs/setvbuf.c create mode 100644 Library/libs/sleep.c create mode 100644 Library/libs/sprintf.c create mode 100644 Library/libs/sscanf.c create mode 100644 Library/libs/stat.c create mode 100644 Library/libs/stdio-l.h create mode 100644 Library/libs/stdio0.c create mode 100644 Library/libs/strcasecmp.c create mode 100644 Library/libs/strcat.c create mode 100644 Library/libs/strchr.c create mode 100644 Library/libs/strcmp.c create mode 100644 Library/libs/strcpy.c create mode 100644 Library/libs/strcspn.c create mode 100644 Library/libs/strdup.c create mode 100644 Library/libs/stricmp.c create mode 100644 Library/libs/strlen.c create mode 100644 Library/libs/strncasecmp.c create mode 100644 Library/libs/strncat.c create mode 100644 Library/libs/strncpy.c create mode 100644 Library/libs/strnicmp.c create mode 100644 Library/libs/strpbrk.c create mode 100644 Library/libs/strrchr.c create mode 100644 Library/libs/strsep.c create mode 100644 Library/libs/strspn.c create mode 100644 Library/libs/strstr.c create mode 100644 Library/libs/strtod.c create mode 100644 Library/libs/strtok.c create mode 100644 Library/libs/strtol.c create mode 100644 Library/libs/sysconf.c create mode 100644 Library/libs/system.c create mode 100644 Library/libs/tcdrain.c create mode 100644 Library/libs/tcflow.c create mode 100644 Library/libs/tcflush.c create mode 100644 Library/libs/tcgetattr.c create mode 100644 Library/libs/tcsetattr.c create mode 100644 Library/libs/time.c create mode 100644 Library/libs/tmpnam.c create mode 100644 Library/libs/ttyname.c create mode 100644 Library/libs/tzset.c create mode 100644 Library/libs/ultoa.c create mode 100644 Library/libs/ungetc.c create mode 100644 Library/libs/utent.c create mode 100644 Library/libs/utsname.c create mode 100644 Library/libs/vfprintf.c create mode 100644 Library/libs/vfscanf.c create mode 100644 Library/libs/vprintf.c create mode 100644 Library/libs/vscanf.c create mode 100644 Library/libs/vsscanf.c create mode 100644 Library/libs/wait.c create mode 100644 Library/libs/xitoa.c create mode 100644 Library/tools/TODO create mode 100644 Library/tools/binman.c create mode 100644 Library/tools/fcc.c create mode 100644 Library/tools/fsize.c create mode 100755 Library/tools/libclean create mode 100644 Library/tools/syscall.c diff --git a/Applications/ASM/init.s b/Applications/ASM/init.s new file mode 100644 index 00000000..1fbd02a9 --- /dev/null +++ b/Applications/ASM/init.s @@ -0,0 +1,38 @@ +; +; A simple testing setup for FUZIX +; + .org 0x100 +start: jp start2 + .db 'F' + .db 'Z' + .db 'X' + .db '1' + .dw 0 +start2: + ld a, '*' + out (1), a + ld hl, 2 + push hl + ld hl, devtty + push hl + ld hl, 1 + push hl + rst 0x30 + ld hl, 13 + push hl + ld hl, banner + push hl + ld hl, 0 + push hl + ld hl, 8 + push hl + rst 0x30 + ld hl, 0 + push hl + ld hl, 37 + push hl + rst 0x30 +banner: + .db 'Hello World' + .db 13,10 +devtty: .db '/dev/tty1',0 \ No newline at end of file diff --git a/Applications/util/Makefile b/Applications/util/Makefile new file mode 100644 index 00000000..ba0126ff --- /dev/null +++ b/Applications/util/Makefile @@ -0,0 +1,92 @@ +CC = sdcc +ASM = sdasz80 +AR = sdar +LINKER = sdcc +#CC_OPT = -mz80 -c --opt-code-size --std-c89 --max-allocs-per-node 2000000 -I../../Library/include +CC_OPT = -mz80 --std-c99 -c --opt-code-size --max-allocs-per-node 20000 -I../../Library/include +#--oldralloc +ASM_OPT = -l -o -s +LINKER_OPT = --code-loc 0 -mz80 --nostdlib --no-std-crt0 + +.SUFFIXES: .c .rel + + +SRCS = basename.c \ + bd.c \ + cal.c \ + cat.c \ + chgrp.c \ + chmod.c \ + chown.c \ + cp.c \ + cut.c \ + date.c \ + dd.c \ + df.c \ + dirname.c \ + du.c \ + echo.c \ + ed.c \ + false.c \ + fsck.c \ + grep.c \ + id.c \ + init.c \ + kill.c \ + ll.c \ + ln.c \ + ls.c \ + mkdir.c \ + mkfs.c \ + mknod.c \ + more.c \ + mount.c \ + mv.c \ + od.c \ + passwd.c \ + patchcpm.c \ + printenv.c \ + prtroot.c \ + ps.c \ + pwd.c \ + rm.c \ + rmdir.c \ + sleep.c \ + ssh.c \ + su.c \ + sync.c \ + termcap.c \ + tget.c \ + touch.c \ + tr.c \ + true.c \ + umount.c \ + uniq.c \ + uud.c \ + uue.c \ + wc.c \ + which.c \ + whoami.c + +OBJS = $(SRCS:.c=.rel) + +LIBS = ../../Library/libs/syslib.lib + +APPS = $(OBJS:.rel=) + +all: $(APPS) + +$(OBJS): $(SRCS) + +.c.rel: + $(CC) $(CC_OPT) $(@:.rel=.c) + +%: %.rel + $(LINKER) $(LINKER_OPT) ../../Library/libs/crt0.rel $< $(LIBS) + +clean: + rm -f $(OBJS) $(APPS) core *~ *.asm *.lst *.sym *.map *.noi *.lk + +rmbak: + rm -f *~ core + diff --git a/Applications/util/basename.c b/Applications/util/basename.c new file mode 100644 index 00000000..7e64872f --- /dev/null +++ b/Applications/util/basename.c @@ -0,0 +1,58 @@ +#include +#include +#include + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +static void remove_suffix(char *name, char *suffix) +{ + char *np, *sp; + + np = name + strlen(name); + sp = suffix + strlen(suffix); + + while (np > name && sp > suffix) + if (*--np != *--sp) + return; + + if (np > name) + *np = '\0'; +} + + +char *basename(char *name) +{ + char *base; + + base = rindex(name, '/'); + return base ? base + 1 : name; +} + + +void strip_trailing_slashes(char *path) +{ + int last; + + last = strlen(path) - 1; + while (last > 0 && path[last] == '/') + path[last--] = '\0'; +} + + +int main(int argc, char *argv[]) +{ + char *line; + + if (argc == 2 || argc == 3) { + strip_trailing_slashes(argv[1]); + line = basename(argv[1]); + if (argc == 3) + remove_suffix(line, argv[2]); + write(STDOUT_FILENO, line, strlen(line)); + write(STDOUT_FILENO, "\n", 1); + } + + return 0; +} diff --git a/Applications/util/bd.c b/Applications/util/bd.c new file mode 100644 index 00000000..cf62389f --- /dev/null +++ b/Applications/util/bd.c @@ -0,0 +1,67 @@ +/************************************************** +UZI (Unix Z80 Implementation) Utilities: bd.c +***************************************************/ +/* + * Block Dump - to examine floppy and hard disks. + * + * Usage: bd dev blkno + */ + +#include +#include +#include +#include +#include +#include + +char buf[512]; + +int main(int argc, char *argv[]) +{ + int i, j, d; + unsigned blkno; + char ch; + + if (argc != 3 || !isdigit(argv[2][0])) { + fprintf(stderr, "usage: bd device blkno\n"); + exit(1); + } + + blkno = atoi(argv[2]); + d = open(argv[1], O_RDONLY); + if (d < 0) { + printf("bd: can't open %s\n", argv[1]); + exit(1); + } + + lseek(d, blkno * 512L, 0); + i = read(d, buf, 512); + close(d); + + if (i != 512) { + printf("bd: error reading block %d\n", blkno); + exit(1); + } + + for (i = 0; i < 512 / 16; ++i) { + printf("%04x ", 16 * i); + for (j = 0; j < 16; ++j) { + printf("%02x ", buf[16 * i + j] & 0xff); + } + printf(" "); + for (j = 0; j < 16; ++j) { + ch = (buf[16 * i + j] & 0x00ff); + if ((ch >= ' ') && (ch < 0x7f)) + putchar(ch); + else + printf("."); + } + printf("\n"); + if (((i + 1) % 16 == 0) && (i < 31)) { + printf("[return for more]"); + getchar(); + printf("\n"); + } + } + exit(0); +} diff --git a/Applications/util/cal.c b/Applications/util/cal.c new file mode 100644 index 00000000..b8ca093f --- /dev/null +++ b/Applications/util/cal.c @@ -0,0 +1,493 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Kim Letkeman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1989, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +static char sccsid[] = "@(#)cal.c 8.4 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include +#include +#include +#include +#include + +int time_zone = 0; +long timezone = 0; + +int errx(int exv, char *str) +{ + fprintf(stderr, "cal: %s\n", str); + exit(exv); +} + +#define THURSDAY 4 /* for reformation */ +#define SATURDAY 6 /* 1 Jan 1 was a Saturday */ + +#define FIRST_MISSING_DAY 639787 /* 3 Sep 1752 */ +#define NUMBER_MISSING_DAYS 11 /* 11 day correction */ + +#define MAXDAYS 42 /* max slots in a month array */ +#define SPACE -1 /* used in day array */ + +static int days_in_month[2][13] = +{ + {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, +}; + +int sep1752[MAXDAYS] = +{ + SPACE, SPACE, 1, 2, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, +}, j_sep1752[MAXDAYS] = +{ + SPACE, SPACE, 245, 246, 258, 259, 260, + 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, 274, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, +}, empty[MAXDAYS] = +{ + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, + SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, +}; + +char day_headings[] = "Su Mo Tu We Th Fr Sa "; +char j_day_headings[] = "Sun Mon Tue Wed Thu Fri Sat "; +char *full_month[12] = { + "January", "February", "March", "April", + "May", "June", "July", "August", + "September", "October", "November", "December" +}; + +/* leap year -- account for gregorian reformation in 1752 */ +#define leap_year(yr) \ + ((yr) <= 1752 ? !((yr) % 4) : \ + (!((yr) % 4) && ((yr) % 100)) || !((yr) % 400)) + +/* number of centuries since 1700, not inclusive */ +#define centuries_since_1700(yr) \ + ((yr) > 1700 ? (yr) / 100 - 17 : 0) + +/* number of centuries since 1700 whose modulo of 400 is 0 */ +#define quad_centuries_since_1700(yr) \ + ((yr) > 1600 ? ((yr) - 1600) / 400 : 0) + +/* number of leap years between year 1 and this year, not inclusive */ +#define leap_years_since_year_1(yr) \ + ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr)) + +int julian; + +void ascii_day(char *, int); +void center(char *, int, int); +void day_array(int, int, int *); +int day_in_week(int, int, int); +int day_in_year(int, int, int); +void j_yearly(int); +void monthly(int, int); +void trim_trailing_spaces(char *); +void usage(void); +void yearly(int); + +int main(int argc, char *argv[]) +{ + struct tm *local_time; + time_t now; + int ch, month, year, yflag; + + julian = yflag = 0; + +#if 1 + while ((ch = getopt(argc, argv, "jy")) != EOF) + switch (ch) { + case 'j': + julian = 1; + break; + case 'y': + yflag = 1; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; +#else + argc--; + argv++; +#endif + + month = 0; + switch (argc) { + case 2: + if ((month = atoi(*argv++)) < 1 || month > 12) + errx(1, "illegal month value: use 1-12"); + /* FALLTHROUGH */ + case 1: + if ((year = atoi(*argv)) < 1 || year > 9999) + errx(1, "illegal year value: use 1-9999"); + break; + + case 0: + now = time(NULL); + local_time = localtime(&now); + year = local_time->tm_year + 1900; + if (!yflag) + month = local_time->tm_mon + 1; + break; + + default: + usage(); + } + + if (month) + monthly(month, year); + else if (julian) + j_yearly(year); + else + yearly(year); + exit(0); +} + +#define DAY_LEN 3 /* 3 spaces per day */ +#define J_DAY_LEN 4 /* 4 spaces per day */ +#define WEEK_LEN 21 /* 7 days * 3 characters */ +#define J_WEEK_LEN 28 /* 7 days * 4 characters */ +#define HEAD_SEP 2 /* spaces between day headings */ +#define J_HEAD_SEP 2 + +void monthly(int month, int year) +{ + int col, row, len, days[MAXDAYS]; + char *p, lineout[30]; + + day_array(month, year, days); + len = sprintf(lineout, "%s %d", full_month[month - 1], year); + printf("%*s%s\n%s\n", + ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "", + lineout, julian ? j_day_headings : day_headings); + for (row = 0; row < 6; row++) { + for (col = 0, p = lineout; col < 7; col++, + p += julian ? J_DAY_LEN : DAY_LEN) + ascii_day(p, days[row * 7 + col]); + *p = '\0'; + trim_trailing_spaces(lineout); + printf("%s\n", lineout); + } +} + +void j_yearly(int year) +{ + char *p; + int col, *dp, i, month, row, which_cal; + int days[12][MAXDAYS]; + char lineout[80]; + + sprintf(lineout, "%d", year); + center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0); + printf("\n\n"); + for (i = 0; i < 12; i++) + day_array(i + 1, year, days[i]); +#if 0 + memset(lineout, ' ', sizeof(lineout) - 1); +#else /* Hi-Tech C */ + memset(lineout, sizeof(lineout) - 1, ' '); +#endif + lineout[sizeof(lineout) - 1] = '\0'; + for (month = 0; month < 12; month += 2) { + center(full_month[month], J_WEEK_LEN, J_HEAD_SEP); + center(full_month[month + 1], J_WEEK_LEN, 0); + printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "", j_day_headings); + for (row = 0; row < 6; row++) { + for (which_cal = 0; which_cal < 2; which_cal++) { + p = lineout + which_cal * (J_WEEK_LEN + 2); + dp = &days[month + which_cal][row * 7]; + for (col = 0; col < 7; col++, p += J_DAY_LEN) + ascii_day(p, *dp++); + } + *p = '\0'; + trim_trailing_spaces(lineout); + printf("%s\n", lineout); + } + } + printf("\n"); +} + +void yearly(int year) +{ + char *p; + int col, *dp, i, month, row, which_cal; + int days[12][MAXDAYS]; + char lineout[80]; + + sprintf(lineout, "%d", year); + center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0); + printf("\n\n"); + for (i = 0; i < 12; i++) + day_array(i + 1, year, days[i]); +#if 0 + memset(lineout, ' ', sizeof(lineout) - 1); +#else /* Hi-Tech C */ + memset(lineout, sizeof(lineout) - 1, ' '); +#endif + lineout[sizeof(lineout) - 1] = '\0'; + for (month = 0; month < 12; month += 3) { + center(full_month[month], WEEK_LEN, HEAD_SEP); + center(full_month[month + 1], WEEK_LEN, HEAD_SEP); + center(full_month[month + 2], WEEK_LEN, 0); + printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP, + "", day_headings, HEAD_SEP, "", day_headings); + for (row = 0; row < 6; row++) { + for (which_cal = 0; which_cal < 3; which_cal++) { + p = lineout + which_cal * (WEEK_LEN + 2); + dp = &days[month + which_cal][row * 7]; + for (col = 0; col < 7; col++, p += DAY_LEN) + ascii_day(p, *dp++); + } + *p = '\0'; + trim_trailing_spaces(lineout); + printf("%s\n", lineout); + } + } + printf("\n"); +} + +/* + * day_array -- + * Fill in an array of 42 integers with a calendar. Assume for a moment + * that you took the (maximum) 6 rows in a calendar and stretched them + * out end to end. You would have 42 numbers or spaces. This routine + * builds that array for any month from Jan. 1 through Dec. 9999. + */ +void day_array(int month, int year, int *days) +{ + int day, dw, dm; + + if (month == 9 && year == 1752) { + memmove(days, + julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int)); + return; + } + memmove(days, empty, MAXDAYS * sizeof(int)); + dm = days_in_month[leap_year(year)][month]; + dw = day_in_week(1, month, year); + day = julian ? day_in_year(1, month, year) : 1; + while (dm--) + days[dw++] = day++; +} + +/* + * day_in_year -- + * return the 1 based day number within the year + */ +int day_in_year(int day, int month, int year) +{ + int i, leap; + + leap = leap_year(year); + for (i = 1; i < month; i++) + day += days_in_month[leap][i]; + return (day); +} + +/* + * day_in_week + * return the 0 based day number for any date from 1 Jan. 1 to + * 31 Dec. 9999. Assumes the Gregorian reformation eliminates + * 3 Sep. 1752 through 13 Sep. 1752. Returns Thursday for all + * missing days. + */ +int day_in_week(int day, int month, int year) +{ + long temp; + + temp = (long) (year - 1) * 365 + leap_years_since_year_1(year - 1) + + day_in_year(day, month, year); + if (temp < FIRST_MISSING_DAY) + return ((temp - 1 + SATURDAY) % 7); + if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS)) + return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7); + return (THURSDAY); +} + +void ascii_day(char *p, int day) +{ + int display, val; + static char *aday[] = + { + "", + " 1", " 2", " 3", " 4", " 5", " 6", " 7", + " 8", " 9", "10", "11", "12", "13", "14", + "15", "16", "17", "18", "19", "20", "21", + "22", "23", "24", "25", "26", "27", "28", + "29", "30", "31", + }; + + if (day == SPACE) { + memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN); + return; + } + if (julian) { + if ((val = day / 100)) { + day %= 100; + *p++ = val + '0'; + display = 1; + } else { + *p++ = ' '; + display = 0; + } + val = day / 10; + if (val || display) + *p++ = val + '0'; + else + *p++ = ' '; + *p++ = day % 10 + '0'; + } else { + *p++ = aday[day][0]; + *p++ = aday[day][1]; + } + *p = ' '; +} + +void trim_trailing_spaces(char *s) +{ + char *p; + + for (p = s; *p; ++p) + continue; + while (p > s && isspace(*--p)) + continue; + if (p > s) + ++p; + *p = '\0'; +} + +void center(char *str, int len, int separate) +{ + + len -= strlen(str); + printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, ""); + if (separate) + printf("%*s", separate, ""); +} + +void usage(void) +{ + fprintf(stderr, "usage: cal [-jy] [[month] year]\n"); + exit(1); +} + +#if 0 +/*------------------------------------------------------------------*/ + +/* + * getopt - parse command-line options + */ + +#define ERR(s, c) if(opterr){\ + fputs(argv[0], stderr);\ + fputs(s, stderr);\ + fputc(c, stderr);\ + fputc('\n', stderr);} + +int opterr = 1; +int optind = 1; +int optopt; +char *optarg; + +int getopt(argc, argv, opts) +int argc; +char **argv; +char *opts; +{ + static int sp = 1; + register c; + register char *cp; + + if (sp == 1) { + if (optind >= argc || + argv[optind][0] != '-' || argv[optind][1] == '\0') + return EOF; + else if (!strcmp(argv[optind], "--")) { + optind++; + return EOF; + } + } + + optopt = c = argv[optind][sp]; + if (c == ':' || (cp=strchr(opts, c)) == NULL) { + ERR (": illegal option -- ", c); + if (argv[optind][++sp] == '\0') { + optind++; + sp = 1; + } + return '?'; + } + if (*++cp == ':') { + if (argv[optind][sp+1] != '\0') { + optarg = &argv[optind++][sp+1]; + } else if (++optind >= argc) { + ERR (": option requires an argument -- ", c); + sp = 1; + return '?'; + } else { + optarg = argv[optind++]; + } + sp = 1; + } else { + if (argv[optind][++sp] == '\0') { + sp = 1; + optind++; + } + optarg = NULL; + } + + return c; +} +#endif diff --git a/Applications/util/cat.c b/Applications/util/cat.c new file mode 100644 index 00000000..d4879b78 --- /dev/null +++ b/Applications/util/cat.c @@ -0,0 +1,102 @@ +/* + * tiny-cat.c - This file is part of the tiny-utils package for Linux & ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +#define STDIN_FILENO 0 /* fileno(stdin) */ +#define STDOUT_FILENO 1 /* fileno(stdout) */ + +#define BUFFER_SIZE 512 + + +/* The name of the file currently being displayed, "-" indicates stdin. */ + +char *filename; + +int open_file(char *new_filename) +{ + int fd; + + filename = new_filename; + + if (*filename == '-' && *(filename + 1) == '\0') + return (STDIN_FILENO); + + /* + * If open() returns an error, the accepted behavior is for cat to + * report the error and move on to the next file in the argument list. + */ + if ((fd = open(filename, O_RDONLY)) < 0) + perror(filename); + + return (fd); +} + + +/* + * Output from the current fd until we reach EOF, and then return. + */ + +int output_file(int fd) +{ + int bytes_read; + char buff[BUFFER_SIZE]; + + while ((bytes_read = read(fd, buff, BUFFER_SIZE)) > 0) + write(STDOUT_FILENO, buff, bytes_read); + + if (bytes_read < 0) + perror(filename); + + return (1); +} + +int main(int argc, char **argv) +{ + /* File descriptor for the input file */ + int curr_input_fd; + int arg_num; + + if (argc == 1) + arg_num = 0; + else + arg_num = 1; + + while (arg_num < argc) { + if (argc == 1) + curr_input_fd = open_file("-"); + else + curr_input_fd = open_file(argv[arg_num]); + + if (curr_input_fd >= 0) { + output_file(curr_input_fd); + close(curr_input_fd); + } + arg_num++; + } + + close(1); + + return (0); +} diff --git a/Applications/util/chgrp.c b/Applications/util/chgrp.c new file mode 100644 index 00000000..fd54d0dc --- /dev/null +++ b/Applications/util/chgrp.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1993 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + */ + +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + char *cp; + int gid; + struct group *grp; + struct stat statbuf; + + cp = argv[1]; + if (!cp) { + fprintf(stderr, "chgrp: too few arguments\n"); + return 1; + } + if (isdigit(*cp)) { + gid = 0; + while (isdigit(*cp)) + gid = gid * 10 + (*cp++ - '0'); + + if (*cp) { + fprintf(stderr, "chgrp: bad gid value\n"); + return 1; + } + } else { + grp = getgrnam(cp); + if (grp == NULL) { + fprintf(stderr, "chgrp: unknown group name\n"); + return 1; + } + gid = grp->gr_gid; + } + + argc--; + argv++; + + while (argc-- > 1) { + argv++; + if ((stat(*argv, &statbuf) < 0) || + (chown(*argv, statbuf.st_uid, gid) < 0)) { + perror(*argv); + return 1; + } + } + + return 0; +} diff --git a/Applications/util/chmod.c b/Applications/util/chmod.c new file mode 100644 index 00000000..3977c9f0 --- /dev/null +++ b/Applications/util/chmod.c @@ -0,0 +1,263 @@ +/* chmod - Change file modes Author: V. Archer */ + +/* Copyright 1991 by Vincent Archer + * You may freely redistribute this software, in source or binary + * form, provided that you do not alter this copyright mention in any + * way. + */ + +#include +#include +#include +#include +#include + +#ifndef S_ISLNK +#define S_ISLNK(mode) 0 +#define lstat stat +#endif + +#define USR_MODES (S_ISUID|S_IRWXU) +#define GRP_MODES (S_ISGID|S_IRWXG) +#define EXE_MODES (S_IXUSR|S_IXGRP|S_IXOTH) +#ifdef S_ISVTX +#define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO|S_ISVTX) +#else +#define ALL_MODES (USR_MODES|GRP_MODES|S_IRWXO) +#endif + +#define PATH_MAX 512 /* FIXME: it's a sysconf shouldn't be + static here */ +/* Common variables */ +char *symbolic; +mode_t new_mode, u_mask; +int rflag, errors; +struct stat st; +char path[PATH_MAX + 1]; + +int main(int argc, char **argv); +mode_t parsemode(char *symbolic, mode_t oldmode); +int do_change(char *name); +void usage(void); + +/* Parse a P1003.2 4.7.7-conformant symbolic mode. */ +mode_t parsemode(char *symbolic, mode_t oldmode) +{ + mode_t who, mask, newmode, tmpmask; + char action; + + newmode = oldmode & ALL_MODES; + while (*symbolic) { + who = 0; + for (; *symbolic; symbolic++) { + if (*symbolic == 'a') { + who |= ALL_MODES; + continue; + } + if (*symbolic == 'u') { + who |= USR_MODES; + continue; + } + if (*symbolic == 'g') { + who |= GRP_MODES; + continue; + } + if (*symbolic == 'o') { + who |= S_IRWXO; + continue; + } + break; + } + if (!*symbolic || *symbolic == ',') + usage(); + while (*symbolic) { + if (*symbolic == ',') + break; + switch (*symbolic) { + default: usage(); + case '+': + case '-': + case '=': action = *symbolic++; break; + } + mask = 0; + for (; *symbolic; symbolic++) { + if (*symbolic == 'u') { + tmpmask = newmode & S_IRWXU; + mask |= tmpmask | (tmpmask << 3) | (tmpmask << 6); + symbolic++; + break; + } + if (*symbolic == 'g') { + tmpmask = newmode & S_IRWXG; + mask |= tmpmask | (tmpmask >> 3) | (tmpmask << 3); + symbolic++; + break; + } + if (*symbolic == 'o') { + tmpmask = newmode & S_IRWXO; + mask |= tmpmask | (tmpmask >> 3) | (tmpmask >> 6); + symbolic++; + break; + } + if (*symbolic == 'r') { + mask |= S_IRUSR | S_IRGRP | S_IROTH; + continue; + } + if (*symbolic == 'w') { + mask |= S_IWUSR | S_IWGRP | S_IWOTH; + continue; + } + if (*symbolic == 'x') { + mask |= EXE_MODES; + continue; + } + if (*symbolic == 's') { + mask |= S_ISUID | S_ISGID; + continue; + } + if (*symbolic == 'X') { + if (S_ISDIR(oldmode) || (oldmode & EXE_MODES)) + mask |= EXE_MODES; + continue; + } +#ifdef S_ISVTX + if (*symbolic == 't') { + mask |= S_ISVTX; + who |= S_ISVTX; + continue; + } +#endif + break; + } + switch (action) { + case '=': + if (who) + newmode &= ~who; + else + newmode = 0; + case '+': + if (who) + newmode |= who & mask; + else + newmode |= mask & (~u_mask); + break; + case '-': + if (who) + newmode &= ~(who & mask); + else + newmode &= ~mask | u_mask; + } + } + if (*symbolic) + symbolic++; + } + return (newmode); +} + + +/* + * Main module. The single option possible (-R) does not warrant a call to + * the getopt() stuff. + */ + +int main(int argc, char *argv[]) +{ + int ex_code = 0; + + argc--; + argv++; + + if (argc && strcmp(*argv, "-R") == 0) { + argc--; + argv++; + rflag = 1; + } else { + rflag = 0; + } + + if (!argc--) usage(); + + if (!strcmp(argv[0], "--")) { /* Allow chmod -- -r, as in Draft11 example */ + if (!argc--) usage(); + argv++; + } + + symbolic = *argv++; + if (!argc) usage(); + + if (*symbolic >= '0' && *symbolic <= '7') { + new_mode = 0; + while (*symbolic >= '0' && *symbolic <= '7') + new_mode = (new_mode << 3) | (*symbolic++ & 07); + if (*symbolic) usage(); + new_mode &= ALL_MODES; + symbolic = (char *) 0; + } else { + u_mask = umask(0); + } + + while (argc--) + if (do_change(*argv++)) + ex_code = 1; + + return (ex_code); +} + + +/* Apply a mode change to a given file system element. */ +int do_change(char *name) +{ + mode_t m; + DIR *dirp; + struct dirent *entp; + char *namp; + + if (lstat(name, &st)) { + perror(name); + return (1); + } + + if (S_ISLNK(st.st_mode) && rflag) + return (0); /* Note: violates POSIX. */ + + if (!symbolic) + m = new_mode; + else + m = parsemode(symbolic, st.st_mode); + + if (chmod(name, m)) { + perror(name); + errors = 1; + } else { + errors = 0; + } + + if (S_ISDIR(st.st_mode) && rflag) { + if (!(dirp = opendir(name))) { + perror(name); + return (1); + } + if (name != path) + strcpy(path, name); + namp = path + strlen(path); + *namp++ = '/'; + while (entp = readdir(dirp)) + if (entp->d_name[0] != '.' || + (entp->d_name[1] && + (entp->d_name[1] != '.' || entp->d_name[2]))) { + strcpy(namp, entp->d_name); + errors |= do_change(path); + } + closedir(dirp); + *--namp = '\0'; + } + return (errors); +} + + +/* Display Posix prototype */ +void usage(void) +{ + fprintf(stderr, "Usage: chmod [-R] mode file...\n"); + exit(1); +} diff --git a/Applications/util/chown.c b/Applications/util/chown.c new file mode 100644 index 00000000..9a8201b4 --- /dev/null +++ b/Applications/util/chown.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1993 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + */ + +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + char *cp; + int uid; + struct passwd *pwd; + struct stat statbuf; + + cp = argv[1]; + if (!cp) { + fprintf(stderr, "chown: too few arguments\n"); + return 1; + } + if (isdigit(*cp)) { + uid = 0; + while (isdigit(*cp)) + uid = uid * 10 + (*cp++ - '0'); + + if (*cp) { + fprintf(stderr, "chown: bad uid value\n"); + return 1; + } + } else { + pwd = getpwnam(cp); + if (pwd == NULL) { + fprintf(stderr, "chown: unknown user name\n"); + return 1; + } + uid = pwd->pw_uid; + } + + argc--; + argv++; + + while (argc-- > 1) { + argv++; + if ((stat(*argv, &statbuf) < 0) || + (chown(*argv, uid, statbuf.st_gid) < 0)) { + perror(*argv); + return 1; + } + } + + return 0; +} diff --git a/Applications/util/cp.c b/Applications/util/cp.c new file mode 100644 index 00000000..f1b8dc4a --- /dev/null +++ b/Applications/util/cp.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 1993 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + * + * Most simple built-in commands are here. + */ + +#include +#include +#include +#include +#include + +typedef unsigned char BOOL; + +#define FALSE 0 +#define TRUE 1 + +#define PATHLEN 512 + +BOOL intflag; + +BOOL isadir(char *); +BOOL copyfile(char *, char *, BOOL); + +char *buildname(char *, char *); + +int main(int argc, char *argv[]) +{ + BOOL dirflag; + char *srcname; + char *destname; + char *lastarg; + + lastarg = argv[argc - 1]; + + dirflag = isadir(lastarg); + + if ((argc > 3) && !dirflag) { + fputs(lastarg, stderr); + fputs(": not a directory\n", stderr); + return 1; + } + while (argc-- > 2) { + srcname = argv[1]; + destname = lastarg; + if (dirflag) + destname = buildname(destname, srcname); + + copyfile(*++argv, destname, FALSE); + } + return 0; +} + +#define BUF_SIZE 4096 + +/* + * Return TRUE if a filename is a directory. + * Nonexistant files return FALSE. + */ +BOOL +isadir(char *name) +{ + struct stat statbuf; + + if (stat(name, &statbuf) < 0) + return FALSE; + + return S_ISDIR(statbuf.st_mode); +} + +/* + * Copy one file to another, while possibly preserving its modes, times, + * and modes. Returns TRUE if successful, or FALSE on a failure with an + * error message output. (Failure is not indicted if the attributes cannot + * be set.) + */ +BOOL copyfile(char *srcname, char *destname, BOOL setmodes) +{ + int rfd, wfd, rcc, wcc; + char *bp, *buf; + struct stat statbuf1; + struct stat statbuf2; + struct utimbuf times; + + if (stat(srcname, &statbuf1) < 0) { + perror(srcname); + return FALSE; + } + if (stat(destname, &statbuf2) < 0) { + statbuf2.st_ino = -1; + statbuf2.st_dev = -1; + } + if ((statbuf1.st_dev == statbuf2.st_dev) && + (statbuf1.st_ino == statbuf2.st_ino)) { + fputs("Copying file \"", stderr); + fputs(srcname, stderr); + fputs("\" to itself\n", stderr); + return FALSE; + } + rfd = open(srcname, 0); + if (rfd < 0) { + perror(srcname); + return FALSE; + } + wfd = creat(destname, statbuf1.st_mode); + if (wfd < 0) { + perror(destname); + close(rfd); + return FALSE; + } + buf = malloc(BUF_SIZE); + while ((rcc = read(rfd, buf, BUF_SIZE)) > 0) { + if (intflag) { + close(rfd); + close(wfd); + return FALSE; + } + bp = buf; + while (rcc > 0) { + wcc = write(wfd, bp, rcc); + if (wcc < 0) { + perror(destname); + goto error_exit; + } + bp += wcc; + rcc -= wcc; + } + } + + if (rcc < 0) { + perror(srcname); + goto error_exit; + } + close(rfd); + if (close(wfd) < 0) { + perror(destname); + return FALSE; + } + if (setmodes) { + chmod(destname, statbuf1.st_mode); + + chown(destname, statbuf1.st_uid, statbuf1.st_gid); + + times.actime = statbuf1.st_atime; + times.modtime = statbuf1.st_mtime; + + utime(destname, ×); + } + return TRUE; + + + error_exit: + close(rfd); + close(wfd); + + return FALSE; +} + +/* + * Build a path name from the specified directory name and file name. + * If the directory name is NULL, then the original filename is returned. + * The built path is in a static area, and is overwritten for each call. + */ +char *buildname(char *dirname, char *filename) +{ + char *cp; + static char buf[PATHLEN]; + + if ((dirname == NULL) || (*dirname == '\0')) + return filename; + + cp = strrchr(filename, '/'); + if (cp) + filename = cp + 1; + + strcpy(buf, dirname); + strcat(buf, "/"); + strcat(buf, filename); + + return buf; +} diff --git a/Applications/util/cut.c b/Applications/util/cut.c new file mode 100644 index 00000000..b51b878e --- /dev/null +++ b/Applications/util/cut.c @@ -0,0 +1,339 @@ +/* cut - extract columns from a file or stdin. Author: Michael J. Holme + * + * Copyright 1989, Michael John Holme, All rights reserved. + * This code may be freely distributed, provided that this notice + * remains intact. + * + * V1.1: 6th September 1989 + * + * Bugs, criticisms, etc, + * c/o Mark Powell + * JANET sq79@uk.ac.liv + * ARPA sq79%liv.ac.uk@nsfnet-relay.ac.uk + * UUCP ...!mcvax!ukc!liv.ac.uk!sq79 + *------------------------------------------------------------------------- + * Changed for POSIX1003.2/Draft10 conformance + * Thomas Brupbacher (tobr@mw.lpc.ethz.ch), September 1990. + * Changes: + * - separation of error messages ( stderr) and output (stdout). + * - support for -b and -n (no effect, -b acts as -c) + * - support for -s + *------------------------------------------------------------------------- + */ + +#include +#include +#include +#include + +#define MAX_FIELD 80 /* Pointers to the beginning of each field + * are stored in columns[], if a line holds + * more than MAX_FIELD columns the array + * boundary is exceed. But unlikely at 80 */ + +#define MAX_ARGS 32 /* Maximum number of fields following -f or + * -c switches */ +int args[MAX_ARGS * 2]; +int num_args; + +/* Lots of new defines, should easen maintainance... */ +#define DUMP_STDIN 0 /* define for mode: no options */ +#define OPTIONF 1 /* define for mode: option -f */ +#define OPTIONC 2 /* define for mode: option -c */ +#define OPTIONB 3 /* define for mode: option -b */ +#define NOTSET 0 /* option not selected */ +#define SET 1 /* option selected */ + +/* Defines for the warnings */ +#define DELIMITER_NOT_APPLICABLE 0 +#define OVERRIDING_PREVIOUS_MODE 1 +#define OPTION_NOT_APPLICABLE 2 +#define UNKNOWN_OPTION 3 +#define FILE_NOT_READABLE 4 + +/* Defines for the fatal errors */ +#define SYNTAX_ERROR 101 +#define POSITION_ERROR 102 +#define USAGE 103 +#define LINE_TO_LONG_ERROR 104 +#define RANGE_ERROR 105 +#define MAX_FIELDS_EXCEEDED_ERROR 106 +#define MAX_ARGS_EXCEEDED_ERROR 107 + + +int mode; /* 0 = dump stdin to stdout, 1=-f, 2=-c */ +int flag_i; /* SET = -i set on command line */ +int flag_s; /* SET = -s set on command line */ +char delim = '\t'; /* default delimiting character */ +FILE *fd; +char *name; +char line[BUFSIZ]; +int exit_status; + + +void warn(int warn_number, char *option) +{ + static char *warn_msg[] = + { + "%s: Option -d allowed only with -f\n", + "%s: -%s overrides earlier option\n", + "%s: -%s not allowed in current mode\n", + "%s: Cannot open %s\n" + }; + + fprintf(stderr, warn_msg[warn_number], name, option); + exit_status = warn_number + 1; + +} + +void cuterror(int err) +{ + static char *err_mes[] = + { + "%s: syntax error\n", + "%s: position must be >0\n", + "%s: usage: cut [-f args [-i] [-d x]]|[-c args] [filename [...]]\n", + "%s: line longer than BUFSIZ\n", + "%s: range must not decrease from left to right\n", + "%s: MAX_FIELD exceeded\n", + "%s: MAX_ARGS exceeded\n" + }; + + fprintf(stderr, err_mes[err - 101], name); + exit(err); +} + + +void get_args(void) +{ + int i = 0; + int arg_ptr = 0; + int flag; + + num_args = 0; + do { + if (num_args == MAX_ARGS) + cuterror(MAX_ARGS_EXCEEDED_ERROR); + if (!isdigit(line[i]) && line[i] != '-') + cuterror(SYNTAX_ERROR); + + args[arg_ptr] = 1; + args[arg_ptr + 1] = BUFSIZ; + flag = 1; + + while (line[i] != ',' && line[i] != 0) { + if (isdigit(line[i])) { + args[arg_ptr] = 0; + while (isdigit(line[i])) + args[arg_ptr] = 10 * args[arg_ptr] + line[i++] - '0'; + if (!args[arg_ptr]) + cuterror(POSITION_ERROR); + arg_ptr++; + } + if (line[i] == '-') { + arg_ptr |= 1; + i++; + flag = 0; + } + } + if (flag && arg_ptr & 1) + args[arg_ptr] = args[arg_ptr - 1]; + if (args[num_args * 2] > args[num_args * 2 + 1]) + cuterror(RANGE_ERROR); + num_args++; + arg_ptr = num_args * 2; + } + while (line[i++]); +} + + +void cut(void) +{ + int i, j, length, maxcol; + char *columns[MAX_FIELD]; + + while (fgets(line, BUFSIZ, fd)) { + + length = strlen(line) - 1; + *(line + length) = 0; + + switch (mode) { + case DUMP_STDIN: + printf("%s", line); + break; + + case OPTIONF: + maxcol = 0; + columns[maxcol++] = line; + for (i = 0; i < length; i++) { + if (*(line + i) == delim) { + *(line + i) = 0; + if (maxcol == MAX_FIELD) + cuterror(MAX_FIELDS_EXCEEDED_ERROR); + columns[maxcol] = line + i + 1; + while (*(line + i + 1) == delim && flag_i) { + columns[maxcol]++; + i++; + } + maxcol++; + } + } + if (maxcol == 1) { + if (flag_s != SET) + printf("%s", line); + } else { + for (i = 0; i < num_args; i++) { + for (j = args[i * 2]; j <= args[i * 2 + 1]; j++) + if (j <= maxcol) { + printf("%s", columns[j - 1]); + if (i != num_args - 1 || j != args[i * 2 + 1]) + putchar(delim); + } + } + } + break; + + case OPTIONC: + for (i = 0; i < num_args; i++) { + for (j = args[i * 2]; j <= (args[i * 2 + 1] > length ? length : + args[i * 2 + 1]); j++) + putchar(*(line + j - 1)); + } + } + + if (maxcol == 1 && flag_s == SET) { + ; + } else { + putchar('\n'); + } + } +} + + +int main(int argc, char *argv[]) +{ + int i = 1; + int numberFilenames = 0; + name = argv[0]; + + if (argc == 1) + cuterror(USAGE); + + while (i < argc) { + if (argv[i][0] == '-') { + switch (argv[i++][1]) { + case 'd': + if (mode == OPTIONC || mode == OPTIONB) + warn(DELIMITER_NOT_APPLICABLE, "d"); + delim = argv[i++][0]; + break; + + case 'f': + sprintf(line, "%s", argv[i++]); + if (mode == OPTIONC || mode == OPTIONB) + warn(OVERRIDING_PREVIOUS_MODE, "f"); + mode = OPTIONF; + break; + + case 'b': + sprintf(line, "%s", argv[i++]); + if (mode == OPTIONF || mode == OPTIONC) + warn(OVERRIDING_PREVIOUS_MODE, "b"); + mode = OPTIONB; + break; + + case 'c': + sprintf(line, "%s", argv[i++]); + if (mode == OPTIONF || mode == OPTIONB) + warn(OVERRIDING_PREVIOUS_MODE, "c"); + mode = OPTIONC; + break; + + case 'i': + flag_i = SET; + break; + + case 's': + flag_s = SET; + break; + + case '\0': /* - means: read from stdin */ + numberFilenames++; + break; + + case 'n': /* needed for Posix, but no effect here */ + if (mode != OPTIONB) + warn(OPTION_NOT_APPLICABLE, "n"); + break; + + default: + warn(UNKNOWN_OPTION, &(argv[i - 1][1])); + } + } else { + i++; + numberFilenames++; + } + } + + /* Here follow the checks, if the selected options are reasonable. */ + + if (mode == OPTIONB) /* since in Minix char == byte */ + mode = OPTIONC; + + /* Flag -s is only allowed with -f, otherwise warn and reset flag_s */ + if (flag_s == SET && (mode == OPTIONB || mode == OPTIONC)) { + warn(OPTION_NOT_APPLICABLE, "s"); + flag_s = NOTSET; + } + + /* Flag -i is only allowed with -f, otherwise warn and reset flag_i */ + if (flag_i == SET && mode == OPTIONF) { + warn(OPTION_NOT_APPLICABLE, "s"); + flag_i = NOTSET; + } + + get_args(); + + if (numberFilenames != 0) { + i = 1; + while (i < argc) { + if (argv[i][0] == '-') { + switch (argv[i][1]) { + case 'f': + case 'c': + case 'b': + case 'd': + i += 2; + break; + + case 'n': + case 'i': + case 's': + i++; + break; + + case '\0': + fd = stdin; + i++; + cut(); + break; + + default: + i++; + } + } else { + if ((fd = fopen(argv[i++], "r")) == NULL) { + warn(FILE_NOT_READABLE, argv[i - 1]); + } else { + cut(); + fclose(fd); + } + } + } + } else { + fd = stdin; + cut(); + } + + return (exit_status); +} diff --git a/Applications/util/date.c b/Applications/util/date.c new file mode 100644 index 00000000..2157b396 --- /dev/null +++ b/Applications/util/date.c @@ -0,0 +1,12 @@ +#include +#include + +int main(int argc, char *argv[]) +{ + time_t now; + + now = time(NULL); + fputs(ctime(&now), stdout); + + return 0; +} diff --git a/Applications/util/dd.c b/Applications/util/dd.c new file mode 100644 index 00000000..e29bd394 --- /dev/null +++ b/Applications/util/dd.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 1993 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + * + * The "dd" built-in command. + */ + +#include +#include +#include +#include +#include +#include + + +typedef unsigned char BOOL; + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +#define PAR_NONE 0 +#define PAR_IF 1 +#define PAR_OF 2 +#define PAR_BS 3 +#define PAR_COUNT 4 +#define PAR_SEEK 5 +#define PAR_SKIP 6 + + +typedef struct { + char *name; + int value; +} PARAM; + + +static PARAM params[] = +{ + {"if", PAR_IF}, + {"of", PAR_OF}, + {"bs", PAR_BS}, + {"count", PAR_COUNT}, + {"seek", PAR_SEEK}, + {"skip", PAR_SKIP}, + {NULL, PAR_NONE} +}; + + +static long getnum(char *); + +BOOL intflag; + +static char localbuf[8192]; + +void main(int argc, char *argv[]) +{ + char *str; + char *cp; + PARAM *par; + char *infile; + char *outfile; + int infd; + int outfd; + int incc; + int outcc; + int blocksize; + long count; + long seekval; + long skipval; + long intotal; + long outtotal; + char *buf; + + infile = NULL; + outfile = NULL; + seekval = 0; + skipval = 0; + blocksize = 512; + count = 0x7fffffff; + + while (--argc > 0) { + str = *++argv; + cp = strchr(str, '='); + if (cp == NULL) { + fprintf(stderr, "Bad dd argument\n"); + return; + } + *cp++ = '\0'; + + for (par = params; par->name; par++) { + if (strcmp(str, par->name) == 0) + break; + } + + switch (par->value) { + case PAR_IF: + if (infile) { + fprintf(stderr, "Multiple input files illegal\n"); + return; + } + infile = cp; + break; + + case PAR_OF: + if (outfile) { + fprintf(stderr, "Multiple output files illegal\n"); + return; + } + outfile = cp; + break; + + case PAR_BS: + blocksize = getnum(cp); + if (blocksize <= 0) { + fprintf(stderr, "Bad block size value\n"); + return; + } + break; + + case PAR_COUNT: + count = getnum(cp); + if (count < 0) { + fprintf(stderr, "Bad count value\n"); + return; + } + break; + + case PAR_SEEK: + seekval = getnum(cp); + if (seekval < 0) { + fprintf(stderr, "Bad seek value\n"); + return; + } + break; + + case PAR_SKIP: + skipval = getnum(cp); + if (skipval < 0) { + fprintf(stderr, "Bad skip value\n"); + return; + } + break; + + default: + fprintf(stderr, "Unknown dd parameter\n"); + return; + } + } + + if (infile == NULL) { + fprintf(stderr, "No input file specified\n"); + return; + } + if (outfile == NULL) { + fprintf(stderr, "No output file specified\n"); + return; + } + buf = localbuf; + if (blocksize > sizeof(localbuf)) { + buf = malloc(blocksize); + if (buf == NULL) { + fprintf(stderr, "Cannot allocate buffer\n"); + return; + } + } + intotal = 0; + outtotal = 0; + + infd = open(infile, 0); + if (infd < 0) { + perror(infile); + if (buf != localbuf) + free(buf); + return; + } + outfd = creat(outfile, 0666); + if (outfd < 0) { + perror(outfile); + close(infd); + if (buf != localbuf) + free(buf); + return; + } + if (skipval) { + if (lseek(infd, skipval * blocksize, 0) < 0) { + while (skipval-- > 0) { + incc = read(infd, buf, blocksize); + if (incc < 0) { + perror(infile); + goto cleanup; + } + if (incc == 0) { + fprintf(stderr, "End of file while skipping\n"); + goto cleanup; + } + } + } + } + if (seekval) { + if (lseek(outfd, seekval * blocksize, 0) < 0) { + perror(outfile); + goto cleanup; + } + } + while ((incc = read(infd, buf, blocksize)) > 0) { + intotal += incc; + cp = buf; + + if (intflag) { + fprintf(stderr, "Interrupted\n"); + goto cleanup; + } + while (incc > 0) { + outcc = write(outfd, cp, incc); + if (outcc < 0) { + perror(outfile); + goto cleanup; + } + outtotal += outcc; + cp += outcc; + incc -= outcc; + } + } + + if (incc < 0) + perror(infile); + + cleanup: + close(infd); + + if (close(outfd) < 0) + perror(outfile); + + if (buf != localbuf) + free(buf); + + printf("%d+%d records in\n", intotal / blocksize, + (intotal % blocksize) != 0); + + printf("%d+%d records out\n", outtotal / blocksize, + (outtotal % blocksize) != 0); +} + + +/* + * Read a number with a possible multiplier. + * Returns -1 if the number format is illegal. + */ +static long getnum(char *cp) +{ + long value; + + if (!isdigit(*cp)) + return -1; + + value = 0; + while (isdigit(*cp)) + value = value * 10 + *cp++ - '0'; + + switch (*cp++) { + case 'k': + value *= 1024; + break; + + case 'b': + value *= 512; + break; + + case 'w': + value *= 2; + break; + + case '\0': + return value; + + default: + return -1; + } + + if (*cp) + return -1; + + return value; +} + + +/* END CODE */ diff --git a/Applications/util/df.c b/Applications/util/df.c new file mode 100644 index 00000000..f1c42b0a --- /dev/null +++ b/Applications/util/df.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include + +char *devname(dev_t); +char *mntpoint(const char *); + +int main(int argc, char *argv[]) +{ + char *p; + int i, j, Total, Used, Free, Percent, iflag = 0, kflag = 0, fflag = 0; + struct _uzifilesys fsys; + + for (i = 1; i < argc; ++i) { + p = argv[i]; + if (p[0] == '-') { + for (++p; *p; ++p) { + switch (*p) { + case 'i': iflag = 1; break; + case 'k': kflag = 1; break; + case 'f': fflag = 1; break; + default: + printf("usage: %s [-ikf]\n", argv[0]); + return 1; + } + } + } else { + break; + } + } + + printf("%-16s %6s %6s %6s %6s %s\n", + "Filesystem", + iflag ? "Inodes" : kflag ? "KBytes" : "Blocks", + iflag ? "IUsed" : "Used", + iflag ? "IFree" : "Free", + iflag ? (fflag ? "%IFree" : "%IUsed") : (fflag ? "%Free" : "%Used"), + "Mounted on"); + + if (i < argc) { + for (; i < argc; ++i) { + p = argv[i]; + } + } else { + for (j = 0; j < 8; ++j) { + if ((_getfsys(j, &fsys) == 0) && fsys.s_mounted) { + Total = iflag ? 8 * (fsys.s_isize - 2) : fsys.s_fsize; + Used = iflag ? Total - fsys.s_tinode : + Total - fsys.s_isize - fsys.s_tfree; + Free = iflag ? fsys.s_tinode : fsys.s_tfree; + + if (!iflag && kflag) { + Total /= 2; + Used /= 2; + Free /= 2; + } + if (fflag) { + if ((Percent = Total / 100) != 0) Percent = Free / Percent; + } else { + if ((Percent = Total / 100) != 0) Percent = Used / Percent; + } + p = devname(j); + printf("%-16s %6u %6u %6u %5u%% %s\n", + p, Total, Used, Free, Percent, + fsys.s_mntpt ? mntpoint(p) : "/"); + } + } + } + + return 0; +} + +/* Search /dev until an entry with the specified device number is found */ + +#define DEV_PATH "/dev" + +char *devname(dev_t devno) +{ + DIR *dp; + struct dirent *entry; + struct stat fstat; + static char namebuf[sizeof(DEV_PATH) + MAXNAMLEN + 2]; + + if ((dp = opendir(DEV_PATH)) != (DIR *) NULL) { + while ((entry = readdir(dp)) != (struct dirent *) NULL) { + sprintf(namebuf, "%s/%s", DEV_PATH, entry->d_name); + if (stat(namebuf, &fstat) != 0) + continue; + if (!S_ISBLK(fstat.st_mode)) + continue; + if (fstat.st_rdev != devno) + continue; + return namebuf; + } + } + + sprintf(namebuf, "%d", devno); + return namebuf; +} + +/* Find the mount point in /etc/mtab for the specified device */ + +char *mntpoint(const char *devname) +{ + FILE *f; + static char tmp[256]; + static char dev[20], mntpt[20], fstype[20], rwflag[20]; + + f = fopen("/etc/mtab", "r"); + if (f) { + while (fgets(tmp, 256, f)) { + sscanf(tmp, "%s %s %s %s\n", dev, mntpt, fstype, rwflag); + if (strcmp(dev, devname) == 0) { + fclose(f); + return mntpt; + } + } + fclose(f); + } + + return "???"; +} diff --git a/Applications/util/dirent.h b/Applications/util/dirent.h new file mode 100644 index 00000000..2e4add5f --- /dev/null +++ b/Applications/util/dirent.h @@ -0,0 +1,24 @@ +#ifndef __DIRENT_H +#define __DIRENT_H + +#include "unix.h" + +#ifndef MAXNAMLEN +#define MAXNAMLEN 13 +#endif + +/* Directory stream type */ + +typedef struct { + int dd_fd; /* file descriptor */ + int dd_loc; /* offset in buffer */ + int dd_size; /* # of valid entries in buffer */ + struct direct dd_buf; /* directory entry buffer */ +} DIR; /* stream data from opendir() */ + +extern DIR *opendir(char *); +extern int closedir(DIR *); +extern struct direct *readdir(DIR *); + +#endif /* dirent.h */ + diff --git a/Applications/util/dirname.c b/Applications/util/dirname.c new file mode 100644 index 00000000..6fc75c48 --- /dev/null +++ b/Applications/util/dirname.c @@ -0,0 +1,37 @@ +#include +#include +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +void strip_trailing_slashes(char *path) +{ + int last; + + last = strlen(path) - 1; + while (last > 0 && path[last] == '/') + path[last--] = '\0'; +} + + +int main(int argc, char *argv[]) +{ + char *line; + + if (argc == 2) { + strip_trailing_slashes(argv[1]); + line = rindex(argv[1], '/'); + if (line == NULL) { + line = "."; + } else { + while (line > argv[1] && *line == '/') + --line; + line[1] = 0; + line = argv[1]; + } + + write(STDOUT_FILENO, line, strlen(line)); + write(STDOUT_FILENO, "\n", 1); + } + return 0; +} diff --git a/Applications/util/du.c b/Applications/util/du.c new file mode 100644 index 00000000..a7c10d6b --- /dev/null +++ b/Applications/util/du.c @@ -0,0 +1,228 @@ +/* du - report on disk usage Author: Alistair G. Crooks */ + +/* + * du.c 1.1 27/5/87 agc Joypace Ltd. + * 1.2 24 Mar 89 nick@nswitgould.oz + * 1.3 31 Mar 89 nick@nswitgould.oz + * 1.4 22 Feb 90 meulenbr@cst.prl.philips.nl + * 1.5 09 Jul 91 hp@vmars.tuwien.ac.at + * 1.6 01 Oct 92 kjb@cs.vu.nl + * 1.7 04 Jan 93 bde + * 1.8 19 Sep 94 kjb + * 1.9 28 Oct 99 kjb + * + * Copyright 1987, Joypace Ltd., London UK. All rights reserved. + * This code may be freely distributed, provided that this notice + * remains attached. + * + * du - a public domain interpretation of du(1). + * + * 1.2: Fixed bug involving 14 character long filenames + * 1.3: Add [-l levels] option to restrict printing. + * 1.4: Added processing of multiple arguments + * 1.5: Fixed processing of multiple arguments. General cleanup. + * 1.6: Use readdir + * 1.7: Merged 1.5 and 1.6. + * Print totals even for non-dirs at top level. + * Count blocks for each dir before printing total for the dir. + * Count blocks for all non-special files. + * Don't clutter link buffer with directories. + * 1.8: Remember all links. + * 1.9: Added -x flag to not cross device boundaries. Type fixes. + * + * Ported to UZI180 10 Jun 2001 (Hector Peraza) + */ + + +#include +#include +#include +#include +#include +#include + +#define LINELEN 256 +#define NR_ALREADY 512 +#define BLOCK_SIZE 512 + +typedef struct already { + struct already *al_next; + int al_dev; + ino_t al_inum; + nlink_t al_nlink; +} ALREADY; + +int main(int argc, char **argv); +int makedname(char *d, char *f, char *out, int outlen); +int done(dev_t dev, ino_t inum, nlink_t nlink); +long dodir(char *d, int thislev, dev_t dev); + +char *prog; /* program name */ +char *optstr = "asxdkl:"; /* options */ +int silent = 0; /* silent mode */ +int all = 0; /* all directory entries mode */ +int crosschk = 0; /* do not cross device boundaries mode */ +int kbytes = 0; /* report size in kilobytes, not blocks */ +char *startdir = "."; /* starting from here */ +int levels = 20000; /* # of directory levels to print */ +ALREADY *already[NR_ALREADY]; +int alc; + +/* + * makedname - make the pathname from the directory name, and the + * directory entry, placing it in out. If this would overflow, + * return 0, otherwise 1. + */ +int makedname(char *d, char *f, char *out, int outlen) +{ + char *cp; + int length; + + length = strlen(f); + if (strlen(d) + length + 2 > outlen) return (0); + for (cp = out; *d; *cp++ = *d++) ; + if (*(cp - 1) != '/') *cp++ = '/'; + while (length--) *cp++ = *f++; + *cp = '\0'; + + return 1; +} + +/* + * done - have we encountered (dev, inum) before? Returns 1 for yes, + * 0 for no, and remembers (dev, inum, nlink). + */ +int done(dev_t dev, ino_t inum, nlink_t nlink) +{ + register ALREADY **pap, *ap; + + pap = &already[(unsigned) inum % NR_ALREADY]; + while ((ap = *pap) != NULL) { + if (ap->al_inum == inum && ap->al_dev == dev) { + if (--ap->al_nlink == 0) { + *pap = ap->al_next; + free(ap); + } + return 1; + } + pap = &ap->al_next; + } + if ((ap = malloc(sizeof(*ap))) == NULL) { + fprintf(stderr, "du: Out of memory\n"); + exit(1); + } + ap->al_next = NULL; + ap->al_inum = inum; + ap->al_dev = dev; + ap->al_nlink = nlink - 1; + *pap = ap; + + return 0; +} + +/* + * dodir - process the directory d. Return the long size (in blocks) + * of d and its descendants. + */ +long dodir(char *d, int thislev, dev_t dev) +{ + int maybe_print; + struct stat s; + long total; + DIR *dp; + struct dirent *entry; + char dent[LINELEN]; + + if (lstat(d, &s) < 0) { + fprintf(stderr, "%s: %s: %s\n", prog, d, strerror(errno)); + return 0L; + } + + if (s.st_dev != dev && dev != 0 && crosschk) + return 0L; + + total = s.st_size; + + if (kbytes) + total = (total + 1023L) / 1024L; + else + total = (total + (long) (BLOCK_SIZE - 1L)) / (long) BLOCK_SIZE; + + switch (s.st_mode & S_IFMT) { + case S_IFDIR: + /* + * Directories should not be linked except to "." and "..", so this + * directory should not already have been done. + */ + maybe_print = !silent; + if ((dp = opendir(d)) == NULL) break; + while ((entry = readdir(dp)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || + strcmp(entry->d_name, "..") == 0) + continue; + if (!makedname(d, entry->d_name, dent, sizeof(dent))) + continue; + total += dodir(dent, thislev - 1, s.st_dev); + } + closedir(dp); + break; + + case S_IFBLK: + case S_IFCHR: + /* st_size for special files is not related to blocks used. */ + total = 0L; + /* Fall through. */ + default: + if (s.st_nlink > 1 && done(s.st_dev, s.st_ino, s.st_nlink)) + return 0L; + maybe_print = all; + break; + } + if (thislev >= levels || (maybe_print && thislev >= 0)) + printf("%ld\t%s\n", total, d); + + return (total); +} + +int main(int argc, char *argv[]) +{ + int c; + + prog = argv[0]; + while ((c = getopt(argc, argv, optstr)) != EOF) + switch (c) { + case 'a': + all = 1; + break; + + case 's': + silent = 1; + break; + + case 'x': + case 'd': + crosschk = 1; + break; + + case 'l': + levels = atoi(optarg); + break; + + case 'k': + kbytes = 1; + break; + + default: + fprintf(stderr, "Usage: %s [-asxk] [-l levels] [startdir]\n", prog); + exit(1); + } + + do { + if (optind < argc) startdir = argv[optind++]; + alc = 0; + dodir(startdir, levels, 0); + } while (optind < argc); + + return (0); +} + diff --git a/Applications/util/dumb.c b/Applications/util/dumb.c new file mode 100644 index 00000000..050384a4 --- /dev/null +++ b/Applications/util/dumb.c @@ -0,0 +1,4 @@ +long long foo(long long a, long long b) +{ + return a%b; +} diff --git a/Applications/util/echo.c b/Applications/util/echo.c new file mode 100644 index 00000000..a9b25f9b --- /dev/null +++ b/Applications/util/echo.c @@ -0,0 +1,53 @@ +/* echo command */ + +#include +#include + +int main(int argc, const char *argv[]) +{ + const char *p; + char c; + int i, nflag, eflag; + + nflag = eflag = 0; + p = *(++argv); + + while (p && *p == '-') { + c = *(++p); + if (c == 'n') + nflag = 1; + else if (c == 'e') + eflag = 1; + else + break; + if (*(++p)) break; + p = *(++argv); + } + + while ((p = *argv++) != NULL) { + while ((c = *p++) != '\0') { + if (c == '\\' && eflag) { + switch (*p++) { + case '0': c = 0; + for (i = 0; i < 3 && *p >= '0' && *p <= '7'; ++i) + c = (c << 3) + *p++ - '0'; + break; + case 'b': c = '\b'; break; + case 'c': return 0; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + case '\\': break; + default: --p; break; + } + } + putchar(c); + } + if (*argv) putchar(' '); + } + if (!nflag) putchar('\n'); + + return 0; +} diff --git a/Applications/util/ed.c b/Applications/util/ed.c new file mode 100644 index 00000000..bb44310a --- /dev/null +++ b/Applications/util/ed.c @@ -0,0 +1,1170 @@ +/* + * Copyright (c) 1993 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + * + * The "ed" built-in command (much simplified) + */ + +#include +#include +#include +#include +#include + +typedef unsigned char BOOL; + +#define FALSE ((BOOL) 0) +#define TRUE ((BOOL) 1) +#define USERSIZE 1024 /* max line length typed in by user */ +#define INITBUFSIZE 1024 /* initial buffer size */ +#define STDIN 0 +#define STDOUT 1 + +/* +#define isblank(ch) (((ch) == ' ') || ((ch) == '\t')) +#define isdecimal(ch) (((ch) >= '0') && ((ch) <= '9')) +*/ +#define isblank(ch) isspace(ch) + +typedef int NUM; +typedef int LEN; + +typedef struct LINE LINE; +struct LINE { + LINE *next; + LINE *prev; + LEN len; + char data[1]; +}; + + +static LINE lines; +static LINE *curline; +static NUM curnum; +static NUM lastnum; +static NUM marks[26]; +static BOOL dirty; +static char *filename; +static char searchstring[USERSIZE]; + +static char *bufbase; +static char *bufp; +static LEN bufused; +static LEN bufsize; + + +static void docommands(void); +static void subcommand(char *, NUM, NUM); +static BOOL getnum(char **, BOOL *, NUM *); +static BOOL setcurnum(NUM); +static BOOL initedit(void); +static void termedit(void); +static void addlines(NUM); +static BOOL insertline(NUM, char *, LEN); +static BOOL deletelines(NUM, NUM); +static BOOL printlines(NUM,NUM, BOOL); +static BOOL writelines(char *, NUM, NUM); +static BOOL readlines(char *, NUM); +static NUM searchlines(char *, NUM, NUM); +static LEN findstring(LINE *, char *, LEN, LEN); +static LINE *findline(NUM); + +BOOL intflag; + +void main(int argc, char *argv[]) +{ + if (!initedit()) + return; + + if (argc > 1) { + filename = strdup(argv[1]); + if (filename == NULL) { + fprintf(stderr, "No memory\n"); + termedit(); + return; + } + if (!readlines(filename, 1)) { + termedit(); + return; + } + if (lastnum) + setcurnum(1); + + dirty = FALSE; + } + docommands(); + + termedit(); +} + + +/* + * Read commands until we are told to stop. + */ +static void docommands(void) +{ + char *cp; + int len; + NUM num1; + NUM num2; + BOOL have1; + BOOL have2; + char buf[USERSIZE]; + + while (TRUE) { + intflag = FALSE; + printf(": "); + fflush(stdout); + + if (fgets(buf, sizeof(buf), stdin) == NULL) + return; + + len = strlen(buf); + if (len == 0) + return; + + cp = &buf[len - 1]; + if (*cp != '\n') { + fprintf(stderr, "Command line too long\n"); + do { + len = fgetc(stdin); + } while ((len != EOF) && (len != '\n')); + + continue; + } + while ((cp > buf) && isblank(cp[-1])) + cp--; + *cp = '\0'; + + cp = buf; + while (isblank(*cp)) + *cp++; + + have1 = FALSE; + have2 = FALSE; + + if ((curnum == 0) && (lastnum > 0)) { + curnum = 1; + curline = lines.next; + } + if (!getnum(&cp, &have1, &num1)) + continue; + + while (isblank(*cp)) + cp++; + + if (*cp == ',') { + cp++; + if (!getnum(&cp, &have2, &num2)) + continue; + + if (!have1) + num1 = 1; + + if (!have2) + num2 = lastnum; + + have1 = TRUE; + have2 = TRUE; + } + if (!have1) + num1 = curnum; + + if (!have2) + num2 = num1; + + switch (*cp++) { + case 'a': + addlines(num1 + 1); + break; + + case 'c': + deletelines(num1, num2); + addlines(num1); + break; + + case 'd': + deletelines(num1, num2); + break; + + case 'f': + if (*cp && !isblank(*cp)) { + fprintf(stderr, "Bad file command\n"); + break; + } + while (isblank(*cp)) + cp++; + if (*cp == '\0') { + if (filename) + printf("\"%s\"\n", filename); + else + printf("No filename\n"); + break; + } + cp = strdup(cp); + if (cp == NULL) { + fprintf(stderr, "No memory for filename\n"); + break; + } + if (filename) + free(filename); + filename = cp; + break; + + case 'i': + addlines(num1); + break; + + case 'k': + while (isblank(*cp)) + cp++; + + if ((*cp < 'a') || (*cp > 'a') || cp[1]) { + fprintf(stderr, "Bad mark name\n"); + break; + } + marks[*cp - 'a'] = num2; + break; + + case 'l': + printlines(num1, num2, TRUE); + break; + + case 'p': + printlines(num1, num2, FALSE); + break; + + case 'q': + while (isblank(*cp)) + cp++; + if (have1 || *cp) { + fprintf(stderr, "Bad quit command\n"); + break; + } + if (!dirty) + return; + + printf("Really quit? "); + fflush(stdout); + + buf[0] = '\0'; + fgets(buf, sizeof(buf), stdin); + cp = buf; + while (isblank(*cp)) + cp++; + if ((*cp == 'y') || (*cp == 'Y')) + return; + break; + + case 'r': + if (*cp && !isblank(*cp)) { + fprintf(stderr, "Bad read command\n"); + break; + } + while (isblank(*cp)) + cp++; + if (*cp == '\0') { + fprintf(stderr, "No filename\n"); + break; + } + if (!have1) + num1 = lastnum; + + if (readlines(cp, num1 + 1)) + break; + + if (filename == NULL) + filename = strdup(cp); + break; + + case 's': + subcommand(cp, num1, num2); + break; + + case 'w': + if (*cp && !isblank(*cp)) { + fprintf(stderr, "Bad write command\n"); + break; + } + while (isblank(*cp)) + cp++; + + if (!have1) { + num1 = 1; + num2 = lastnum; + } + if (*cp == '\0') + cp = filename; + if (cp == NULL) { + fprintf(stderr, "No file name specified\n"); + break; + } + writelines(cp, num1, num2); + break; + + case 'z': + switch (*cp) { + case '-': + printlines(curnum - 21, curnum, FALSE); + break; + case '.': + printlines(curnum - 11, curnum + 10, FALSE); + break; + default: + printlines(curnum, curnum + 21, FALSE); + break; + } + break; + + case '.': + if (have1) { + fprintf(stderr, "No arguments allowed\n"); + break; + } + printlines(curnum, curnum, FALSE); + break; + + case '-': + if (setcurnum(curnum - 1)) + printlines(curnum, curnum, FALSE); + break; + + case '=': + printf("%d\n", num1); + break; + + case '\0': + if (have1) { + printlines(num2, num2, FALSE); + break; + } + if (setcurnum(curnum + 1)) + printlines(curnum, curnum, FALSE); + break; + + default: + fprintf(stderr, "Unimplemented command\n"); + break; + } + } +} + + +/* + * Do the substitute command. + * The current line is set to the last substitution done. + */ +static void subcommand(char *cp, NUM num1, NUM num2) +{ + int delim; + char *oldstr; + char *newstr; + LEN oldlen; + LEN newlen; + LEN deltalen; + LEN offset; + LINE *lp; + LINE *nlp; + BOOL globalflag; + BOOL printflag; + BOOL didsub; + BOOL needprint; + + if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) { + fprintf(stderr, "Bad line range for substitute\n"); + return; + } + globalflag = FALSE; + printflag = FALSE; + didsub = FALSE; + needprint = FALSE; + + if (isblank(*cp) || (*cp == '\0')) { + fprintf(stderr, "Bad delimiter for substitute\n"); + return; + } + delim = *cp++; + oldstr = cp; + + cp = strchr(cp, delim); + if (cp == NULL) { + fprintf(stderr, "Missing 2nd delimiter for substitute\n"); + return; + } + *cp++ = '\0'; + + newstr = cp; + cp = strchr(cp, delim); + if (cp) + *cp++ = '\0'; + else + cp = ""; + + while (*cp) + switch (*cp++) { + case 'g': + globalflag = TRUE; + break; + + case 'p': + printflag = TRUE; + break; + + default: + fprintf(stderr, "Unknown option for substitute\n"); + return; + } + + if (*oldstr == '\0') { + if (searchstring[0] == '\0') { + fprintf(stderr, "No previous search string\n"); + return; + } + oldstr = searchstring; + } + if (oldstr != searchstring) + strcpy(searchstring, oldstr); + + lp = findline(num1); + if (lp == NULL) + return; + + oldlen = strlen(oldstr); + newlen = strlen(newstr); + deltalen = newlen - oldlen; + offset = 0; + + while (num1 <= num2) { + offset = findstring(lp, oldstr, oldlen, offset); + if (offset < 0) { + if (needprint) { + printlines(num1, num1, FALSE); + needprint = FALSE; + } + offset = 0; + lp = lp->next; + num1++; + continue; + } + needprint = printflag; + didsub = TRUE; + dirty = TRUE; + + /* + * If the replacement string is the same size or shorter + * than the old string, then the substitution is easy. + */ + if (deltalen <= 0) { + memcpy(&lp->data[offset], newstr, newlen); + + if (deltalen) { + memcpy(&lp->data[offset + newlen], + &lp->data[offset + oldlen], + lp->len - offset - oldlen); + + lp->len += deltalen; + } + offset += newlen; + if (globalflag) + continue; + + if (needprint) { + printlines(num1, num1, FALSE); + needprint = FALSE; + } + lp = nlp->next; + num1++; + continue; + } + /* + * The new string is larger, so allocate a new line + * structure and use that. Link it in in place of + * the old line structure. + */ + nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltalen); + if (nlp == NULL) { + fprintf(stderr, "Cannot get memory for line\n"); + return; + } + nlp->len = lp->len + deltalen; + + memcpy(nlp->data, lp->data, offset); + + memcpy(&nlp->data[offset], newstr, newlen); + + memcpy(&nlp->data[offset + newlen], + &lp->data[offset + oldlen], + lp->len - offset - oldlen); + + nlp->next = lp->next; + nlp->prev = lp->prev; + nlp->prev->next = nlp; + nlp->next->prev = nlp; + + if (curline == lp) + curline = nlp; + + free(lp); + lp = nlp; + + offset += newlen; + + if (globalflag) + continue; + + if (needprint) { + printlines(num1, num1, FALSE); + needprint = FALSE; + } + lp = lp->next; + num1++; + } + + if (!didsub) + fprintf(stderr, "No substitutions found for \"%s\"\n", oldstr); +} + + +/* + * Search a line for the specified string starting at the specified + * offset in the line. Returns the offset of the found string, or -1. + */ +static LEN findstring(LINE *lp, char *str, LEN len, LEN offset) +{ + LEN left; + char *cp; + char *ncp; + + cp = &lp->data[offset]; + left = lp->len - offset; + + while (left >= len) { + ncp = memchr(cp, *str, left); + if (ncp == NULL) + return -1; + + left -= (ncp - cp); + if (left < len) + return -1; + + cp = ncp; + if (memcmp(cp, str, len) == 0) + return (cp - lp->data); + + cp++; + left--; + } + + return -1; +} + + +/* + * Add lines which are typed in by the user. + * The lines are inserted just before the specified line number. + * The lines are terminated by a line containing a single dot (ugly!), + * or by an end of file. + */ +static void addlines(NUM num) +{ + int len; + char buf[USERSIZE + 1]; + + while (fgets(buf, sizeof(buf), stdin)) { + if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0')) + return; + + len = strlen(buf); + if (len == 0) + return; + + if (buf[len - 1] != '\n') { + fprintf(stderr, "Line too long\n"); + do { + len = fgetc(stdin); + } while ((len != EOF) && (len != '\n')); + return; + } + if (!insertline(num++, buf, len)) + return; + } +} + + +/* + * Parse a line number argument if it is present. This is a sum + * or difference of numbers, '.', '$', 'x, or a search string. + * Returns TRUE if successful (whether or not there was a number). + * Returns FALSE if there was a parsing error, with a message output. + * Whether there was a number is returned indirectly, as is the number. + * The character pointer which stopped the scan is also returned. + */ +static BOOL getnum(char **retcp, BOOL *rethavenum, NUM *retnum) +{ + char *cp; + char *str; + BOOL havenum; + NUM value; + NUM num; + NUM sign; + + cp = *retcp; + havenum = FALSE; + value = 0; + sign = 1; + + while (TRUE) { + while (isblank(*cp)) + cp++; + + switch (*cp) { + case '.': + havenum = TRUE; + num = curnum; + cp++; + break; + + case '$': + havenum = TRUE; + num = lastnum; + cp++; + break; + + case '\'': + cp++; + if ((*cp < 'a') || (*cp > 'z')) { + fprintf(stderr, "Bad mark name\n"); + return FALSE; + } + havenum = TRUE; + num = marks[*cp++ - 'a']; + break; + + case '/': + str = ++cp; + cp = strchr(str, '/'); + if (cp) + *cp++ = '\0'; + else + cp = ""; + num = searchlines(str, curnum, lastnum); + if (num == 0) + return FALSE; + + havenum = TRUE; + break; + + default: + if (!isdecimal(*cp)) { + *retcp = cp; + *rethavenum = havenum; + *retnum = value; + return TRUE; + } + num = 0; + while (isdecimal(*cp)) + num = num * 10 + *cp++ - '0'; + havenum = TRUE; + break; + } + + value += num * sign; + + while (isblank(*cp)) + cp++; + + switch (*cp) { + case '-': + sign = -1; + cp++; + break; + case '+': + sign = 1; + cp++; + break; + + default: + *retcp = cp; + *rethavenum = havenum; + *retnum = value; + return TRUE; + } + } +} + + +/* + * Initialize everything for editing. + */ +static BOOL initedit(void) +{ + int i; + + bufsize = INITBUFSIZE; + bufbase = malloc(bufsize); + if (bufbase == NULL) { + fprintf(stderr, "No memory for buffer\n"); + return FALSE; + } + bufp = bufbase; + bufused = 0; + + lines.next = &lines; + lines.prev = &lines; + + curline = NULL; + curnum = 0; + lastnum = 0; + dirty = FALSE; + filename = NULL; + searchstring[0] = '\0'; + + for (i = 0; i < 26; i++) + marks[i] = 0; + return TRUE; +} + + +/* + * Finish editing. + */ +static void termedit(void) +{ + if (bufbase) + free(bufbase); + bufbase = NULL; + bufp = NULL; + bufsize = 0; + bufused = 0; + + if (filename) + free(filename); + filename = NULL; + + searchstring[0] = '\0'; + + if (lastnum) + deletelines(1, lastnum); + + lastnum = 0; + curnum = 0; + curline = NULL; +} + + +/* + * Read lines from a file at the specified line number. + * Returns TRUE if the file was successfully read. + */ +static BOOL readlines(char *file, NUM num) +{ + int fd; + int cc; + LEN len; + LEN linecount; + LEN charcount; + char *cp; + + if ((num < 1) || (num > lastnum + 1)) { + fprintf(stderr, "Bad line for read\n"); + return FALSE; + } + fd = open(file, 0); + if (fd < 0) { + perror(file); + return FALSE; + } + bufp = bufbase; + bufused = 0; + linecount = 0; + charcount = 0; + + printf("\"%s\", ", file); + fflush(stdout); + + do { + if (intflag) { + printf("INTERRUPTED, "); + bufused = 0; + break; + } + cp = memchr(bufp, '\n', bufused); + if (cp) { + len = (cp - bufp) + 1; + if (!insertline(num, bufp, len)) { + close(fd); + return FALSE; + } + bufp += len; + bufused -= len; + charcount += len; + linecount++; + num++; + continue; + } + if (bufp != bufbase) { + memcpy(bufbase, bufp, bufused); + bufp = bufbase + bufused; + } + if (bufused >= bufsize) { + len = (bufsize * 3) / 2; + cp = realloc(bufbase, len); + if (cp == NULL) { + fprintf(stderr, "No memory for buffer\n"); + close(fd); + return FALSE; + } + bufbase = cp; + bufp = bufbase + bufused; + bufsize = len; + } + cc = read(fd, bufp, bufsize - bufused); + bufused += cc; + bufp = bufbase; + + } while (cc > 0); + + if (cc < 0) { + perror(file); + close(fd); + return FALSE; + } + if (bufused) { + if (!insertline(num, bufp, bufused)) { + close(fd); + return -1; + } + linecount++; + charcount += bufused; + } + close(fd); + + printf("%d lines%s, %d chars\n", linecount, + (bufused ? " (incomplete)" : ""), charcount); + + return TRUE; +} + + +/* + * Write the specified lines out to the specified file. + * Returns TRUE if successful, or FALSE on an error with a message output. + */ +static BOOL writelines(char *file, NUM num1, NUM num2) +{ + int fd; + LINE *lp; + LEN linecount; + LEN charcount; + + if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) { + fprintf(stderr, "Bad line range for write\n"); + return FALSE; + } + linecount = 0; + charcount = 0; + + unlink(file); /* if CREAT resets file size/data, remove this line */ + fd = creat(file, 0666); + if (fd < 0) { + perror(file); + return FALSE; + } + printf("\"%s\", ", file); + fflush(stdout); + + lp = findline(num1); + if (lp == NULL) { + close(fd); + return FALSE; + } + while (num1++ <= num2) { + if (write(fd, lp->data, lp->len) != lp->len) { + perror(file); + close(fd); + return FALSE; + } + charcount += lp->len; + linecount++; + lp = lp->next; + } + + if (close(fd) < 0) { + perror(file); + return FALSE; + } + printf("%d lines, %d chars\n", linecount, charcount); + + return TRUE; +} + + +/* + * Print lines in a specified range. + * The last line printed becomes the current line. + * If expandflag is TRUE, then the line is printed specially to + * show magic characters. + */ +static BOOL printlines(NUM num1, NUM num2, BOOL expandflag) +{ + LINE *lp; + unsigned char *cp; + int ch; + LEN count; + + if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) { + fprintf(stderr, "Bad line range for print\n"); + return FALSE; + } + lp = findline(num1); + if (lp == NULL) + return FALSE; + + while (!intflag && (num1 <= num2)) { + if (!expandflag) { + write(STDOUT, lp->data, lp->len); + setcurnum(num1++); + lp = lp->next; + continue; + } + /* + * Show control characters and characters with the + * high bit set specially. + */ + cp = lp->data; + count = lp->len; + if ((count > 0) && (cp[count - 1] == '\n')) + count--; + + while (count-- > 0) { + ch = *cp++; + if (ch & 0x80) { + fputs("M-", stdout); + ch &= 0x7f; + } + if (ch < ' ') { + fputc('^', stdout); + ch += '@'; + } + if (ch == 0x7f) { + fputc('^', stdout); + ch = '?'; + } + fputc(ch, stdout); + } + fputs("$\n", stdout); + + setcurnum(num1++); + lp = lp->next; + } + + return TRUE; +} + + +/* + * Insert a new line with the specified text. + * The line is inserted so as to become the specified line, + * thus pushing any existing and further lines down one. + * The inserted line is also set to become the current line. + * Returns TRUE if successful. + */ +static BOOL insertline(NUM num, char *data, LEN len) +{ + LINE *newlp; + LINE *lp; + + if ((num < 1) || (num > lastnum + 1)) { + fprintf(stderr, "Inserting at bad line number\n"); + return FALSE; + } + newlp = (LINE *) malloc(sizeof(LINE) + len - 1); + if (newlp == NULL) { + fprintf(stderr, "Failed to allocate memory for line\n"); + return FALSE; + } + memcpy(newlp->data, data, len); + newlp->len = len; + + if (num > lastnum) + lp = &lines; + else { + lp = findline(num); + if (lp == NULL) { + free((char *) newlp); + return FALSE; + } + } + + newlp->next = lp; + newlp->prev = lp->prev; + lp->prev->next = newlp; + lp->prev = newlp; + + lastnum++; + dirty = TRUE; + + return setcurnum(num); +} + + +/* + * Delete lines from the given range. + */ +static BOOL deletelines(NUM num1, NUM num2) +{ + LINE *lp; + LINE *nlp; + LINE *plp; + NUM count; + + if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) { + fprintf(stderr, "Bad line numbers for delete\n"); + return FALSE; + } + lp = findline(num1); + if (lp == NULL) + return FALSE; + + if ((curnum >= num1) && (curnum <= num2)) { + if (num2 < lastnum) + setcurnum(num2 + 1); + else if (num1 > 1) + setcurnum(num1 - 1); + else + curnum = 0; + } + count = num2 - num1 + 1; + + if (curnum > num2) + curnum -= count; + + lastnum -= count; + + while (count-- > 0) { + nlp = lp->next; + plp = lp->prev; + plp->next = nlp; + nlp->prev = plp; + lp->next = NULL; + lp->prev = NULL; + lp->len = 0; + free(lp); + lp = nlp; + } + + dirty = TRUE; + + return TRUE; +} + + +/* + * Search for a line which contains the specified string. + * If the string is NULL, then the previously searched for string + * is used. The currently searched for string is saved for future use. + * Returns the line number which matches, or 0 if there was no match + * with an error printed. + */ +static NUM searchlines(char *str, NUM num1, NUM num2) +{ + LINE *lp; + int len; + + if ((num1 < 1) || (num2 > lastnum) || (num1 > num2)) { + fprintf(stderr, "Bad line numbers for search\n"); + return 0; + } + if (*str == '\0') { + if (searchstring[0] == '\0') { + fprintf(stderr, "No previous search string\n"); + return 0; + } + str = searchstring; + } + if (str != searchstring) + strcpy(searchstring, str); + + len = strlen(str); + + lp = findline(num1); + if (lp == NULL) + return 0; + + while (num1 <= num2) { + if (findstring(lp, str, len, 0) >= 0) + return num1; + + num1++; + lp = lp->next; + } + + fprintf(stderr, "Cannot find string \"%s\"\n", str); + + return 0; +} + + +/* + * Return a pointer to the specified line number. + */ +static LINE *findline(NUM num) +{ + LINE *lp; + NUM lnum; + + if ((num < 1) || (num > lastnum)) { + fprintf(stderr, "Line number %d does not exist\n", num); + return NULL; + } + if (curnum <= 0) { + curnum = 1; + curline = lines.next; + } + if (num == curnum) + return curline; + + lp = curline; + lnum = curnum; + + if (num < (curnum / 2)) { + lp = lines.next; + lnum = 1; + } else if (num > ((curnum + lastnum) / 2)) { + lp = lines.prev; + lnum = lastnum; + } + while (lnum < num) { + lp = lp->next; + lnum++; + } + + while (lnum > num) { + lp = lp->prev; + lnum--; + } + + return lp; +} + + +/* + * Set the current line number. + * Returns TRUE if successful. + */ +static BOOL setcurnum(NUM num) +{ + LINE *lp; + + lp = findline(num); + if (lp == NULL) + return FALSE; + + curnum = num; + curline = lp; + + return TRUE; +} + +/* END CODE */ diff --git a/Applications/util/false.c b/Applications/util/false.c new file mode 100644 index 00000000..241975f5 --- /dev/null +++ b/Applications/util/false.c @@ -0,0 +1,6 @@ +#include + +int main(int argc, char *argv[]) +{ + exit(1); +} diff --git a/Applications/util/fsck.c b/Applications/util/fsck.c new file mode 100644 index 00000000..6de8a1b5 --- /dev/null +++ b/Applications/util/fsck.c @@ -0,0 +1,797 @@ +/************************************************** +UZI (Unix Z80 Implementation) Utilities: fsck.c + 21.09.99 corrected daread, ckdir - HP + 06.05.01 adapted to work under uzi - HP +***************************************************/ + +#include +#include +#include +#include +#include +#include + +#define MAXDEPTH 20 /* Maximum depth of directory tree to search */ + +/* This checks a filesystem */ + +int dev; +struct _uzifilesys filsys; + +#define SMOUNTED 12472 + +typedef uint16_t blkno_t; + +char *bitmap; +int16_t *linkmap; + +char *daread(uint16_t blk); +int yes(void); + +struct dinode { + uint16_t i_mode; + uint16_t i_nlink; + uint16_t i_uid; + uint16_t i_gid; + off_t i_size; + uint32_t i_atime; /* Breaks in 2038 */ + uint32_t i_mtime; /* Need to hide some extra bits ? */ + uint32_t i_ctime; /* 24 bytes */ + blkno_t i_addr[20]; +}; /* Exactly 64 bytes long! */ + +/* Internal version */ +struct _uzidirent { + uint16_t d_ino; + char d_name[30]; +}; + +#define ROOTINODE 1 + + +char *daread(uint16_t blk) +{ + static char da_buf[512]; + + lseek(dev, blk * 512L, 0); + if (read(dev, da_buf, 512) != 512) { + fprintf(stderr, "Read of block %d failed.\n", blk); + exit(-1); + } + + return da_buf; +} + + +void dwrite(uint16_t blk, char *addr) +{ + + lseek(dev, blk * 512L, 0); + if (write(dev, addr, 512) != 512) + fprintf(stderr, "Write of block %d failed %d.\n", blk, errno); + /*sync();*/ +} + + +/* + * Getblkno gets a pointer index, and a number of a block in the file. + * It returns the number of the block on the disk. A value of zero + * means an unallocated block. + */ + +blkno_t getblkno(struct dinode *ino, blkno_t num) +{ + blkno_t indb; + blkno_t dindb; + blkno_t *buf; + + if (num < 18) { /* Direct block */ + return (ino->i_addr[num]); + } + if (num < 256 + 18) { /* Single indirect */ + indb = ino->i_addr[18]; + if (indb == 0) + return (0); + buf = (blkno_t *) daread(indb); + return (buf[num - 18]); + } + /* Double indirect */ + indb = ino->i_addr[19]; + if (indb == 0) + return (0); + + buf = (blkno_t *) daread(indb); + + dindb = buf[(num - (18 + 256)) >> 8]; + buf = (blkno_t *) daread(dindb); + + return (buf[(num - (18 + 256)) & 0x00ff]); +} + + +/* + * Setblkno sets the given block number of the given file to the given + * disk block number, possibly creating or modifiying the indirect blocks. + * A return of zero means there were no blocks available to create an + * indirect block. This should never happen in fsck. + */ + +void setblkno(struct dinode *ino, blkno_t num, blkno_t dnum) +{ + blkno_t indb; + blkno_t dindb; + blkno_t *buf; + + if (num < 18) { /* Direct block */ + ino->i_addr[num] = dnum; + } else if (num < 256 + 18) { /* Single indirect */ + indb = ino->i_addr[18]; + if (indb == 0) { + fprintf(stderr, "Missing indirect block"); + exit(-1); + } + + buf = (blkno_t *) daread(indb); + buf[num - 18] = dnum; + dwrite(indb, (char *) buf); + } else { /* Double indirect */ + indb = ino->i_addr[19]; + if (indb == 0) { + fprintf(stderr, "Missing indirect block"); + exit(-1); + } + + buf = (blkno_t *) daread(indb); + dindb = buf[(num - (18 + 256)) >> 8]; + if (dindb == 0) { + fprintf(stderr, "Missing indirect block"); + exit(-1); + } + + buf = (blkno_t *) daread(dindb); + buf[(num - (18 + 256)) & 0x00ff] = num; + dwrite(indb, (char *) buf); + } +} + + +/* + * blk_alloc0 allocates an unused block. + * A returned block number of zero means no more blocks. + */ + +/*--- was blk_alloc ---*/ + +blkno_t blk_alloc0(struct _uzifilesys *filsys) +{ + blkno_t newno; + blkno_t *buf; + int16_t j; + + newno = filsys->s_free[--filsys->s_nfree]; + if (!newno) { + ++filsys->s_nfree; + return (0); + } + + /* See if we must refill the s_free array */ + + if (!filsys->s_nfree) { + buf = (blkno_t *) daread(newno); + filsys->s_nfree = buf[0]; + for (j = 0; j < 50; j++) { + filsys->s_free[j] = buf[j + 1]; + } + } + + --filsys->s_tfree; + + if (newno < filsys->s_isize || newno >= filsys->s_fsize) { + printf("Free list is corrupt. Did you rebuild it?\n"); + return (0); + } + dwrite((blkno_t) 1, (char *) filsys); + return (newno); +} + + + +void iread(uint16_t ino, struct dinode *buf) +{ + struct dinode *addr; + + addr = (struct dinode *) daread((ino >> 3) + 2); + bcopy((char *) &addr[ino & 7], (char *) buf, sizeof(struct dinode)); +} + + +void iwrite(uint16_t ino, struct dinode *buf) +{ + struct dinode *addr; + + addr = (struct dinode *) daread((ino >> 3) + 2); + bcopy((char *) buf, (char *) &addr[ino & 7], sizeof(struct dinode)); + dwrite((ino >> 3) + 2, (char *) addr); +} + + +void dirread(struct dinode *ino, uint16_t j, struct _uzidirent *dentry) +{ + blkno_t blkno; + char *buf; + + blkno = getblkno(ino, (blkno_t) j / 16); + if (blkno == 0) { + fprintf(stderr, "Missing block in directory"); + exit(-1); + } + buf = daread(blkno); + bcopy(buf + 32 * (j % 16), (char *) dentry, 32); +} + + +void dirwrite(struct dinode *ino, uint16_t j, struct _uzidirent *dentry) +{ + blkno_t blkno; + char *buf; + + blkno = getblkno(ino, (blkno_t) j / 32); + if (blkno == 0) { + fprintf(stderr, "Missing block in directory"); + exit(-1); + } + buf = daread(blkno); + bcopy((char *) dentry, buf + 32 * (j % 16), 32); + dwrite(blkno, buf); +} + +/* This makes an entry in "lost+found" for inode n */ + +void mkentry(uint16_t inum) +{ + struct dinode rootino; + struct _uzidirent dentry; + uint16_t d; + + iread(ROOTINODE, &rootino); + for (d = 0; d < rootino.i_size/32; ++d) { + dirread(&rootino, d, &dentry); + if (dentry.d_ino == 0 && dentry.d_name[0] == '\0') { + dentry.d_ino = inum; + sprintf(dentry.d_name, "l+f%d", inum); + dirwrite(&rootino, d, &dentry); + return; + } + } + printf("Sorry... No empty slots in root directory.\n"); +} + + +/* + * Pass 1 checks each inode independently for validity, zaps bad block + * numbers in the inodes, and builds the block allocation map. + */ + +void pass1(void) +{ + uint16_t n; + struct dinode ino; + uint16_t mode; + blkno_t b; + blkno_t bno; + uint16_t icount; + blkno_t *buf; + + icount = 0; + + for (n = ROOTINODE; n < 8 * (filsys.s_isize - 2); ++n) { + iread(n, &ino); + linkmap[n] = -1; + if (ino.i_mode == 0) + continue; + + mode = ino.i_mode & S_IFMT; + + /* FIXME: named pipes ? */ + /* Check mode */ + if (mode != S_IFREG && mode != S_IFDIR && mode != S_IFBLK && mode != S_IFCHR) { + printf("Inode %d with mode 0%o is not of correct type. Zap? ", + n, ino.i_mode); + if (yes()) { + ino.i_mode = 0; + ino.i_nlink = 0; + iwrite(n, &ino); + continue; + } + } + linkmap[n] = 0; + ++icount; + /* Check size */ + + if (ino.i_size < 0) { + printf("Inode %d offset is negative with value of %ld. Fix? ", + n, ino.i_size); + if (yes()) { + ino.i_size = 0; + iwrite(n, &ino); + } + } + /* Check blocks and build free block map */ + if (mode == S_IFREG || mode == S_IFDIR) { + /* Check singly indirect blocks */ + + for (b = 18; b < 20; ++b) { + if (ino.i_addr[b] != 0 && (ino.i_addr[b] < filsys.s_isize || + ino.i_addr[b] >= filsys.s_fsize)) { + printf("Inode %d singly ind. blk %d out of range, val = %u. Zap? ", + n, b, ino.i_addr[b]); + if (yes()) { + ino.i_addr[b] = 0; + iwrite(n, &ino); + } + } + if (ino.i_addr[b] != 0 && ino.i_size < 18*512) { + printf("Inode %d singly ind. blk %d past end of file, val = %u. Zap? ", + n, b, ino.i_addr[b]); + if (yes()) { + ino.i_addr[b] = 0; + iwrite(n, &ino); + } + } + if (ino.i_addr[b] != 0) + bitmap[ino.i_addr[b]] = 1; + } + + /* Check the double indirect blocks */ + if (ino.i_addr[19] != 0) { + buf = (blkno_t *) daread(ino.i_addr[19]); + for (b = 0; b < 256; ++b) { + if (buf[b] != 0 && (buf[b] < filsys.s_isize || + buf[b] >= filsys.s_fsize)) { + printf("Inode %d doubly ind. blk %d is ", n, b); + printf("out of range, val = %u. Zap? ", buf[b]); + /* 1.4.98 - line split. HFB */ + if (yes()) { + buf[b] = 0; + dwrite(b, (char *) buf); + } + } + if (buf[b] != 0) + bitmap[buf[b]] = 1; + } + } + /* Check the rest */ + for (bno = 0; bno <= ino.i_size >> 9; ++bno) { + b = getblkno(&ino, bno); + + if (b != 0 && (b < filsys.s_isize || b >= filsys.s_fsize)) { + printf("Inode %d block %d out of range, val = %u. Zap? ", + n, bno, b); + if (yes()) { + setblkno(&ino, bno, 0); + iwrite(n, &ino); + } + } + if (b != 0) + bitmap[b] = 1; + } + } + } + /* Fix free inode count in super block */ + if (filsys.s_tinode != 8 * (filsys.s_isize - 2) - ROOTINODE - icount) { + printf("Free inode count in super block is %u, should be %u. Fix? ", + filsys.s_tinode, 8 * (filsys.s_isize - 2) - ROOTINODE - icount); + + if (yes()) { + filsys.s_tinode = 8 * (filsys.s_isize - 2) - ROOTINODE - icount; + dwrite((blkno_t) 1, (char *) &filsys); + } + } +} + + +/* Clear inode free list, rebuild block free list using bit map. */ + +void pass2(void) +{ + blkno_t j; + blkno_t oldtfree; + + printf("Rebuild free list? "); + if (!yes()) + return; + + oldtfree = filsys.s_tfree; + + /* Initialize the super-block */ + + filsys.s_ninode = 0; + filsys.s_nfree = 1; + filsys.s_free[0] = 0; + filsys.s_tfree = 0; + + /* Free each block, building the free list */ + + for (j = filsys.s_fsize - 1; j >= filsys.s_isize; --j) { + if (bitmap[j] == 0) { + if (filsys.s_nfree == 50) { + dwrite(j, (char *) &filsys.s_nfree); + filsys.s_nfree = 0; + } + ++filsys.s_tfree; + filsys.s_free[(filsys.s_nfree)++] = j; + } + } + + dwrite((blkno_t) 1, (char *) &filsys); + + if (oldtfree != filsys.s_tfree) + printf("During free list regeneration s_tfree was changed to %d from %d.\n", + filsys.s_tfree, oldtfree); + +} + + +/* Pass 3 finds and fixes multiply allocated blocks. */ + +void pass3(void) +{ + uint16_t n; + struct dinode ino; + uint16_t mode; + blkno_t b; + blkno_t bno; + blkno_t newno; + + for (b = filsys.s_isize; b < filsys.s_fsize; ++b) + bitmap[b] = 0; + + for (n = ROOTINODE; n < 8 * (filsys.s_isize - 2); ++n) { + iread(n, &ino); + + mode = ino.i_mode & S_IFMT; + if (mode != S_IFREG && mode != S_IFDIR) + continue; + + /* Check singly indirect blocks */ + + for (b = 18; b < 20; ++b) { + if (ino.i_addr[b] != 0) { + if (bitmap[ino.i_addr[b]] != 0) { + printf("Indirect block %d in inode %u value %u multiply allocated. Fix? ", + b, n, ino.i_addr[b]); + if (yes()) { + newno = blk_alloc0(&filsys); + if (newno == 0) + printf("Sorry... No more free blocks.\n"); + else { + dwrite(newno, daread(ino.i_addr[b])); + ino.i_addr[b] = newno; + iwrite(n, &ino); + } + } + } else + bitmap[ino.i_addr[b]] = 1; + } + } + + /* Check the rest */ + for (bno = 0; bno <= ino.i_size >> 9; ++bno) { + b = getblkno(&ino, bno); + + if (b != 0) { + if (bitmap[b] != 0) { + printf("Block %d in inode %u value %u multiply allocated. Fix? ", + bno, n, b); + if (yes()) { + newno = blk_alloc0(&filsys); + if (newno == 0) + printf("Sorry... No more free blocks.\n"); + else { + dwrite(newno, daread(b)); + setblkno(&ino, bno, newno); + iwrite(n, &ino); + } + } + } else + bitmap[b] = 1; + } + } + + } + +} + +int depth; + + +/* This recursively checks the directories */ + +void ckdir(uint16_t inum, uint16_t pnum, char *name) +{ + struct dinode ino; + struct _uzidirent dentry; + uint16_t j; + int c; + int nentries; + char ename[150]; + + iread(inum, &ino); + if ((ino.i_mode & S_IFMT) != S_IFDIR) + return; + ++depth; + + if (ino.i_size % 32 != 0) { + printf("Directory inode %d has improper length. Fix? "); + if (yes()) { + ino.i_size &= (~0x1f); + iwrite(inum, &ino); + } + } + nentries = ino.i_size/32; + + for (j = 0; j < nentries; ++j) { + dirread(&ino, j, &dentry); + +#if 1 /* cleanup entry - HP */ + { + int i; + + for (i = 0; i < 30; ++i) if (dentry.d_name[i] == '\0') break; + for ( ; i < 30; ++i) dentry.d_name[i] = '\0'; + dirwrite(&ino, j, &dentry); + } +#endif + + + if (dentry.d_ino == 0) + continue; + + if (dentry.d_ino < ROOTINODE || dentry.d_ino >= 8 * filsys.s_isize) { + printf("Directory entry %s%-1.30s has out-of-range inode %u. Zap? ", + name, dentry.d_name, dentry.d_ino); + if (yes()) { + dentry.d_ino = 0; + dentry.d_name[0] = '\0'; + dirwrite(&ino, j, &dentry); + continue; + } + } + if (dentry.d_ino && linkmap[dentry.d_ino] == -1) { + printf("Directory entry %s%-1.30s points to bogus inode %u. Zap? ", + name, dentry.d_name, dentry.d_ino); + if (yes()) { + dentry.d_ino = 0; + dentry.d_name[0] = '\0'; + dirwrite(&ino, j, &dentry); + continue; + } + } + ++linkmap[dentry.d_ino]; + + for (c = 0; c < 14 && dentry.d_name[c]; ++c) { + if (dentry.d_name[c] == '/') { + printf("Directory entry %s%-1.30s contains slash. Fix? ", + name, dentry.d_name); + if (yes()) { + dentry.d_name[c] = 'X'; + dirwrite(&ino, j, &dentry); + } + } + } + + if (strncmp(dentry.d_name, ".", 14) == 0 && dentry.d_ino != inum) { + printf("\".\" entry %s%-1.30s points to wrong place. Fix? ", + name, dentry.d_name); + if (yes()) { + dentry.d_ino = inum; + dirwrite(&ino, j, &dentry); + } + } + if (strncmp(dentry.d_name, "..", 14) == 0 && dentry.d_ino != pnum) { + printf("\"..\" entry %s%-1.30s points to wrong place. Fix? ", + name, dentry.d_name); + if (yes()) { + dentry.d_ino = pnum; + dirwrite(&ino, j, &dentry); + } + } + if (dentry.d_ino != pnum && dentry.d_ino != inum && depth < MAXDEPTH) { + strcpy(ename, name); + strcat(ename, dentry.d_name); + strcat(ename, "/"); + ckdir(dentry.d_ino, inum, ename); + } + } + --depth; +} + +/* + * Pass 4 traverses the directory tree, fixing bad directory entries + * and finding the actual number of references to each inode. + */ + +void pass4(void) +{ + depth = 0; + linkmap[ROOTINODE] = 1; + ckdir(ROOTINODE, ROOTINODE, "/"); + if (depth != 0) { + fprintf(stderr, "Inconsistent depth"); + exit(-1); + } +} + + + +/* Pass 5 compares the link counts found in pass 4 with the inodes. */ + +void pass5(void) +{ + uint16_t n; + struct dinode ino; + + for (n = ROOTINODE; n < 8 * (filsys.s_isize - 2); ++n) { + iread(n, &ino); + + if (ino.i_mode == 0) { + if (linkmap[n] != -1) { + fprintf(stderr, "Inconsistent linkmap"); + exit(-1); + } + continue; + } + + if (linkmap[n] == -1 && ino.i_mode != 0) { + fprintf(stderr, "Inconsistent linkmap"); + exit(-1); + } + + if (linkmap[n] > 0 && ino.i_nlink != linkmap[n]) { + printf("Inode %d has link count %d should be %d. Fix? ", + n, ino.i_nlink, linkmap[n]); + if (yes()) { + ino.i_nlink = linkmap[n]; + iwrite(n, &ino); + } + } + + if (linkmap[n] == 0) { + if ((ino.i_mode & S_IFMT) == S_IFBLK || + (ino.i_mode & S_IFMT) == S_IFCHR || + (ino.i_size == 0)) { + printf("Useless inode %d with mode 0%o has become detached. Link count is %d. Zap? ", + n, ino.i_mode, ino.i_nlink); + if (yes()) { + ino.i_nlink = 0; + ino.i_mode = 0; + iwrite(n, &ino); + ++filsys.s_tinode; + dwrite((blkno_t) 1, (char *) &filsys); + } + } else { +#if 0 + printf("Inode %d has become detached. Link count is %d. Fix? ", + n, ino.i_nlink); + if (yes()) { + ino.i_nlink = 1; + iwrite(n, &ino); + mkentry(n); + } +#else + printf("Inode %d has become detached. Link count is %d. ", + n, ino.i_nlink); + if (ino.i_nlink == 0) + printf("Zap? "); + else + printf("Fix? "); + if (yes()) { + if (ino.i_nlink == 0) { + ino.i_nlink = 0; + ino.i_mode = 0; + iwrite(n, &ino); + ++filsys.s_tinode; + dwrite((blkno_t) 1, (char *) &filsys); + } else { + ino.i_nlink = 1; + iwrite(n, &ino); + mkentry(n); + } + } +#endif + } + } + + } +} + + + + +int yes(void) +{ + char line[20]; + /*int fgets(); -- HP */ + + if (!fgets(line, sizeof(line), stdin) || (*line != 'y' && *line != 'Y')) + return (0); + + return (1); +} + + +main(int argc, char *argv[]) +{ + char *buf; + struct stat statbuf; + + if (argc != 2) { + fprintf(stderr, "usage: fsck device\n"); + exit(-1); + } + + if (stat(argv[1], &statbuf) != 0) { + fprintf(stderr, "fsck: can't stat %s\n", argv[1]); + exit(-1); + } + + if ((statbuf.st_mode & S_IFMT) != S_IFBLK) { + fprintf(stderr, "fsck: %s is not a valid device\n", argv[1]); + exit(-1); + } + + dev = open(argv[1], O_RDWR); + if (dev < 0) { + fprintf(stderr, "fsck: can't open device %s\n", argv[1]); + exit(-1); + } + + /* Read in the super block. */ + + buf = daread(1); + bcopy(buf, (char *) &filsys, sizeof(struct _uzifilesys)); + + /* Verify the fsize and isize parameters */ + + if (filsys.s_mounted != SMOUNTED) { + printf("Device %s has invalid magic number %d. Fix? ", + argv[1], filsys.s_mounted); + if (!yes()) + exit(-1); + filsys.s_mounted = SMOUNTED; + dwrite((blkno_t) 1, (char *) &filsys); + } + printf("Device %s has fsize = %d and isize = %d. Continue? ", + argv[1], filsys.s_fsize, filsys.s_isize); + if (!yes()) + exit(-1); + + bitmap = calloc(filsys.s_fsize, sizeof(char)); + linkmap = (int16_t *) calloc(8 * filsys.s_isize, sizeof(int16_t)); + + if (!bitmap || !linkmap) { + fprintf(stderr, "Not enough memory.\n"); + exit(-1); + } + + printf("Pass 1: Checking inodes...\n"); + pass1(); + + printf("Pass 2: Rebuilding free list...\n"); + pass2(); + + printf("Pass 3: Checking block allocation...\n"); + pass3(); + + printf("Pass 4: Checking directory entries...\n"); + pass4(); + + printf("Pass 5: Checking link counts...\n"); + pass5(); + + sync(); + printf("Done.\n"); + + return 0; +} + diff --git a/Applications/util/grep.c b/Applications/util/grep.c new file mode 100644 index 00000000..7e274163 --- /dev/null +++ b/Applications/util/grep.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 1993 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + * + * The "grep" built-in command. + */ + +#include +#include +#include + +typedef unsigned char BOOL; + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +BOOL intflag; +static char buf[8192]; + +/* + * See if the specified word is found in the specified string. + */ +static BOOL search(char *string, char *word, BOOL ignorecase) +{ + char *cp1, *cp2; + int ch1, ch2, len, lowfirst; + + len = strlen(word); + + if (!ignorecase) { + while (TRUE) { + string = strchr(string, word[0]); + if (string == NULL) + return FALSE; + + if (memcmp(string, word, len) == 0) + return TRUE; + + string++; + } + } + /* + * Here if we need to check case independence. + * Do the search by lower casing both strings. + */ + lowfirst = *word; + if (isupper(lowfirst)) + lowfirst = tolower(lowfirst); + + while (TRUE) { + while (*string && (*string != lowfirst) && + (!isupper(*string) || (tolower(*string) != lowfirst))) + string++; + + if (*string == '\0') + return FALSE; + + cp1 = string; + cp2 = word; + + do { + if (*cp2 == '\0') + return TRUE; + + ch1 = *cp1++; + if (isupper(ch1)) + ch1 = tolower(ch1); + + ch2 = *cp2++; + if (isupper(ch2)) + ch2 = tolower(ch2); + + } while (ch1 == ch2); + + string++; + } +} + + +void main(int argc, char *argv[]) +{ + FILE *fp; + char *word, *name, *cp; + BOOL tellname, ignorecase, tellline; + long line; + + ignorecase = FALSE; + tellline = FALSE; + + argc--; + argv++; + + if (**argv == '-') { + argc--; + cp = *argv++; + + while (*++cp) + switch (*cp) { + case 'i': + ignorecase = TRUE; + break; + + case 'n': + tellline = TRUE; + break; + + default: + fprintf(stderr, "Unknown option\n"); + return; + } + } + word = *argv++; + argc--; + + tellname = (argc > 1); + + while (argc-- > 0) { + name = *argv++; + + fp = fopen(name, "r"); + if (fp == NULL) { + perror(name); + continue; + } + line = 0; + + while (fgets(buf, sizeof(buf), fp)) { + if (intflag) { + fclose(fp); + return; + } + line++; + + cp = &buf[strlen(buf) - 1]; + if (*cp != '\n') + fprintf(stderr, "%s: Line too long\n", name); + + if (search(buf, word, ignorecase)) { + if (tellname) + printf("%s: ", name); + if (tellline) + printf("%d: ", line); + + fputs(buf, stdout); + } + } + + if (ferror(fp)) + perror(name); + + fclose(fp); + } +} + +/* END CODE */ diff --git a/Applications/util/grp.h b/Applications/util/grp.h new file mode 100644 index 00000000..dfcf25c8 --- /dev/null +++ b/Applications/util/grp.h @@ -0,0 +1,37 @@ +#ifndef __GRP_H +#define __GRP_H + +#include + +#ifndef _UID_T +#define _UID_T +typedef int uid_t; +#endif + +#ifndef _GID_T +#define _GID_T +typedef int gid_t; +#endif + +/* The passwd structure */ +struct group +{ + char *gr_name; /* group name */ + char *gr_passwd; /* group password */ + gid_t gr_gid; /* group ID */ + char **gr_mem; /* group members */ +}; + + +extern int setgrent(void); +extern void endgrent(void); +extern struct group *getgrent(void); + +extern int putgrent(struct group *, FILE *); +extern int getgr(gid_t uid, char *buf); + +extern struct group *getgrgid(gid_t); +extern struct group *getgrnam(char *); + + +#endif /* grp.h */ diff --git a/Applications/util/id.c b/Applications/util/id.c new file mode 100644 index 00000000..c528a722 --- /dev/null +++ b/Applications/util/id.c @@ -0,0 +1,52 @@ +/* id - return uid and gid Author: John J. Marco */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ +/* ----- id.c ----- */ +/* Id - get real and effective user id and group id */ +/* Author: John J. Marco */ +/* pa1343@sdcc15.ucsd.edu */ +/* Modified for UZI180 by H. Peraza */ +/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +#include +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + struct passwd *pwd; + struct group *grp; + int uid, gid, euid, egid; + + uid = getuid(); + gid = getgid(); + euid = geteuid(); + egid = getegid(); + + if ((pwd = getpwuid(uid)) == NULL) + printf("uid=%d ", uid); + else + printf("uid=%d(%s) " , uid, pwd->pw_name); + + if ((grp = getgrgid(gid)) == NULL) + printf("gid=%d ", gid); + else + printf("gid=%d(%s) ", gid, grp->gr_name); + + if (uid != euid) + if ((pwd = getpwuid(euid)) != NULL) + printf("euid=%d(%s) ", euid, pwd->pw_name); + else + printf("euid=%d ", euid); + + if (gid != egid) + if ((grp = getgrgid(egid)) != NULL) + printf("egid=%d(%s) ", egid, grp->gr_name); + else + printf("egid=%d ", egid); + + printf("\n"); + return(0); +} diff --git a/Applications/util/init.c b/Applications/util/init.c new file mode 100644 index 00000000..fb3eeffe --- /dev/null +++ b/Applications/util/init.c @@ -0,0 +1,212 @@ +/* init.c - simplified init program for UZI180 (mix of init/getty/login) + * only handles logins in /dev/tty1 + * handles user names from /etc/passwd + */ + +#include +#include +#include +#include +#include +#include + +extern char **environ; + +char *argp[] = { "sh", NULL }; + +#define crlf write(1, "\n", 1) + +int login(char *); +void spawn(struct passwd *); +int showfile(char *); +void putstr(char *); +void sigalarm(unsigned int); + +int main(int argc, char *argv[]) +{ + int fdtty1, sh_pid, pid; + + signal(SIGINT, SIG_IGN); + + /* remove any stale /etc/mtab file */ + + unlink("/etc/mtab"); + + /* loop until we can open the first terminal */ + + do { + fdtty1 = open("/dev/tty1", O_RDWR); + } while (fdtty1 < 0); + + /* make stdin, stdout and stderr point to /dev/tty1 */ + + if (fdtty1 != 0) close(0); + dup(fdtty1); + close(1); + dup(fdtty1); + close(2); + dup(fdtty1); + + putstr("init version 0.8\n"); + + /* then call the login procedure on it */ + + for (;;) { + + sh_pid = login("/dev/tty1"); + + /* wait until the user exits the shell */ + + do { + pid = wait(NULL); + } while (sh_pid != pid); + + /* then loop to call login again */ + + crlf; + } +} + +int login(char *ttyname) +{ + int fdtty, pid; + struct passwd *pwd; + char *p, buf[50], salt[3]; + + fdtty = open(ttyname, O_RDWR); + if (fdtty < 0) return -1; + + for (;;) { + pid = fork(); + if (pid == -1) { + putstr("init: can't fork\n"); + } else { + if (pid != 0) { + close(fdtty); + /* parent's context: return pid of the child process */ + return pid; + } + + /* here we are inside child's context of execution */ + + putenv("PATH=:/bin:/usr/bin"); + strcpy(buf, "CTTY="); + strcat(buf, ttyname); + putenv(buf); + + /* make stdin, stdout and stderr point to fdtty */ + + close(0); + dup(fdtty); + close(1); + dup(fdtty); + close(2); + dup(fdtty); + + /* display the /etc/issue file, if exists */ + showfile("/etc/issue"); + + /* loop until a valid user name is entered + * and a shell is spawned */ + + for (;;) { + putstr("login: "); + while (read(0, buf, 20) < 0); /* EINTR might happens because of the alarm() call below */ + + if ((p = strchr(buf, '\n')) != NULL) + *p = '\0'; /* strip newline */ + + pwd = getpwnam(buf); + + if (pwd) { + if (pwd->pw_passwd[0] != '\0') { + p = getpass("Password: "); + salt[0] = pwd->pw_passwd[0]; + salt[1] = pwd->pw_passwd[1]; + salt[2] = '\0'; + p = crypt(p, salt); + } else { + p = ""; + } + if (strcmp(p, pwd->pw_passwd) == 0) spawn(pwd); + } + + putstr("Login incorrect\n\n"); + signal(SIGALRM, sigalarm); + alarm(2); + pause(); + } + } + } +} + +void spawn(struct passwd *pwd) +{ + char *p, buf[50]; + + setgid(pwd->pw_gid); + setuid(pwd->pw_uid); + signal(SIGINT, SIG_DFL); + + /* setup user environment variables */ + + strcpy(buf, "LOGNAME="); + strcat(buf, pwd->pw_name); + putenv(buf); + + strcpy(buf, "HOME="); + strcat(buf, pwd->pw_dir); + putenv(buf); + + strcpy(buf, "SHELL="); + strcat(buf, pwd->pw_shell); + putenv(buf); + + /*chdir(pwd->pw_dir);*/ + + /* show the motd file */ + + if (!showfile("/etc/motd")) crlf; + + /* and spawn the shell */ + + strcpy(buf, "-"); + if ((p = strrchr(pwd->pw_shell, '/')) != NULL) + strcat(buf, ++p); + else + strcat(buf, pwd->pw_shell); + + argp[0] = buf; + argp[1] = NULL; + + execve(pwd->pw_shell, argp, environ); + putstr("login: can't execute shell\n"); + exit(1); +} + +void sigalarm(unsigned int sig) +{ + return; +} + +int showfile(char *fname) +{ + int fd, len; + char buf[80]; + + fd = open(fname, O_RDONLY); + if (fd > 0) { + do { + len = read(fd, buf, 80); + write(1, buf, len); + } while (len > 0); + close(fd); + return 1; + } + return 0; +} + +void putstr(char *str) +{ + write(1, str, strlen(str)); +} diff --git a/Applications/util/kill.c b/Applications/util/kill.c new file mode 100644 index 00000000..87e1db83 --- /dev/null +++ b/Applications/util/kill.c @@ -0,0 +1,63 @@ +/* Copyright (c) 1993 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + * + * Most simple built-in commands are here. + */ + +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + char *cp; + int pid, sig = SIGTERM; + + if (argc < 2) { + fprintf(stderr, "usage: kill [-sig] pid ...\n"); + return 0; + } + if (argv[1][0] == '-') { + cp = &argv[1][1]; + if (!strncmp(cp, "SIG", 3)) + cp += 3; + if (!strcmp(cp, "HUP")) + sig = SIGHUP; + else if (!strcmp(cp, "INT")) + sig = SIGINT; + else if (!strcmp(cp, "QUIT")) + sig = SIGQUIT; + else if (strcmp(cp, "KILL")) + sig = SIGKILL; + else if (strcmp(cp, "TERM")) + sig = SIGTERM; + else { + sig = 0; + while (isdigit(*cp)) + sig = sig * 10 + *cp++ - '0'; + if (*cp) { + fprintf(stderr, "kill: unknown signal\n"); + return 1; + } + } + argc--; + argv++; + } + while (argc-- > 1) { + cp = *++argv; + pid = 0; + while (isdigit(*cp)) + pid = pid * 10 + *cp++ - '0'; + if (*cp) { + fprintf(stderr, "kill: non-numeric pid\n"); + continue; + } + if (kill(pid, sig) < 0) { + perror(*argv); + return 1; + } + } + return 0; +} diff --git a/Applications/util/ll.c b/Applications/util/ll.c new file mode 100644 index 00000000..3555c9c2 --- /dev/null +++ b/Applications/util/ll.c @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include +#include + +char *month[] = { "Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" }; + + +void prmode(int mode) +{ + if (mode & 4) + printf("r"); + else + printf("-"); + + if (mode & 2) + printf("w"); + else + printf("-"); + + if (mode & 1) + printf("x"); + else + printf("-"); +} + +/* FIXME: use readdir */ +struct _uzidirent { + uint16_t ino; + char d_name[30]; +}; + +int ls(char *path) +{ + int d, st; + struct _uzidirent buf; + struct stat statbuf; + char dname[128]; + + if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) { + printf("ls: can't stat %s\n", path); + return -1; + } + + d = open(path, O_RDONLY); + if (d < 0) { + printf ("ls: can't open %s\n", path); + return -1; + } + + /* FIXME: use readdir etc */ + while (read(d, (char *)&buf, 32) == 16) { + if (buf.d_name[0] == '\0') + continue; + + if (path[0] != '.' || path[1]) { + strcpy(dname, path); + strcat(dname, "/"); + } else { + dname[0] = '\0'; + } + + /* FIXME: 128 byte overflow */ + strcat(dname, buf.d_name); + + if (stat(dname, &statbuf) != 0) { + printf("ls: can't stat %s\n", dname); + break; + } + + st = statbuf.st_mode & S_IFMT; + + if (st == S_IFDIR) + printf("d"); + else if (st == S_IFCHR) + printf("c"); + else if (st == S_IFBLK) + printf("b"); + else if (st == S_IFIFO) + printf("p"); + else if ((st & S_IFREG) == 0) + printf("l"); + else + printf("-"); + + prmode(statbuf.st_mode >> 6); + prmode(statbuf.st_mode >> 3); + prmode(statbuf.st_mode); + + printf("%4d %5d", statbuf.st_nlink, statbuf.st_ino); + if (S_ISDIR(statbuf.st_mode)) + strcat(dname, "/"); + else if (statbuf.st_mode & 0111) + strcat(dname, "*"); + + printf("%12lu ", + (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) ? + statbuf.st_rdev : + statbuf.st_size); + + if (statbuf.st_mtime == 0) { /* st_mtime? */ + printf(" "); + } else { + struct tm *t = localtime(&statbuf.st_mtime); + printf("%2s %02d %4d ", + month[t->tm_mon], + t->tm_mday, + t->tm_year); + + printf("%2d:%02d", + t->tm_hour, + t->tm_min); + } + + printf(" %-30s\n", dname); + } + close (d); + return 0; +} + +int main(int argc, char *argval[]) +{ + if (argc < 2) + return ls("."); + else + return ls(argval[1]); +} diff --git a/Applications/util/ln.c b/Applications/util/ln.c new file mode 100644 index 00000000..01b2b16a --- /dev/null +++ b/Applications/util/ln.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1993 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + */ + +#include +#include +#include +#include + +#ifndef BOOL +#define BOOL int +#define TRUE 1 +#define FALSE 0 +#endif + +#define PATHLEN 512 + + +/* + * Return TRUE if name is a directory. + * Return FALSE otherwise or if the file does not exist. + */ + +BOOL isadir(char *name) +{ + struct stat statbuf; + + if (stat(name, &statbuf) < 0) + return FALSE; + + return S_ISDIR(statbuf.st_mode); +} + + +/* + * Build a path name from the specified directory name and file name. + * If the directory name is NULL, then the original filename is returned. + * The built path is in a static area, and is overwritten for each call. + */ + +char *buildname(char *dirname, char *filename) +{ + char *cp; + static char buf[PATHLEN]; + + if ((dirname == NULL) || (*dirname == '\0')) + return filename; + + cp = strrchr(filename, '/'); + if (cp) + filename = cp + 1; + + /* FIXME: overflow check */ + strcpy(buf, dirname); + strcat(buf, "/"); + strcat(buf, filename); + + return buf; +} + + +int main(int argc, char *argv[]) +{ + int dirflag; + char *srcname, *destname, *lastarg; + + /* Symbolic link? */ + + if (argv[1][0] == '-') { +#if defined(S_ISLNK) && 0 /* FIXME */ + if (strcmp(argv[1], "-s") == 0) { + if (argc != 4) { + fprintf(stderr, "%s: wrong number of arguments for symbolic link\n", argv[0]); + return 1; + } + + if (symlink(argv[2], argv[3]) < 0) { + perror(argv[3]); + return 1; + } + return 0; + + } +#endif + fprintf(stderr, "%s: unknown option %s\n", argv[0], argv[1]); + return 1; + } + + /* Here for normal hard links. */ + + lastarg = argv[argc - 1]; + dirflag = isadir(lastarg); + + if ((argc > 3) && !dirflag) { + fprintf(stderr, "%s: not a directory\n", lastarg); + return 1; + } + + while (argc-- > 2) { + srcname = *(++argv); + if (access(srcname, 0) < 0) { + perror(srcname); + continue; + } + + destname = lastarg; + if (dirflag) + destname = buildname(destname, srcname); + + if (link(srcname, destname) < 0) { + perror(destname); + continue; + } + } + + return 0; +} diff --git a/Applications/util/ls.c b/Applications/util/ls.c new file mode 100644 index 00000000..97da0a06 --- /dev/null +++ b/Applications/util/ls.c @@ -0,0 +1,342 @@ +/* The "ls" standard command. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define LISTSIZE 256 + +typedef unsigned char BOOL; + +#define PATHLEN 512 + +#ifdef S_ISLNK +#define LSTAT lstat +#else +#define LSTAT stat +#endif + +/* + * Flags for the LS command. + */ +#define LSF_LONG 0x01 +#define LSF_DIR 0x02 +#define LSF_INODE 0x04 +#define LSF_MULT 0x08 +#define LSF_FILE 0x10 +#define LSF_DOWN 0x20 +#define LSF_ALL 0x40 +#define LSF_OCT 0x80 +#define LSF_UNSORT 0x100 + +static char **list; +static int listsize; +static int listused; +static int flags; + +static void lsfile(char *, struct stat *, int); +static char *modestring(int mode); +char *timestring(time_t *t); +int namesort(const void *p1, const void *p2); + +long time_zone = 0; +long timezone = 0; + + +/* + * Sort routine for list of filenames. + */ +int namesort(const void *p1, const void *p2) +{ + return strcmp(* (char * const *)p1, * (char * const *) p2); +} + +/* + * Return the standard ls-like mode string from a file mode. + * This is static and so is overwritten on each call. + */ +static char *modestring(int mode) +{ + static char buf[12]; + + if (flags & LSF_OCT) { + sprintf(buf, "%06o", mode); + return buf; + } + strcpy(buf, "----------"); + + /* Fill in the file type. */ + if (S_ISDIR(mode)) + buf[0] = 'd'; + if (S_ISCHR(mode)) + buf[0] = 'c'; + if (S_ISBLK(mode)) + buf[0] = 'b'; +#ifdef S_ISLNK + if (S_ISLNK(mode)) + buf[0] = 'l'; +#endif + /* Now fill in the normal file permissions. */ + if (mode & S_IRUSR) + buf[1] = 'r'; + if (mode & S_IWUSR) + buf[2] = 'w'; + if (mode & S_IXUSR) + buf[3] = 'x'; + + if (mode & S_IRGRP) + buf[4] = 'r'; + if (mode & S_IWGRP) + buf[5] = 'w'; + if (mode & S_IXGRP) + buf[6] = 'x'; + + if (mode & S_IROTH) + buf[7] = 'r'; + if (mode & S_IWOTH) + buf[8] = 'w'; + if (mode & S_IXOTH) + buf[9] = 'x'; + + /* Finally fill in magic stuff like suid and sticky text. */ + if (mode & S_ISUID) + buf[3] = ((mode & S_IXUSR) ? 's' : 'S'); + if (mode & S_ISGID) + buf[6] = ((mode & S_IXGRP) ? 's' : 'S'); + if (mode & S_ISVTX) + buf[9] = ((mode & S_IXOTH) ? 't' : 'T'); + return buf; +} + +/* + * Get the time to be used for a file. + * This is down to the minute for new files, but only the date for old files. + * The string is returned from a static buffer, and so is overwritten for + * each call. + */ +char *timestring(time_t *t) +{ + char *str; + static char buf[26]; + + str = ctime(t); + strcpy(buf, &str[4]); + buf[12] = '\0'; +#if 0 /* ??? */ + if ((t > now) || (t < now - 365 * 24 * 60 * 60L)) { + strcpy(&buf[7], &str[20]); + buf[11] = '\0'; + } +#endif + return buf; +} + +/* + * Do an LS of a particular file name according to the flags. + */ +static void lsfile(char *name, struct stat *statbuf, int flags) +{ + static char username[12]; + static int userid; + static BOOL useridknown; + static char groupname[12]; + static int groupid; + static BOOL groupidknown; + + struct passwd *pwd; + struct group *grp; + char buf[PATHLEN], *cp = buf; + int len; + + *cp = '\0'; + if (flags & LSF_INODE) { + sprintf(cp, "%5d ", statbuf->st_ino); + cp += strlen(cp); + } + if (flags & LSF_LONG) { + cp += strlen(strcpy(cp, modestring(statbuf->st_mode))); + sprintf(cp, "%4d ", statbuf->st_nlink); + cp += strlen(cp); +#if 1 + if (!useridknown || (statbuf->st_uid != userid)) { + if ((pwd = getpwuid(statbuf->st_uid)) != NULL) + strcpy(username, pwd->pw_name); + else + sprintf(username, "%d", statbuf->st_uid); + userid = statbuf->st_uid; + useridknown = 1; + } + sprintf(cp, "%-8s ", username); + cp += strlen(cp); + if (!groupidknown || (statbuf->st_gid != groupid)) { + if ((grp = getgrgid(statbuf->st_gid)) != NULL) + strcpy(groupname, grp->gr_name); + else + sprintf(groupname, "%d", statbuf->st_gid); + groupid = statbuf->st_gid; + groupidknown = 1; + } + sprintf(cp, "%-8s ", groupname); + cp += strlen(cp); +#endif + if (S_ISDEV(statbuf->st_mode)) + sprintf(cp, "%3d,%-3d ", + statbuf->st_rdev >> 8, statbuf->st_rdev & 0xFF); + else + sprintf(cp, "%8ld ", (long) statbuf->st_size); + cp += strlen(cp); + sprintf(cp, "%-12s ", timestring(&statbuf->st_mtime)); + } + fputs(buf, stdout); + fputs(name, stdout); +#ifdef S_ISLNK + if ((flags & LSF_LONG) && S_ISLNK(statbuf->st_mode)) { + if ((len = readlink(name, buf, PATHLEN - 1)) >= 0) { + buf[len] = '\0'; + printf(" -> %s", buf); + } + } +#endif + fputc('\n', stdout); +} + +void main(int argc, char *argv[]) +{ + static char *def[1] = + {"."}; + + struct stat statbuf; + struct dirent *dp; + BOOL endslash; + DIR *dirp; + int i; + char *cp, *name, **newlist, fullname[PATHLEN]; + + if ((list = (char **) malloc(LISTSIZE * sizeof(char *))) == NULL) { + fprintf(stderr, "No memory for ls buffer\n"); + return; + } + listsize = LISTSIZE; + listused = 0; + flags = 0; + for (--argc, ++argv; argc > 0 && argv[0][0] == '-'; --argc, ++argv) { + for (cp = *argv + 1; *cp; ++cp) { + switch (*cp) { + case 'h': + printf("Usage: ls [-dilfaouR] [pattern]\n"); + return; + case 'd': + flags |= LSF_DIR; + break; + case 'i': + flags |= LSF_INODE; + break; + case 'l': + flags |= LSF_LONG; + break; + case 'f': + flags |= LSF_FILE; + break; + case 'a': + flags |= LSF_ALL; + break; + case 'o': + flags |= LSF_OCT; + break; + case 'u': + flags |= LSF_UNSORT; + break; + case 'R': + flags |= LSF_DOWN; + break; + default: + fprintf(stderr, "Unknown option -%c\n", *cp); + return; + } + } + } + if (argc == 0) { + argc = 1; + argv = def; + } + if (argc > 1) + flags |= LSF_MULT; + while (--argc >= 0) { + name = *argv++; + endslash = (*name && (name[strlen(name) - 1] == '/')); + if (LSTAT(name, &statbuf) < 0) { + perror(name); + continue; + } + if ((flags & LSF_DIR) || (!S_ISDIR(statbuf.st_mode))) { + lsfile(name, &statbuf, flags); + continue; + } + /* Do all the files in a directory. */ + if ((dirp = opendir(name)) == NULL) { + perror(name); + continue; + } + if (flags & LSF_MULT) + printf("\n%s:\n", name); + while ((dp = readdir(dirp)) != NULL) { + if (dp->d_name[0] == '\0') + continue; + if (!(flags & LSF_ALL) && dp->d_name[0] == '.') + continue; + fullname[0] = '\0'; + if ((*name != '.') || (name[1] != '\0')) { + strcpy(fullname, name); + if (!endslash) + strcat(fullname, "/"); + } + strcat(fullname, dp->d_name); + if (listused >= listsize) { + newlist = realloc(list, + ((sizeof(char **)) * (listsize + LISTSIZE))); + if (newlist == NULL) { + fprintf(stderr, "No memory for ls buffer\n"); + break; + } + list = newlist; + listsize += LISTSIZE; + } + if ((list[listused] = strdup(fullname)) == NULL) { + fprintf(stderr, "No memory for filenames\n"); + break; + } + listused++; + } + closedir(dirp); + /* Sort the files. */ + if (!(flags & LSF_UNSORT)) + qsort((char *) list, listused, + sizeof(char *), namesort); /**/ + /* Now finally list the filenames. */ + for (i = 0; i < listused; i++, free(name)) { + name = list[i]; + if (LSTAT(name, &statbuf) < 0) { + perror(name); + continue; + } + if (((flags & LSF_DIR) && !S_ISDIR(statbuf.st_mode)) || + ((flags & LSF_FILE) && S_ISDIR(statbuf.st_mode))) + continue; + if ((cp = strrchr(name, '/')) != 0) + ++cp; + else + cp = name; + lsfile(cp, &statbuf, flags); + } + listused = 0; + } + fflush(stdout); +} + diff --git a/Applications/util/mkdir.c b/Applications/util/mkdir.c new file mode 100644 index 00000000..ea7209f9 --- /dev/null +++ b/Applications/util/mkdir.c @@ -0,0 +1,53 @@ +#include +#include +#include + +unsigned short newmode; + +int make_dir(const char *name, int f) +{ + char *line; + char iname[256]; + + int l = strlen(name) - 1; + + /* FIXME: Size check ! */ + strcpy(iname, name); + if (l && iname[l] == '/') + iname[l] = 0; + if (((line = rindex(iname, '/')) != NULL) && f) { + while ((line > iname) && (*line == '/')) + --line; + line[1] = 0; + make_dir(iname, 1); + } + if (mkdir(name, newmode) && !f) + return (1); + else + return (0); +} + + +int main(int argc, char *argv[]) +{ + int i, parent = 0, er = 0; + + if ((argv[1][0] == '-') && (argv[1][1] == 'p')) + parent = 1; + + newmode = 0777 & ~umask(0); + + for (i = parent + 1; i < argc; i++) { + if (argv[i][0] != '-') { + + if (make_dir(argv[i], parent)) { + fprintf(stderr, "mkdir: cannot create directory %s\n", argv[i]); + er = 1; + } + } else { + fprintf(stderr, "mkdir: usage error\n"); + exit(1); + } + } + return er; +} diff --git a/Applications/util/mkfs.c b/Applications/util/mkfs.c new file mode 100644 index 00000000..0b6e252a --- /dev/null +++ b/Applications/util/mkfs.c @@ -0,0 +1,175 @@ +/************************************************** +UZI (Unix Z80 Implementation) Utilities: mkfs.c +***************************************************/ + +/* This utility creates an UZI file system for a defined block device. + * the format is: + * mkfs device isize fsize + * where: device is the logical block on which to install a filesystem + * isize is the number of 512-byte blocks (less two reserved for + * system use) to use for storing 64-byte i-nodes + * fsize is the total number of 512-byte blocks to assign to the + * filesystem. Space available for storage of data is therefore + * fsize-isize blocks. + * + * Revisions: + * Based on UZI280 version (minor changes from original UZI. HFB + * Modified for use under UZI. HP + */ + +#include +#include + +long lseek(uchar, long, uchar); + +int dev; + +direct dirbuf[32] = { ROOTINODE, ".", ROOTINODE, ".." }; +struct dinode inode[8]; +struct filesys fs_tab; + +main(argc, argv) +int argc; +char *argv[]; +{ + uint16 fsize, isize; + struct stat statbuf; + int atoi(), yes(), stat(), open(); + + if (argc != 4) { + fprintf(stderr, "usage: mkfs device isize fsize\n"); + exit(-1); + } + + if (stat(argv[1], &statbuf) != 0) { + fprintf(stderr, "mkfs: can't stat %s\n", argv[1]); + exit(-1); + } + + if ((statbuf.st_mode & F_BDEV) != F_BDEV) { + fprintf(stderr, "mkfs: %s is not a block device\n", argv[1]); + exit(-1); + } + + isize = (uint16) atoi(argv[2]); + fsize = (uint16) atoi(argv[3]); + + if (fsize < 3 || isize < 2 || isize >= fsize) { + fprintf(stderr, "mkfs: bad parameter values\n"); + exit(-1); + } + + printf("Making filesystem on device %s with isize %u fsize %u. Confirm? ", + argv[1], isize, fsize); + if (!yes()) + exit(-1); + + dev = open(argv[1], O_RDWR); + if (dev < 0) { + fprintf(stderr, "mkfs: can't open device %s\n", argv[1]); + exit(-1); + } + + mkfs(fsize, isize); + + exit(0); +} + + +mkfs(fsize, isize) +uint16 fsize, isize; +{ + uint16 j; + char *zeros; + char *zerobuf(); + + /* Zero out the blocks */ + printf("Zeroizing i-blocks...\n"); + zeros = zerobuf(); /* Get a zero filled buffer */ + +#if 1 + for (j = 0; j < fsize; ++j) + dwrite(j, zeros); +#else + for (j = 0; j < isize; ++j) + dwrite(j, zeros); +#endif + + /* Initialize the super-block */ + fs_tab.s_mounted = SMOUNTED; /* Magic number */ + fs_tab.s_isize = isize; + fs_tab.s_fsize = fsize; + fs_tab.s_nfree = 1; + fs_tab.s_free[0] = 0; + fs_tab.s_tfree = 0; + fs_tab.s_ninode = 0; + fs_tab.s_tinode = (8 * (isize - 2)) - 2; + + /* Free each block, building the free list */ + + printf("Building free list...\n"); + for (j = fsize - 1; j > isize; --j) { + if (fs_tab.s_nfree == 50) { + dwrite(j, (char *) &fs_tab.s_nfree); + fs_tab.s_nfree = 0; + } + ++fs_tab.s_tfree; + fs_tab.s_free[(fs_tab.s_nfree)++] = j; + } + + /* The inodes are already zeroed out */ + /* create the root dir */ + + inode[ROOTINODE].i_mode = F_DIR | (0777 & MODE_MASK); + inode[ROOTINODE].i_nlink = 3; + inode[ROOTINODE].i_size.o_blkno = 0; + inode[ROOTINODE].i_size.o_offset = 32; + inode[ROOTINODE].i_addr[0] = isize; + + /* Reserve reserved inode */ + inode[0].i_nlink = 1; + inode[0].i_mode = ~0; + + printf("Writing initial inode and superblock...\n"); + + sync(); + dwrite(2, (char *) inode); + dwrite(isize, (char *) dirbuf); + + sync(); + /* Write out super block */ + dwrite(1, (char *) &fs_tab); + + sync(); + printf("Done.\n"); +} + + +dwrite(blk, addr) +uint16 blk; +char *addr; +{ + int write(); + + lseek(dev, blk * 512L, 0); + write(dev, addr, 512); +} + +char *zerobuf() +{ + static char buf[512]; + + blkclr(buf, 512); + return buf; +} + + +int yes() +{ + char line[20]; + + if (!fgets(line, sizeof(line), stdin) || (*line != 'y' && *line != 'Y')) + return (0); + + return (1); +} diff --git a/Applications/util/mknod.c b/Applications/util/mknod.c new file mode 100644 index 00000000..97a0794a --- /dev/null +++ b/Applications/util/mknod.c @@ -0,0 +1,42 @@ +#include +#include +#include + + +int do_mknod(char *path, char *modes, char *devs) +{ + int mode; + int dev; + + mode = -1; + sscanf(modes, "%o", &mode); + if (mode == -1) { + printf("mknod: bad mode\n"); + return (-1); + } + + if (!S_ISFIFO(mode) && !S_ISDEV(mode)) { + printf("mknod: mode is not device/fifo\n"); + return (-1); + } + + if (sscanf(devs, "%d", &dev) != 1) { + printf("mknod: bad device\n"); + return (-1); + } + + if (mknod(path, mode, dev) != 0) { + perror("mknod"); + return (-1); + } + return(0); +} + +int main(int argc, char *argv[]) +{ + if (argc != 4) { + printf("usage: mknod path modes devs\n"); + return 1; + } + return do_mknod(argv[1], argv[2], argv[3]); +} diff --git a/Applications/util/more.c b/Applications/util/more.c new file mode 100644 index 00000000..f59f3583 --- /dev/null +++ b/Applications/util/more.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1993 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + */ + +#include +#include +#include +#include + +int more(FILE *fp); + +int main(int argc, char *argv[]) +{ + FILE *fp; + char *name; + int next; + + if (argc == 1) { + + next = dup(0); + close(0); + name = getenv("CTTY"); + if (!name) { + fprintf(stderr, "%s: CTTY not set\n", argv[0]); + return -1; + } + if (open(name, O_RDWR) == 0) { + fp = fdopen(next, "r"); + if (fp) more(fp); + } else { + perror("more (CTTY)"); + } + + } else while (argc-- > 1) { + + name = *(++argv); + + fp = fopen(name, "r"); + if (fp == NULL) { + perror(name); + return 1; + } + + printf("<< %s >>\n", name); + next = more(fp); + fclose(fp); + if (!next) break; + } + + return 0; +} + +int more(FILE *fp) +{ + int ch, line, col; + char buf[80]; + + line = 1; + col = 0; + + while ((ch = fgetc(fp)) != EOF) { + switch (ch) { + case '\r': + col = 0; + break; + + case '\n': + line++; + col = 0; + break; + + case '\t': + col = ((col + 1) | 0x07) + 1; + break; + + case '\b': + if (col > 0) --col; + break; + + default: + col++; + } + + putchar(ch); + if (col >= 80) { + col -= 80; + ++line; + } + if (line < 24) + continue; + + if (col > 0) + putchar('\n'); + + printf("--More--"); + fflush(stdout); + + if (read(0, buf, sizeof(buf)) < 0) { + return 0; + } + ch = buf[0]; + if (ch == ':') + ch = buf[1]; + + switch (ch) { + case 'N': /* next file */ + case 'n': + return 1; + + case 'Q': /* quit */ + case 'q': + return 0; + } + + col = 0; + line = 1; + } + + return 1; +} diff --git a/Applications/util/mount.c b/Applications/util/mount.c new file mode 100644 index 00000000..72e4693f --- /dev/null +++ b/Applications/util/mount.c @@ -0,0 +1,82 @@ +#include +#include +#include + + +char tmp[256]; + +int lsmtab(void) +{ + FILE *f; + static char dev[20], mntpt[20], fstype[20], rwflag[20]; + + f = fopen("/etc/mtab", "r"); + if (f) { + while (fgets(tmp, 256, f)) { + sscanf(tmp, "%s %s %s %s\n", dev, mntpt, fstype, rwflag); + if (strcmp(fstype, "swap") == 0) + printf("%s is swapspace\n", dev); + else + printf("%s mounted on %s read-%s\n", dev, mntpt, + (strcmp(rwflag, "ro") == 0) ? "only" : "write"); + } + fclose(f); + } + + return 0; +} + +int add2mtab(char *dev, char *mntpt, char *fstype, char *rwflag) +{ + FILE *inpf, *outf; + char *tmp_fname; + + if ((tmp_fname = tmpnam(NULL)) == NULL) { + perror("Error getting temporary file name"); + exit(1); + } + inpf = fopen("/etc/mtab", "r"); + outf = fopen(tmp_fname, "w"); + if (!outf) { + perror("Can't create temporary file"); + exit(1); + } + if (inpf) { + while (fgets(tmp, 255, inpf)) { + fprintf(outf, "%s", tmp); + } + fclose(inpf); + } + fprintf(outf, "%s %s %s %s\n", dev, mntpt, fstype, rwflag); + fclose(outf); + if (inpf && unlink("/etc/mtab") < 0) { + perror("Can't delete old /etc/mtab file"); + exit(1); + } + if (rename(tmp_fname, "/etc/mtab") < 0) { + perror("Error installing /etc/mtab"); + exit(1); + } + return 0; +} + +main(int argc, char *argv[]) +{ + if (argc == 1) { + lsmtab(); + return 0; + } + + if (argc != 3) { + printf("usage: mount device path\n"); + return 1; + } + + if (mount(argv[1], argv[2], 0) == 0) { + add2mtab(argv[1], argv[2], "uzi", "rw"); + } else { + perror("mount"); + return 1; + } + return 0; +} diff --git a/Applications/util/mv.c b/Applications/util/mv.c new file mode 100644 index 00000000..f3bffeff --- /dev/null +++ b/Applications/util/mv.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 1993 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + * + * Most simple built-in commands are here. + */ + +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned char BOOL; + +#define FALSE 0 +#define TRUE 1 + +#define PATHLEN 512 + + +BOOL intflag; + +#define BUF_SIZE 4096 + +/* + * Return TRUE if a filename is a directory. + * Nonexistant files return FALSE. + */ +BOOL isadir(char *name) +{ + struct stat statbuf; + + if (stat(name, &statbuf) < 0) + return FALSE; + + return S_ISDIR(statbuf.st_mode); +} + +/* + * Copy one file to another, while possibly preserving its modes, times, + * and modes. Returns TRUE if successful, or FALSE on a failure with an + * error message output. (Failure is not indicted if the attributes cannot + * be set.) + */ +BOOL copyfile(char *srcname, char *destname, BOOL setmodes) +{ + int rfd; + int wfd; + int rcc; + int wcc; + char *bp; + char *buf; + struct stat statbuf1; + struct stat statbuf2; + struct utimbuf times; + + if (stat(srcname, &statbuf1) < 0) { + perror(srcname); + return FALSE; + } + + if (stat(destname, &statbuf2) < 0) { + statbuf2.st_ino = -1; + statbuf2.st_dev = -1; + } + + if ((statbuf1.st_dev == statbuf2.st_dev) && + (statbuf1.st_ino == statbuf2.st_ino)) { + fprintf(stderr, "Copying file \"%s\" to itself\n", srcname); + return FALSE; + } + + rfd = open(srcname, 0); + if (rfd < 0) { + perror(srcname); + return FALSE; + } + + wfd = creat(destname, statbuf1.st_mode); + if (wfd < 0) { + perror(destname); + close(rfd); + return FALSE; + } + + buf = malloc(BUF_SIZE); + if (buf == NULL) { + fprintf(stderr, "Out of memory.\n"); + goto error_exit; + } + while ((rcc = read(rfd, buf, BUF_SIZE)) > 0) { + bp = buf; + while (rcc > 0) { + wcc = write(wfd, bp, rcc); + if (wcc < 0) { + perror(destname); + goto error_exit; + } + bp += wcc; + rcc -= wcc; + } + } + + if (rcc < 0) { + perror(srcname); + goto error_exit; + } + + close(rfd); + if (close(wfd) < 0) { + perror(destname); + return FALSE; + } + + if (setmodes) { + chmod(destname, statbuf1.st_mode); + + chown(destname, statbuf1.st_uid, statbuf1.st_gid); + + times.actime = statbuf1.st_atime; + times.modtime = statbuf1.st_mtime; + + utime(destname, ×); + } + + return TRUE; + + + error_exit: + close(rfd); + close(wfd); + + return FALSE; +} + +/* + * Build a path name from the specified directory name and file name. + * If the directory name is NULL, then the original filename is returned. + * The built path is in a static area, and is overwritten for each call. + */ +char *buildname(char *dirname, char *filename) +{ + char *cp; + /* FIXME: length check */ + static char buf[PATHLEN]; + + if ((dirname == NULL) || (*dirname == '\0')) + return filename; + + cp = strrchr(filename, '/'); + if (cp) + filename = cp + 1; + + strcpy(buf, dirname); + strcat(buf, "/"); + strcat(buf, filename); + + return buf; +} + + +int main(int argc, char *argv[]) +{ + int dirflag; + char *srcname; + char *destname; + char *lastarg; + + lastarg = argv[argc - 1]; + + dirflag = isadir(lastarg); + + if ((argc > 3) && !dirflag) { + fprintf(stderr, "%s: not a directory\n", lastarg); + return 1; + } + + while (argc-- > 2) { + srcname = *(++argv); + if (access(srcname, 0) < 0) { + perror(srcname); + continue; + } + + destname = lastarg; + if (dirflag) + destname = buildname(destname, srcname); + + if (rename(srcname, destname) >= 0) + continue; + + if (errno != EXDEV) { + perror(destname); + continue; + } + + if (!copyfile(srcname, destname, TRUE)) + continue; + + if (unlink(srcname) < 0) + perror(srcname); + } + + return 0; +} diff --git a/Applications/util/od.c b/Applications/util/od.c new file mode 100644 index 00000000..6d20aaf6 --- /dev/null +++ b/Applications/util/od.c @@ -0,0 +1,308 @@ +/* od - octal dump Author: Andy Tanenbaum */ +/* Adapted to UZI180 by H. Peraza */ + +#include +#include +#include + +int bflag, cflag, dflag, oflag, xflag, hflag, vflag; +int linenr, width, state, ever; +int prevwds[8]; +long off; +char buf[512], buffer[BUFSIZ]; +int next; +int bytespresent; + + +int main(int argc, char **argv); +long offset(int argc, char *argv[], int k); +void dumpfile(void); +void wdump(short *words, int k, int radix); +void bdump(char bytes[16], int k, int c); +void byte(int val, int c); +int getwords(short **words); +int same(short *w1, int *w2); +void outword(int val, int radix); +void outnum(int num, int radix); +void addrout(long l); +char hexit(int k); +void usage(void); + + + +long offset(int argc, char *argv[], int k) +{ + int dot, radix; + char *p, c; + long val; + + /* See if the offset is decimal. */ + dot = 0; + p = argv[k]; + while (*p) + if (*p++ == '.') dot = 1; + + /* Convert offset to binary. */ + radix = (dot ? 10 : 8); + val = 0; + p = argv[k]; + if (*p == '+') p++; + while (*p != 0 && *p != '.') { + c = *p++; + if (c < '0' || c > '9') { + printf("Bad character in offset: %c\n", c); + exit(1); + } + val = (long) radix * val + (long) (c - '0'); + } + + p = argv[k + 1]; + if (k + 1 == argc - 1 && *p == 'b') val = 512L * val; + + return(val); +} + + +void dumpfile(void) +{ + int k; + short *words; + + while ((k = getwords(&words))) { /* 'k' is # bytes read */ + if (!vflag) { /* ensure 'lazy' evaluation */ + if (k == 16 && ever == 1 && same(words, prevwds)) { + if (state == 0) { + printf("*\n"); + state = 1; + off += 16L; + continue; + } else if (state == 1) { + off += 16L; + continue; + } + } + } + addrout(off); + off += (long) k; + state = 0; + ever = 1; + linenr = 1; + if (oflag) wdump(words, k, 8); + if (dflag) wdump(words, k, 10); + if (xflag) wdump(words, k, 16); + if (cflag) bdump((char *)words, k, (int)'c'); + if (bflag) bdump((char *)words, k, (int)'b'); + for (k = 0; k < 8; k++) prevwds[k] = words[k]; + for (k = 0; k < 8; k++) words[k] = 0; + } +} + + +void wdump(short *words, int k, int radix) +{ + int i; + + if (linenr++ != 1) printf(" "); + for (i = 0; i < (k + 1) / 2; i++) + outword(words[i] & 0xFFFF, radix); + printf("\n"); +} + + +void bdump(char bytes[16], int k, int c) +{ + int i; + + if (linenr++ != 1) printf(" "); + for (i = 0; i < k; i++) + byte(bytes[i] & 0377, c); + printf("\n"); +} + +void byte(int val, int c) +{ + if (c == 'b') { + printf(" "); + outnum(val, 7); + return; + } + if (val == 0) + printf(" \\0"); + else if (val == '\b') + printf(" \\b"); + else if (val == '\f') + printf(" \\f"); + else if (val == '\n') + printf(" \\n"); + else if (val == '\r') + printf(" \\r"); + else if (val == '\t') + printf(" \\t"); + else if (val >= ' ' && val < 0177) + printf(" %c", val); + else { + printf(" "); + outnum(val, 7); + } +} + + +int getwords(short **words) +{ + int count; + + if (next >= bytespresent) { + bytespresent = read(0, buf, 512); + next = 0; + } + if (next >= bytespresent) return(0); + *words = (short *) &buf[next]; + if (next + 16 <= bytespresent) + count = 16; + else + count = bytespresent - next; + + next += count; + + return(count); +} + +int same(short *w1, int *w2) +{ + int i; + + i = 8; + while (i--) + if (*w1++ != *w2++) return(0); + + return(1); +} + +void outword(int val, int radix) +{ + /* Output 'val' in 'radix' in a field of total size 'width'. */ + + int i = 4; + + if (radix == 16) i = width - 4; + if (radix == 10) i = width - 5; + if (radix == 8) i = width - 6; + + if (i == 1) + printf(" "); + else if (i == 2) + printf(" "); + else if (i == 3) + printf(" "); + else if (i == 4) + printf(" "); + + outnum(val, radix); +} + + +void outnum(int num, int radix) +{ + /* Output a number with all leading 0s present. Octal is 6 places, + * decimal is 5 places, hex is 4 places. + */ + unsigned val; + + val = (unsigned) num; + if (radix == 8) + printf ("%06o", val); + else if (radix == 10) + printf ("%05u", val); + else if (radix == 16) + printf ("%04x", val); + else if (radix == 7) { + /* special case */ + printf ("%03o", val); + } +} + + +void addrout(long l) +{ + if (hflag == 0) { + printf("%07lo", l); + } else { + printf("%07lx", l); + } +} + + +void usage(void) +{ + fprintf(stderr, "Usage: od [-bcdhovx] [file] [ [+] offset [.] [b] ]\n"); + exit(1); +} + +int main(int argc, char *argv[]) +{ + int k, flags; + char *p; + + /* Process flags */ + setbuf(stdout, buffer); + flags = 0; + p = argv[1]; + if (argc > 1 && *p == '-') { + /* Flags present. */ + flags++; + p++; + while (*p) { + switch (*p) { + case 'b': bflag++; break; + case 'c': cflag++; break; + case 'd': dflag++; break; + case 'h': hflag++; break; + case 'o': oflag++; break; + case 'v': vflag++; break; + case 'x': xflag++; break; + default: usage(); + } + p++; + } + } else { + oflag = 1; + } + + if ((bflag | cflag | dflag | oflag | xflag) == 0) oflag = 1; + k = (flags ? 2 : 1); + if (bflag | cflag) { + width = 8; + } else if (oflag) { + width = 7; + } else if (dflag) { + width = 6; + } else { + width = 5; + } + + /* Process file name, if any. */ + p = argv[k]; + if (k < argc && *p != '+') { + /* Explicit file name given. */ + close(0); + if (open(argv[k], O_RDONLY) != 0) { + fprintf(stderr, "od: cannot open %s\n", argv[k]); + exit(1); + } + k++; + } + + /* Process offset, if any. */ + if (k < argc) { + /* Offset present. */ + off = offset(argc, argv, k); + off = (off / 16L) * 16L; + lseek(0, off, SEEK_SET); + } + + dumpfile(); + addrout(off); + printf("\n"); + + return(0); +} diff --git a/Applications/util/passwd.c b/Applications/util/passwd.c new file mode 100644 index 00000000..7ca6e0a3 --- /dev/null +++ b/Applications/util/passwd.c @@ -0,0 +1,140 @@ +/* passwd.c + * description: change user password + * author: Shane Kerr + * copyright: 1998 by Shane Kerr , under terms of GPL + */ + +#include +#include +#include +#include +#include +#include + +/* maximum allowed errors */ +#define MAX_FAILURE 5 + +/* valid characters for a salt value */ +static char salt_char[] = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; + +char nbuf1[128], nbuf2[128]; + +int time_zone = 0; + +int main(int argc, char *argv[]) +{ + char *s, *pbuf, *tmp_fname, *pwf = "/etc/passwd"; + char salt[3]; + int n, failure_cnt, uid, gid; + struct passwd *pwd; + FILE * passwd_fp; + time_t now; + long lnow; + + umask(022); + + switch (argc) { + case 1: + if ((pwd = getpwuid(getuid())) == NULL) { + fprintf(stderr, "%s: error reading password file\n", argv[0]); + return 1; + } + break; + + case 2: + if ((pwd = getpwnam(argv[1])) == NULL) { + fprintf(stderr, "%s: unknown user %s\n", argv[0], argv[1]); + return 1; + } + if ((getuid() != 0) && (getuid() != pwd->pw_uid)) { + fprintf(stderr, "You may not change the password for %s.\n", + argv[1]); + return 1; + } + break; + + default: + fprintf(stderr, "usage: %s [name]\n", argv[0]); + return 1; + } + + printf("Changing password for %s\n", pwd->pw_name); + if ((getuid() != 0) && (pwd->pw_passwd[0] != 0)) { + pbuf = getpass("Old password: "); + salt[0] = pwd->pw_passwd[0]; + salt[1] = pwd->pw_passwd[1]; + salt[2] = 0; + if (strcmp(crypt(pbuf, salt), pwd->pw_passwd)) { + fprintf(stderr, "Incorrect password for %s\n", pwd->pw_name); + return 1; + } + memset(pbuf, 0, strlen(pbuf)); + } + failure_cnt = 0; + for (;;) { + pbuf = getpass("New password: "); + strcpy(nbuf1, pbuf); + pbuf = getpass("Re-enter new password: "); + strcpy(nbuf2, pbuf); + if (strcmp(nbuf1, nbuf2) == 0) { + /* need to create a tmp file for the new password */ + if ((tmp_fname = tmpnam(NULL)) == NULL) { + perror("Error getting temporary file name"); + return 1; + } + if ((passwd_fp = fopen(tmp_fname, "w")) == NULL) { + perror(tmp_fname); + return 1; + } + + /* save off our UID */ + uid = pwd->pw_uid; + gid = pwd->pw_gid; + time(&now); + salt[0] = salt_char[(now) & 0x3F]; + salt[1] = salt_char[(now >> 6) & 0x3F]; + salt[2] = 0; + s = crypt(nbuf1, salt); + + /* save entries to the new file */ + setpwent(); + for (n = 0; (pwd = getpwent()) != NULL; ++n) { + if (pwd->pw_uid == uid && pwd->pw_gid == gid) + pwd->pw_passwd = s; + if (putpwent(pwd, passwd_fp) == -1) { + perror("Error writing password file"); + return 1; + } + } + endpwent(); + + /* update the file and move it into position */ + fclose(passwd_fp); + if (n < 1) { + fprintf(stderr, "Can't rewrite %s\n", pwf); + } + strcpy(nbuf2, pwf); + strcat(nbuf2, "~"); + unlink(nbuf2); + if (rename(pwf, nbuf2) < 0) { + perror("Error renaming old password file"); + return 1; + } + if (rename(tmp_fname, pwf) < 0) { + perror("Error installing new password file"); + return 1; + } + + /* celebrate our success */ + printf("Password changed.\n"); + return 0; + } + if (++failure_cnt >= MAX_FAILURE) { + fprintf(stderr, "The password for %s is unchanged.\n", + pwd->pw_name); + return 1; + } + fprintf(stderr, "They don't match; try again.\n"); + } +} diff --git a/Applications/util/patchcpm.c b/Applications/util/patchcpm.c new file mode 100644 index 00000000..fe3b4080 --- /dev/null +++ b/Applications/util/patchcpm.c @@ -0,0 +1,93 @@ +/*************************************************************** + * Utility to patch CP/M executable files as required by UZI's * + * CP/M emulator. Copyright (C) 2000, 2001, Hector Peraza. * + ***************************************************************/ + +#include +#include +#include + +off_t tell(int fd) +{ + return lseek(fd, 0L, 0); +} + +int main(int argc, char *argv[]) +{ + int fd; + long fsize; + unsigned char b1, b2, b3, bfr[14]; + + + if (argc != 2) { + fprintf(stderr, "usage: %s filename\n", argv[0]); + return 1; + } + + fd = open(argv[1], O_RDWR); + if (fd < 0) { + fprintf(stderr, "%s: can't open file %s\n", argv[0], argv[1]); + return 1; + } + + if (read(fd, bfr, 3) != 3) { + fprintf(stderr, "%s: read error from %s\n", argv[0], argv[1]); + return 1; + } + + b1 = bfr[0]; + b2 = bfr[1]; + b3 = bfr[2]; + + if (b1 == 0xc3) { /* jp already there */ + printf("%s: no patch needed\n", argv[0]); + close(fd); + return 0; + } + + lseek(fd, 0L, SEEK_END); + fsize = tell(fd); + + bfr[0] = 0x21; /* ld hl,100h */ + bfr[1] = 0x00; + bfr[2] = 0x01; + + bfr[3] = 0x36; /* ld (hl),b1 */ + bfr[4] = b1; + bfr[5] = 0x23; /* inc hl */ + + bfr[6] = 0x36; /* ld (hl),b2 */ + bfr[7] = b2; + bfr[8] = 0x23; /* inc hl */ + + bfr[9] = 0x36; /* ld (hl),b3 */ + bfr[10] = b3; + + bfr[11] = 0xc3; /* jp 100h */ + bfr[12] = 0x00; + bfr[13] = 0x01; + + if (write(fd, bfr, 14) != 14) { + fprintf(stderr, "%s: file write error\n", argv[0]); + return -1; + } + + lseek(fd, 0L, SEEK_SET); + if (tell(fd) != 0L) { + fprintf(stderr, "%s: seek error\n", argv[0]); + return -1; + } + + bfr[0] = 0xc3; /* jp instruction to our patching code */ + bfr[1] = (fsize + 0x100) & 0xff; + bfr[2] = ((fsize + 0x100) >> 8) & 0xff; + + if (write(fd, bfr, 3) != 3) { + fprintf(stderr, "%s: file write error\n", argv[0]); + return -1; + } + + close(fd); + + return 0; +} diff --git a/Applications/util/printenv.c b/Applications/util/printenv.c new file mode 100644 index 00000000..ee6e8059 --- /dev/null +++ b/Applications/util/printenv.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1993 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + */ + +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + char **env; + extern char **environ; + int len; + + env = environ; + + if (argc == 1) { + while (*env) + printf("%s\n", *env++); + return 0; + } + + len = strlen(argv[1]); + while (*env) { + if ((strlen(*env) > len) && (env[0][len] == '=') && + (memcmp(argv[1], *env, len) == 0)) { + printf("%s\n", &env[0][len + 1]); + return 0; + } + env++; + } + + return 1; +} diff --git a/Applications/util/prtroot.c b/Applications/util/prtroot.c new file mode 100644 index 00000000..19dce5a5 --- /dev/null +++ b/Applications/util/prtroot.c @@ -0,0 +1,71 @@ +/* printroot - print root device on stdout Author: Bruce Evans */ + +/* This program figures out what the root device is by doing a stat on it, and + * then searching /dev until it finds an entry with the same device number. + * A typical use (probably the only use) is in /etc/rc for initializing + * /etc/mtab, as follows: + * + * /usr/bin/printroot >/etc/mtab + * + * 9 Dec 1989 - clean up for 1.5 - full prototypes (BDE) + * 15 Oct 1989 - avoid ACK cc bugs (BDE): + * - sizeof "foo" is 2 (from wrong type char *) instead of 4 + * - char foo[10] = "bar"; allocates 4 bytes instead of 10 + * 1 Oct 1989 - Minor changes by Andy Tanenbaum + * 5 Oct 1992 - Use readdir (kjb) + * 26 Nov 1994 - Flag -r: print just the root device (kjb) + * 19 May 2001 - Ported to UZI180 + */ + +#include +#include +#include +#include +#include + +#define DEV_PATH "/dev/" +#define MESSAGE " / uzi rw\n" +#define UNKNOWN_DEV "/dev/unknown" +#define ROOT "/" + +int rflag; + +void done(const char *name, int status) +{ + write(1, name, strlen(name)); + if (rflag) { + write(1, "\n", 1); + exit(status); + } + write(1, MESSAGE, sizeof(MESSAGE)); + + exit(status); +} + +int main(int argc, const char *argv[]) +{ + DIR *dp; + struct dirent *entry; + struct stat filestat, rootstat; + static char namebuf[sizeof(DEV_PATH) + MAXNAMLEN + 1]; + + rflag = (argc > 1 && strcmp(argv[1], "-r") == 0); + + if (stat(ROOT, &rootstat) == 0 + && (dp = opendir(DEV_PATH)) != (DIR *) NULL) { + while ((entry = readdir(dp)) != (struct dirent *) NULL) { + strcpy(namebuf, DEV_PATH); + strcat(namebuf, entry->d_name); + if (stat(namebuf, &filestat) != 0) + continue; + if (!S_ISBLK(filestat.st_mode)) + continue; + if (filestat.st_rdev != rootstat.st_dev) + continue; + done(namebuf, 0); + } + } + done(UNKNOWN_DEV, 1); + return (0); /* not reached */ +} + diff --git a/Applications/util/ps.c b/Applications/util/ps.c new file mode 100644 index 00000000..1b12ea2d --- /dev/null +++ b/Applications/util/ps.c @@ -0,0 +1,131 @@ +#include +#include +#include + +#define F_a 0x01 /* all users flag */ +#define F_h 0x02 /* no header flag */ +#define F_r 0x04 /* running only flag */ +#define F_n 0x08 /* numeric output flag */ + +int flags; + +char *mapstat(char s) +{ + switch (s) { + case P_ZOMBIE: + case P_ZOMBIE2: return "Defunct"; + case P_FORKING: return "Forking"; + case P_RUNNING: return "Running"; + case P_READY: return "Ready"; + case P_SLEEP: + case P_XSLEEP: return "Sleeping"; + case P_PAUSE: return "Paused"; + case P_WAIT: return "Waiting"; + } + return "?"; +} + +int do_ps(void) +{ + ptptr pp; + int i, j, uid, pfd, ptsize; + int open(), ioctl(), read(), close(), getuid(); + struct passwd *pwd; + struct p_tab ptab[PTABSIZE]; + char name[10], uname[20]; + + uid = getuid(); + + if ((pfd = open("/dev/proc", O_RDONLY)) < 0) { + perror("ps"); + return 1; + } + + if (ioctl(pfd, 1, (char *) &ptsize) != 0) { + perror("ioctl"); + close(pfd); + return 1; + } + + if (ptsize > PTABSIZE) ptsize = PTABSIZE; + + for (i = 0; i < ptsize; ++i) { + if (read(pfd, &ptab[i], sizeof(struct p_tab)) != + sizeof(struct p_tab)) { + fprintf(stderr, "ps: error reading from /dev/proc\n"); + close(pfd); + return 1; + } + } + close(pfd); + + if (!(flags & F_h)) { + if (flags & F_n) + printf(" PID\tUID\tSTAT\tWCHAN\tALARM\tCOMMAND\n"); + else + printf("USER\t PID\tSTAT\tWCHAN\tALARM\tCOMMAND\n"); + } + + for (pp = ptab, i = 0; i < ptsize; ++i, ++pp) { + if (pp->p_status == 0) + continue; + + if ((flags & F_r) && + (pp->p_status != P_RUNNING && pp->p_status != P_READY)) + continue; + + if (!(flags & F_a) && (pp->p_uid != uid)) + continue; + + strncpy(name, pp->p_name, 8); + name[8] = '\0'; + + for (j = 0; j < 8; ++j) { + if (name[j] != 0) + if (name[j] < ' ') name[j] = '?'; + } + + if (flags & F_n) { + printf("%5d\t%-3d\t%s\t%04x\t%-5d\t%s\n", + pp->p_pid, pp->p_uid, + mapstat(pp->p_status), pp->p_wait, pp->p_alarm, + name); + } else { + pwd = getpwuid(pp->p_uid); + if (pwd) + strcpy(uname, pwd->pw_name); + else + sprintf(uname, "%d", pp->p_uid); + printf("%s\t%5d\t%s\t%04x\t%-5d\t%s\n", + uname, pp->p_pid, + mapstat(pp->p_status), pp->p_wait, pp->p_alarm, + name); + } + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int i; + + flags = 0; + for (i = 1; i < argc; ++i) { + char *p = argv[i]; + + if (*p == '-') ++p; + while (*p) + switch (*p++) { + case 'a': flags |= F_a; break; + case 'h': flags |= F_h; break; + case 'r': flags |= F_r; break; + case 'n': flags |= F_n; break; + default: + fprintf(stderr, "usage: ps [-][ahrn]\n"); + return 1; + } + } + + return do_ps(); +} diff --git a/Applications/util/pwd.c b/Applications/util/pwd.c new file mode 100644 index 00000000..5375d23b --- /dev/null +++ b/Applications/util/pwd.c @@ -0,0 +1,14 @@ +#include +#include + +int main(int argc, const char *argv[]) +{ + char buf[512]; + + if (getcwd(buf, 512) == NULL) { + fprintf(stderr, "pwd: cannot get current directory\n"); + return -1; + } + printf("%s\n", buf); + return 0; +} diff --git a/Applications/util/pwd.h b/Applications/util/pwd.h new file mode 100644 index 00000000..ee0418a3 --- /dev/null +++ b/Applications/util/pwd.h @@ -0,0 +1,40 @@ +#ifndef __PWD_H +#define __PWD_H + +#include + +#ifndef _UID_T +#define _UID_T +typedef int uid_t; +#endif + +#ifndef _GID_T +#define _GID_T +typedef int gid_t; +#endif + +/* The passwd structure */ +struct passwd +{ + char *pw_name; /* Username */ + char *pw_passwd; /* Password */ + uid_t pw_uid; /* User ID */ + gid_t pw_gid; /* Group ID */ + char *pw_gecos; /* Real name */ + char *pw_dir; /* Home directory */ + char *pw_shell; /* Shell program */ +}; + + +extern int setpwent(void); +extern void endpwent(void); +extern struct passwd *getpwent(void); + +extern int putpwent(struct passwd *, FILE *); +extern int getpw(uid_t uid, char *buf); + +extern struct passwd *getpwuid(uid_t); +extern struct passwd *getpwnam(char *); + + +#endif /* pwd.h */ diff --git a/Applications/util/rm.c b/Applications/util/rm.c new file mode 100644 index 00000000..6fc45566 --- /dev/null +++ b/Applications/util/rm.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +char *basename(char *name) +{ + char *base = rindex(name, '/'); + return base ? base + 1 : name; +} + + +int main(int argc, const char *argv[]) +{ + int i /*, recurse = 0, interact =0 */ ; + struct stat sbuf; + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + if (!lstat(argv[i], &sbuf)) { + if (unlink(argv[i])) { + fprintf(stderr, "rm: could not remove %s\n", argv[i]); + } + } + } + } + return 0; +} diff --git a/Applications/util/rmdir.c b/Applications/util/rmdir.c new file mode 100644 index 00000000..c0c702fe --- /dev/null +++ b/Applications/util/rmdir.c @@ -0,0 +1,47 @@ +#include +#include +#include + +unsigned short newmode; + +int remove_dir(char *name, int f) +{ + int er, era = 2; + char *line; + char *p = name + strlen(name) - 1; + while(p >= name && *p == '/') + *p-- = '\0'; + + while (((er = rmdir(name)) == 0) + && ((line = rindex(name, '/')) != NULL) && f) { + while ((line > name) && (*line == '/')) --line; + line[1] = 0; + era = 0; + } + return (er && era); +} + + +int main(int argc, char **argv) +{ + int i, parent = 0, er = 0; + + if ((argv[1][0] == '-') && (argv[1][1] == 'p')) + parent = 1; + + newmode = 0666 & ~umask(0); + + for (i = parent + 1; i < argc; i++) { + if (argv[i][0] != '-') { + if (remove_dir(argv[i], parent)) { + fprintf(stderr, "rmdir: cannot remove directory %s\n", argv[i]); + er = 1; + } + } else { + fprintf(stderr, "rmdir: usage error\n"); + exit(1); + } + } + return er; +} + diff --git a/Applications/util/sleep.c b/Applications/util/sleep.c new file mode 100644 index 00000000..802216f6 --- /dev/null +++ b/Applications/util/sleep.c @@ -0,0 +1,76 @@ +/* sleep - delay for a specified amount of time. + Copyright (C) 84, 91, 92, 93, 1994 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include + +/* The name by which this program was run. */ +char *program_name; + +static void usage(void) +{ + printf("Usage: %s number[h|m|s]\n", program_name); + exit(1); +} + +unsigned int argdecode(char *s) +{ + unsigned int value; + register char *p = s; + register char c; + + value = 0; + while ((c = *p++) >= '0' && c <= '9') + value = value * 10L + (long) (c - '0'); + + switch (c) { + case 's': + break; + case 'm': + value *= 60L; + break; + case 'h': + value *= 60L * 60L; + break; + default: + p--; + } + + if (*p) { + fprintf(stderr, "%s: invalid time interval `%s'\n", program_name, s); + exit(1); + } + return value; +} + +void main(int argc, char *argv[]) +{ + int i; + unsigned int seconds = 0; + + program_name = argv[0]; + + if (argc == 1) { + usage(); + } + for (i = 1; i < argc; i++) + seconds += argdecode(argv[i]); + + sleep(seconds); + exit(0); +} + diff --git a/Applications/util/ssh.c b/Applications/util/ssh.c new file mode 100644 index 00000000..6399ac7f --- /dev/null +++ b/Applications/util/ssh.c @@ -0,0 +1,166 @@ +/*************************************************** + UZI (Unix Z80 Implementation) Utilities: ssh.c + Simple Shell. Copyright (C) 1998, Harold F. Bower + + 15 Mar 1998 - Added Path searching from Minix. HFB + 26 Sep 1999 - Added kill command HP + 29 Sep 1999 - Added pwd and sync commands HP + 04 Oct 1999 - Added umask command HP + 27 MAy 2001 - Added simple support for env vars HP +****************************************************/ + +#include +#include +#include +#include + +extern char **environ; /* Location of Envp from executable Header */ + +#define MAX_ARGS 10 + +char buf[128]; +char eline[45]; /* Line for Search command */ + +char cmd[50], arg[MAX_ARGS][50]; + + +main(int argc, char *argval[]) +{ + char *path, *tp, *sp; /* Pointers for Path Searching */ + int login_sh, pid, sig, stat, count, asis, i; + char cprompt; + char *home; + char *argv[MAX_ARGS+1]; + + login_sh = 0; + if (argval[0][0] == '-') login_sh = 1; + + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + + if (login_sh) { + home = getenv("HOME"); + if (!home) putenv("HOME=/"); + chdir("/"); + } + + cprompt = (getuid() == 0) ? '#' : '$'; + + for (;;) { + cmd[0] = (char) 0; + for (i = 0; i < MAX_ARGS; i++) arg[i][0] = (char) 0; + do { + printf("ssh%c ", cprompt); + fgets(buf, 127, stdin); + if (feof(stdin)) return 0; /* user typed ^D ? */ + buf[strlen(buf) - 1] = '\0'; /* Strip newline from fgets */ + } + while (buf[0] == (char) 0); + count = sscanf(buf, "%s %s %s %s %s %s %s %s %s %s %s", + cmd, + arg[0], arg[1], arg[2], arg[3], arg[4], + arg[5], arg[6], arg[7], arg[8], arg[9]); + + /* Check for User-Requested Exit back to Login Prompt */ + if (strcmp(cmd, "exit") == 0) + return (0); /* Quit if requested */ + + /* Check for User request to change Current Working Directory */ + else if (strcmp(cmd, "cd") == 0) { + stat = chdir(*arg[0] ? arg[0] : getenv("HOME")); + if (stat) + perror("cd"); + } + + else if (strcmp(cmd, "pwd") == 0) { + if (getcwd(buf, 128)) + printf("%s\n", buf); + else + printf("pwd: cannot get current directory\n"); + } + + else if (strcmp(cmd, "sync") == 0) { + sync(); + } + + else if (strcmp(cmd, "umask") == 0) { + if (arg[0][0] == (char) 0) { + i = umask(0); + umask(i); + printf("%03o\n", i); + } else { + i = 0; + tp = arg[0]; + while (*tp >= '0' && *tp <= '7') + i = (i << 3) + *tp++ - '0'; + if (*tp || (i & ~0777)) + printf("umask: bad mask value\n"); + else + umask(i); + } + } + + /* Check for User request to kill a process */ + else if (strcmp(cmd, "kill") == 0) { + if (arg[0][0] == '-') { + sig = atoi(&arg[0][1]); + pid = atoi(arg[1]); + } else { + sig = SIGINT; + pid = atoi(arg[0]); + } + if (pid == 0 || pid == 1) { + printf("kill: can't kill process %d\n", pid); + } else { + stat = kill(pid, sig); + if (stat) + perror("kill"); + } + } + + /* Check for environmen variable assignment */ + else if ((tp = strchr(cmd, '=')) != NULL) { + if (*(tp+1) == '\0') *tp = '\0'; + putenv(cmd); + } + + /* No built-in Command, Try to find Executable Command File */ + else { + argv[0] = cmd; /* Build Argv Pointer Array */ + for (i = 0; i < MAX_ARGS; ++i) + argv[i+1] = *arg[i] ? arg[i] : (char *) NULL; + + if ((pid = fork()) == -1) { /* Try to spawn new Process */ + printf("ssh: can't fork\n"); + } else { + if (pid == 0) { /* Child is in context */ + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + /* Path search adapted from Univ of Washington's Minix */ + path = getenv("PATH"); /* Get base of path string, or NULL */ + eline[0] = '\0'; + sp = strchr(cmd, '/') ? "" : path; + asis = *sp == '\0'; + while (asis || *sp != '\0') { + asis = 0; + tp = eline; + for (; *sp != '\0'; tp++) + if ((*tp = *sp++) == ':') { + asis = *sp == '\0'; + break; + } + if (tp != eline) + *tp++ = '/'; + for (i = 0; (*tp++ = cmd[i++]) != '\0'; ) + ; + execve(eline, argv, environ); + } + printf("ssh: %s?\n", buf); /* Say we can't exec */ + exit(1); + } /* Parent is in context */ + wait(0); /* Parent waits for completion */ + kill(pid, SIGKILL); /* then kills child process */ + } + } + } +} diff --git a/Applications/util/su.c b/Applications/util/su.c new file mode 100644 index 00000000..c8583f32 --- /dev/null +++ b/Applications/util/su.c @@ -0,0 +1,97 @@ +/* su - become super-user Author: Patrick van Kleef */ +/* Ported to UZI by Hector Peraza */ + +#include +#include +#include +#include + +/* True if the invoker need not give a password. */ +#define privileged() (getgid() == 0) + +static char *shell1 = "/bin/sh"; +static char *shell2 = "/usr/bin/sh"; +static char *shell3 = "/bin/ssh"; + +static char USER[20], LOGNAME[25], HOME[100], SHELL[100]; + +int main(int argc, char *argv[]) +{ + register char *name, *password; + register struct passwd *pwd; + int login_shell = 0; + char *shell, arg0[20]; + + if (argc > 1 && strcmp(argv[1], "-") == 0) { + login_shell = 1; /* Read .profile */ + argv[1] = argv[0]; + argv++; + argc--; + } + + if (argc > 1) { + if (argv[1][0] == '-') { + fprintf(stderr, "Usage: su [-] [user [shell-arguments ...]]\n"); + exit(1); + } + name = argv[1]; + argv[1] = argv[0]; + argv++; + } else { + name = "root"; + } + + if ((pwd = getpwnam(name)) == 0) { + fprintf(stderr, "%s: user %s does not exist\n", argv[0], name); + exit(1); + } + + if (!privileged() && + strcmp(pwd->pw_passwd, crypt("", pwd->pw_passwd)) != 0) { + password = getpass("Password: "); + if (strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd))) { + fprintf(stderr, "%s: incorrect password\n", argv[0]); + exit(2); + } + } + + if (login_shell) { + if ((shell = pwd->pw_shell)[0] == 0) shell = shell1; + } else { + if ((shell = getenv("SHELL")) == NULL) shell = shell1; + } + + if (access(shell, 0) < 0) shell = shell2; + if (access(shell, 0) < 0) shell = shell3; + + if ((argv[0] = strrchr(shell, '/')) == NULL) + argv[0] = shell; + else + argv[0]++; + + if (login_shell) { + arg0[0] = '-'; + strncpy(arg0 + 1, argv[0], sizeof(arg0) - 2); + arg0[sizeof(arg0) - 1] = 0; + argv[0] = arg0; + strcpy(USER, "USER="); + strcpy(USER + 5, name); + putenv(USER); + strcpy(LOGNAME, "LOGNAME="); + strcpy(LOGNAME + 8, name); + putenv(LOGNAME); + strcpy(SHELL, "SHELL="); + strcpy(SHELL + 6, shell); + putenv(SHELL); + strcpy(HOME, "HOME="); + strcpy(HOME + 5, pwd->pw_dir); + putenv(HOME); + chdir(pwd->pw_dir); + } + setgid(pwd->pw_gid); + setuid(pwd->pw_uid); + execve(shell, argv, environ); + + fprintf(stderr, "%s: no shell\n", argv[0]); + return (3); +} diff --git a/Applications/util/sync.c b/Applications/util/sync.c new file mode 100644 index 00000000..863d6899 --- /dev/null +++ b/Applications/util/sync.c @@ -0,0 +1,6 @@ +#include + +main(int argc, const char *argv[]) +{ + return sync(); +} diff --git a/Applications/util/termcap.c b/Applications/util/termcap.c new file mode 100644 index 00000000..99c54892 --- /dev/null +++ b/Applications/util/termcap.c @@ -0,0 +1,504 @@ +/* termcap - print termcap settings Author: Terrence Holm */ + +#include +#include +#include + +#define TC_BUFFER 1024 /* Size of termcap(3) buffer */ + +/****************************************************************/ +/* */ +/* termcap [ type ] */ +/* */ +/* Prints out all of the termcap capabilities as described */ +/* in termcap(4). If "type" is not supplied then $TERM is */ +/* used. */ +/* */ +/****************************************************************/ + +int main(int argc, char **argv); +void Print(char *comment, char *name); +void Error(char *message, char *arg); + +int main(argc, argv) +int argc; +char *argv[]; +{ + char *term; + char buffer[TC_BUFFER]; + + /* Check for an argument */ + + if (argc > 2) + Error("Usage: %s [type]\n", argv[0]); + + if (argc == 2) + term = argv[1]; + else + term = getenv("TERM"); + + if (term == NULL) + Error("termcap: $TERM is not defined\n", ""); + + + /* Read in the termcap entry */ + + if (tgetent(buffer, term) != 1) + Error("termcap: No termcap entry for %s\n", term); + + + /* Print out the entry's contents */ + + printf("TERM = %s\n\n", term); + + if (tgetflag("am") == 1) + printf("End of line wraps to next line (am)\n"); + + if (tgetflag("bs") == 1) + printf("Ctrl/H performs a backspace (bs)\n"); + + printf("Number of columns (co) = %d\n", tgetnum("co")); + printf("Number of lines (li) = %d\n", tgetnum("li")); + + Print("Clear to end of line", "ce"); + Print("Clear to end of screen", "cd"); + Print("Clear the whole screen", "cl"); + + Print("Start \"stand out\" mode", "so"); + Print("End \"stand out\" mode", "se"); + Print("Start underscore mode", "us"); + Print("End underscore mode", "ue"); + Print("Start blinking mode", "mb"); + Print("Start bold mode", "md"); + Print("Start reverse mode", "mr"); + Print("Return to normal mode", "me"); + + Print("Scroll backwards", "sr"); + Print("Cursor motion", "cm"); + + Print("Up one line", "up"); + Print("Down one line", "do"); + Print("Left one space", "le"); + Print("Right one space", "nd"); + Print("Move to top left corner", "ho"); + + Print("Generated by \"UP\"", "ku"); + Print("Generated by \"DOWN\"", "kd"); + Print("Generated by \"LEFT\"", "kl"); + Print("Generated by \"RIGHT\"", "kr"); + Print("Generated by \"HOME\"", "kh"); + Print("Generated by \"END\"", "k0"); + Print("Generated by \"PGUP\"", "k1"); + Print("Generated by \"PGDN\"", "k2"); + Print("Generated by numeric \"+\"", "k3"); + Print("Generated by numeric \"-\"", "k4"); + Print("Generated by numeric \"5\"", "k5"); + + return (0); +} + + +/****************************************************************/ +/* */ +/* Print(comment, name) */ +/* */ +/* If a termcap entry exists for "name", then */ +/* print out "comment" and the entry. Control */ +/* characters are printed as ^x. */ +/* */ +/****************************************************************/ + +void Print(comment, name) +char *comment; +char *name; +{ + char entry[50]; + char *p = entry; + + if (tgetstr(name, &p) == NULL) + return; + + printf("%-32s (%s) = ", comment, name); + + for (p = entry; *p != '\0'; ++p) + if (*p < ' ') + printf("^%c", *p + '@'); + else if (*p == '\177') + printf("^?"); + else + putchar(*p); + + putchar('\n'); +} + + +/****************************************************************/ +/* */ +/* Error(message, arg) */ +/* */ +/* Printf the "message" and abort. */ +/* */ +/****************************************************************/ + +void Error(message, arg) +char *message; +char *arg; +{ + fprintf(stderr, message, arg); + exit(1); +} + +/****************************/ + +/*#include */ +/* + * termcap.c V1.1 20/7/87 agc Joypace Ltd + * + * Copyright Joypace Ltd, London, UK, 1987. All rights reserved. + * This file may be freely distributed provided that this notice + * remains attached. + * + * A public domain implementation of the termcap(3) routines. + * + * + * + * Klamer Schutte V1.2 Nov. 1988 + * + * - Can match multiple terminal names [tgetent] + * - Removal of **area assignments [tgetstr] + * + * Terrence W. Holm V1.3 May, Sep, Oct. 1988 + * + * - Correct when TERM != name and TERMCAP is defined [tgetent] + * - Correct the comparison for the terminal name [tgetent] + * - Correct the value of ^x escapes [tgetstr] + * - Added %r to reverse row/column [tgoto] + * - Fixed end of definition test [tgetnum/flag/str] + * + * Terrence W. Holm V1.4 Jan. 1989 + * + * - Incorporated Klamer's V1.2 fixes into V1.3 + * - Added %d, (old %d is now %2) [tgoto] + * - Allow '#' comments in definition file [tgetent] + */ + +#include +#include +/*#include +#include */ +#include + +char *capab = (char *) NULL; /* the capability itself */ + +#if 0 +/* The following are not yet used. */ +extern short ospeed; /* output speed */ +extern char PC; /* padding character */ +extern char *BC; /* back cursor movement */ +extern char *UP; /* up cursor movement */ +#endif + + +/* + * tgetent - get the termcap entry for terminal name, and put it + * in bp (which must be an array of 1024 chars). Returns 1 if + * termcap entry found, 0 if not found, and -1 if file not found. + */ + +int tgetent(bp, name) +char *bp; +char *name; +{ + FILE *fp; + char *file; + char *term; + short len = strlen(name); + + capab = bp; + + /* If TERMCAP begins with a '/' then use TERMCAP as the path */ + /* Name of the termcap definitions file. If TERMCAP is a */ + /* Definition and TERM equals "name" then use TERMCAP as the */ + /* Definition. Otherwise use "/etc/termcap" as the path name. */ + + if ((file = getenv("TERMCAP")) == (char *) NULL) + file = "/etc/termcap"; + else if (*file != '/') + if ((term = getenv("TERM")) != (char *) NULL + && strcmp(term, name) == 0) { + *bp = '\0'; + strncat(bp, file, 1023); + return (1); + } else + file = "/etc/termcap"; + + if ((fp = fopen(file, "r")) == (FILE *) NULL) { + capab = (char *) NULL; /* no valid termcap */ + return (-1); + } + for (;;) { + /* Read in each definition */ + int def_len = 0; + char *cp = bp; + + do { + if (fgets(&bp[def_len], (unsigned int) (1024 - def_len), fp) == + (char *) NULL) { + fclose(fp); + capab = (char *) NULL; /* no valid termcap */ + return (0); + } + def_len = strlen(bp) - 2; + } while (bp[def_len] == '\\'); + + while (isspace(*cp)) + cp++; + + /* Comment lines start with a '#' */ + if (*cp == '#') + continue; + + /* See if any of the terminal names in this definition */ + /* Match "name". */ + + do { + if (strncmp(name, cp, len) == 0 && + (cp[len] == '|' || cp[len] == ':')) { + fclose(fp); + return (1); + } + while ((*cp) && (*cp != '|') && (*cp != ':')) + cp++; + } while (*cp++ == '|'); + } +} + + +/* + * tgetnum - get the numeric terminal capability corresponding + * to id. Returns the value, -1 if invalid. + */ + +int tgetnum(id) +char *id; +{ + register char *cp = capab; + + if (cp == (char *) NULL || id == (char *) NULL) + return (-1); + + for (;;) { + while (*cp++ != ':') + if (cp[-1] == '\0') + return (-1); + + while (isspace(*cp)) + cp++; + + if (strncmp(cp, id, 2) == 0 && cp[2] == '#') + return (atoi(cp + 3)); + } +} + + +/* + * tgetflag - get the boolean flag corresponding to id. Returns -1 + * if invalid, 0 if the flag is not in termcap entry, or 1 if it is + * present. + */ + +int tgetflag(id) +char *id; +{ + register char *cp = capab; + + if (cp == (char *) NULL || id == (char *) NULL) + return (-1); + + for (;;) { + while (*cp++ != ':') + if (cp[-1] == '\0') + return (0); + + while (isspace(*cp)) + cp++; + + if (strncmp(cp, id, 2) == 0) + return (1); + } +} + + +/* + * tgetstr - get the string capability corresponding to id and place + * it in area (advancing area at same time). Expand escape sequences + * etc. Returns the string, or NULL if it can't do it. + */ + +char *tgetstr(id, area) +char *id; +char **area; +{ + register char *cp = capab; + register char *wsp = *area; /* workspace pointer */ + + if (cp == (char *) NULL || id == (char *) NULL) + return ((char *) NULL); + + for (;;) { + while (*cp++ != ':') + if (cp[-1] == '\0') + return ((char *) NULL); + + while (isspace(*cp)) + cp++; + + if (strncmp(cp, id, 2) == 0 && cp[2] == '=') { + for (cp += 3; *cp && *cp != ':'; wsp++, cp++) + switch (*cp) { + case '^': + *wsp = *++cp - '@'; + break; + + case '\\': + switch (*++cp) { + case 'E': + *wsp = '\033'; + break; + case 'n': + *wsp = '\n'; + break; + case 'r': + *wsp = '\r'; + break; + case 't': + *wsp = '\t'; + break; + case 'b': + *wsp = '\b'; + break; + case 'f': + *wsp = '\f'; + break; + case '0': + case '1': + case '2': + case '3': + { + int i; + int t = 0; + for (i = 0; i < 3 && isdigit(*cp); ++i, ++cp) + t = t * 8 + *cp - '0'; + *wsp = t; + cp--; + break; + } + default: + *wsp = *cp; + } + break; + + default: + *wsp = *cp; + } + + *wsp++ = '\0'; + + { + char *ret = *area; + *area = wsp; + return (ret); + } + } + } /* end for(;;) */ +} + + +/* + * tgoto - given the cursor motion string cm, make up the string + * for the cursor to go to (destcol, destline), and return the string. + * Returns "OOPS" if something's gone wrong, or the string otherwise. + */ + +char *tgoto(cm, destcol, destline) +char *cm; +int destcol; +int destline; +{ + static char ret[24]; + char *rp = ret; + int incr = 0; + int argno = 0; + int numval; + + for (; *cm; cm++) { + if (*cm == '%') { + switch (*++cm) { + case 'i': + incr = 1; + break; + + case 'r': + argno = 1; + break; + + case '+': + numval = (argno == 0 ? destline : destcol); + *rp++ = numval + incr + *++cm; + argno = 1 - argno; + break; + + case '2': + numval = (argno == 0 ? destline : destcol); + numval = (numval + incr) % 100; + *rp++ = '0' + (numval / 10); + *rp++ = '0' + (numval % 10); + argno = 1 - argno; + break; + + case 'd': + numval = (argno == 0 ? destline : destcol); + numval = (numval + incr) % 1000; + if (numval > 99) + *rp++ = '0' + (numval / 100); + if (numval > 9) + *rp++ = '0' + (numval / 10) % 10; + *rp++ = '0' + (numval % 10); + argno = 1 - argno; + break; + + case '%': + *rp++ = '%'; + break; + + default: + return ("OOPS"); + } + + } else + *rp++ = *cm; + } + + *rp = '\0'; + return (ret); +} + + +/* + * tputs - put the string cp out onto the terminal, using the function + * outc. This should do padding for the terminal, but I can't find a + * terminal that needs padding at the moment... + */ + +int tputs(cp, affcnt, outc) +register char *cp; +int affcnt; +void (*outc)(int ch); +{ + if (cp == (char *) NULL) + return (1); + /* Do any padding interpretation - left null for MINIX just now */ + while (*cp) + (*outc) (*cp++); + return (1); +} diff --git a/Applications/util/termcap.h b/Applications/util/termcap.h new file mode 100644 index 00000000..1dc96c00 --- /dev/null +++ b/Applications/util/termcap.h @@ -0,0 +1,11 @@ +#ifndef _TERMCAP_H +#define _TERMCAP_H + +int tgetent(char *_bp, char *_name); +int tgetflag(char *_id); +int tgetnum(char *_id); +char *tgetstr(char *_id, char **_area); +char *tgoto(char *_cm, int _destcol, int _destline); +int tputs(char *_cp, int _affcnt, int (*_outc)(int)); + +#endif /* _TERMCAP_H */ diff --git a/Applications/util/tget.c b/Applications/util/tget.c new file mode 100644 index 00000000..ef3f5ab2 --- /dev/null +++ b/Applications/util/tget.c @@ -0,0 +1,99 @@ +/* tget 1.0 - get termcap values Author: Kees J. Bot + * 6 Mar 1994 + */ + +#define nil 0 + +#include +#include +#include +#include "termcap.h" + +int fputchar(int c) +{ + putchar(c); + return 0; +} + +void usage(void) +{ + fprintf(stderr, + "Usage: tget [-flag id] [-num id] [-str id] [-goto col line] [[-echo] string]\n"); + exit(-1); +} + +char termbuf[1024]; +char string[256], *pstr; + +void main(int argc, char **argv) +{ + char *term; + int i, excode = 0; + + if ((term = getenv("TERM")) == nil) { + fprintf(stderr, "tget: $TERM is not set\n"); + exit(-1); + } + + if (tgetent(termbuf, term) != 1) { + fprintf(stderr, "tget: no termcap entry for '%s'\n", term); + exit(-1); + } + + for (i = 1; i < argc; i++) { + char *option = argv[i]; + char *id; + + if (option[0] != '-') { + fputs(option, stdout); + continue; + } + + if (++i == argc) + usage(); + id = argv[i]; + + if (strcmp(option, "-flag") == 0) { + excode = tgetflag(id) ? 0 : 1; + } else if (strcmp(option, "-num") == 0) { + int num; + + if ((num = tgetnum(id)) == -1) { + excode = 1; + } else { + excode = 0; + printf("%d", num); + } + } else if (strcmp(option, "-str") == 0) { + char *str; + + if ((str = tgetstr(id, (pstr = string, &pstr))) == nil) { + excode = 1; + } else { + excode = 0; + tputs(str, 0, fputchar); + } + } else if (strcmp(option, "-goto") == 0) { + char *cm; + int col, line; + + col = atoi(id); + if (++i == argc) + usage(); + line = atoi(argv[i]); + + if ((cm = tgetstr("cm", (pstr = string, &pstr))) == nil) { + excode = 1; + } else { + excode = 0; + tputs(tgoto(cm, col, line), 0, fputchar); + } + } else if (strcmp(option, "-echo") == 0) { + fputs(id, stdout); + } else { + usage(); + } + } + + exit(excode); +} diff --git a/Applications/util/touch.c b/Applications/util/touch.c new file mode 100644 index 00000000..9aa8c5e3 --- /dev/null +++ b/Applications/util/touch.c @@ -0,0 +1,30 @@ +#include +#include +#include + +static time_t settime; + +int main(int argc, const char *argv[]) +{ + int er = 0, i, ncreate = 0; + struct stat sbuf; + struct utimbuf tbuf; + + if ((argv[1][0] == '-') && (argv[1][1] == 'c')) + ncreate = 1; + + for (i = ncreate + 1; i < argc; i++) { + if (argv[i][0] != '-') { + if (stat(argv[i], &sbuf)) { + if (!ncreate) + er = close(creat(argv[i], 0666)); + } else { + settime = time(NULL); + tbuf.actime = settime; + tbuf.modtime = settime; + er |= utime(argv[i], &tbuf); + } + } + } + return er; +} diff --git a/Applications/util/tr.c b/Applications/util/tr.c new file mode 100644 index 00000000..3f23a3fe --- /dev/null +++ b/Applications/util/tr.c @@ -0,0 +1,172 @@ +/* tr - translate characters Author: Michiel Huisjes */ + +/* Usage: tr [-cds] [string1 [string2]] + * c: take complement of string1 + * d: delete input characters coded string1 + * s: squeeze multiple output characters of string2 into one character + */ +#include +#include +#include + +#define BUFFER_SIZE 1024 +#define ASCII 0377 + +typedef char BOOL; +#define TRUE 1 +#define FALSE 0 + +#define NIL_PTR ((char *) 0) + +BOOL com_fl, del_fl, sq_fl; + +unsigned char output[BUFFER_SIZE], input[BUFFER_SIZE]; +unsigned char vector[ASCII + 1]; +BOOL invec[ASCII + 1], outvec[ASCII + 1]; + +short in_index, out_index; + +int main(int argc, char **argv); +void convert(void); +void map(unsigned char *string1, unsigned char *string2); +void expand(char *arg, unsigned char *buffer); +void complement(unsigned char *buffer); + +int main(int argc, char *argv[]) +{ + register unsigned char *ptr; + int index = 1; + short i; + + if (argc > 1 && argv[index][0] == '-') { + for (ptr = (unsigned char *) &argv[index][1]; *ptr; ptr++) { + switch (*ptr) { + case 'c': + com_fl = TRUE; + break; + case 'd': + del_fl = TRUE; + break; + case 's': + sq_fl = TRUE; + break; + default: + write(2, "Usage: tr [-cds] [string1 [string2]].\n", 38); + exit(1); + } + } + index++; + } + + for (i = 0; i <= ASCII; i++) { + vector[i] = i; + invec[i] = outvec[i] = FALSE; + } + + if (argv[index] != NIL_PTR) { + expand(argv[index++], input); + if (com_fl) complement(input); + if (argv[index] != NIL_PTR) expand(argv[index], output); + if (argv[index] != NIL_PTR) map(input, output); + for (ptr = input; *ptr; ptr++) invec[*ptr] = TRUE; + for (ptr = output; *ptr; ptr++) outvec[*ptr] = TRUE; + } + + convert(); + + return (0); +} + +void convert(void) +{ + short read_chars = 0; + short c, coded; + short last = -1; + + for (;;) { + if (in_index == read_chars) { + if ((read_chars = read(0, (char *) input, BUFFER_SIZE)) <= 0) { + if (write(1, (char *) output, out_index) != out_index) + write(2, "Bad write\n", 10); + exit(0); + } + in_index = 0; + } + c = input[in_index++]; + coded = vector[c]; + if (del_fl && invec[c]) continue; + if (sq_fl && last == coded && outvec[coded]) continue; + output[out_index++] = last = coded; + if (out_index == BUFFER_SIZE) { + if (write(1, (char *) output, out_index) != out_index) { + write(2, "Bad write\n", 10); + exit(1); + } + out_index = 0; + } + } + + /* NOTREACHED */ +} + +void map(unsigned char *string1, unsigned char *string2) +{ + unsigned char last = 0; + + while (*string1) { + if (*string2 == '\0') + vector[*string1] = last; + else + vector[*string1] = last = *string2++; + string1++; + } +} + +void expand(char *arg, unsigned char *buffer) +{ + int i, ac; + + while (*arg) { + if (*arg == '\\') { + arg++; + i = ac = 0; + if (*arg >= '0' && *arg <= '7') { + do { + ac = (ac << 3) + *arg++ - '0'; + i++; + } while (i < 4 && *arg >= '0' && *arg <= '7'); + *buffer++ = ac; + } else if (*arg != '\0') + *buffer++ = *arg++; + } else if (*arg == '[') { + arg++; + i = *arg++; + if (*arg++ != '-') { + *buffer++ = '['; + arg -= 2; + continue; + } + ac = *arg++; + while (i <= ac) *buffer++ = i++; + arg++; /* Skip ']' */ + } else { + *buffer++ = *arg++; + } + } +} + +void complement(unsigned char *buffer) +{ + register unsigned char *ptr; + register short i, index; + unsigned char conv[ASCII + 2]; + + index = 0; + for (i = 1; i <= ASCII; i++) { + for (ptr = buffer; *ptr; ptr++) + if (*ptr == i) break; + if (*ptr == '\0') conv[index++] = i & ASCII; + } + conv[index] = '\0'; + strcpy((char *) buffer, (char *) conv); +} diff --git a/Applications/util/true.c b/Applications/util/true.c new file mode 100644 index 00000000..d66447b7 --- /dev/null +++ b/Applications/util/true.c @@ -0,0 +1,6 @@ +#include + +int main(int argc, char *argv[]) +{ + return 0; +} diff --git a/Applications/util/umount.c b/Applications/util/umount.c new file mode 100644 index 00000000..7aa71b2a --- /dev/null +++ b/Applications/util/umount.c @@ -0,0 +1,89 @@ +#include +#include +#include + + +char tmp[256]; + +char *getdev(char *arg) +{ + FILE *f; + static char dev[20], mntpt[20], fstype[20], rwflag[20]; + + f = fopen("/etc/mtab", "r"); + if (f) { + while (fgets(tmp, 256, f)) { + sscanf(tmp, "%s %s %s %s\n", dev, mntpt, fstype, rwflag); + if ((strcmp(dev, arg) == 0) || (strcmp(mntpt, arg) == 0)) { + fclose(f); + return dev; + } + } + fclose(f); + } + + return NULL; +} + + +int rm_mtab(char *devname) +{ + FILE *inpf, *outf; + char *tmp_fname; + static char dev[20], mntpt[20], fstype[20], rwflag[20]; + + if ((tmp_fname = tmpnam(NULL)) == NULL) { + perror("Error getting temporary file name"); + exit(1); + } + inpf = fopen("/etc/mtab", "r"); + if (!inpf) { + perror("Can't open /etc/mtab"); + exit(1); + } + outf = fopen(tmp_fname, "w"); + if (!outf) { + perror("Can't create temporary file"); + exit(1); + } + while (fgets(tmp, 255, inpf)) { + sscanf(tmp, "%s %s %s %s\n", dev, mntpt, fstype, rwflag); + if (strcmp(dev, devname) == 0) { + continue; + } else { + fprintf(outf, "%s", tmp); + } + } + fclose(inpf); + fclose(outf); + if (unlink("/etc/mtab") < 0) { + perror("Can't delete old /etc/mtab file"); + exit(1); + } + if (rename(tmp_fname, "/etc/mtab") < 0) { + perror("Error installing /etc/mtab"); + exit(1); + } + return 0; +} + +int main(int argc, char *argv[]) +{ + char *dev; + + if (argc != 2) { + printf("usage: umount device\n"); + return 1; + } + + dev = getdev(argv[1]); + if (!dev) dev = argv[1]; + + if (umount(dev) == 0) { + rm_mtab(dev); + } else { + perror("umount"); + return 1; + } + return 0; +} diff --git a/Applications/util/uniq.c b/Applications/util/uniq.c new file mode 100644 index 00000000..1eefe95c --- /dev/null +++ b/Applications/util/uniq.c @@ -0,0 +1,192 @@ +/* uniq - compact repeated lines Author: John Woods */ +/* uniq [-udc] [-n] [+n] [infile [outfile]] + * + * Written 02/08/86 by John Woods, placed into public domain. Enjoy. + * + */ + +/* If the symbol WRITE_ERROR is defined, uniq will exit(1) if it gets a + * write error on the output. This is not (of course) how V7 uniq does it, + * so undefine the symbol if you want to lose your output to a full disk + */ + +#include +#include +#include +#include + +#define WRITE_ERROR 1 + +char buffer[BUFSIZ]; +int uflag = 1; /* default is union of -d and -u outputs */ +int dflag = 1; /* flags are mutually exclusive */ +int cflag = 0; +int fields = 0; +int chars = 0; + +char *skip(char *); +int equal(char *, char *); +void show(char *, int); +int uniq(void); +void usage(void); +int getline(char *, int); + +FILE *xfopen(char *fn, char *mode) +{ + FILE *p; + + if ((p = fopen(fn, mode)) == NULL) { + perror("uniq"); + fflush(stdout); + exit(1); + } + return (p); +} + +int main(int argc, char *argv[]) +{ + char *p; + int inf = -1, outf; + + setbuf(stdout, buffer); + for (--argc, ++argv; argc > 0 && (**argv == '-' || **argv == '+'); + --argc, ++argv) { + if (*argv[0] == '+') + chars = atoi(*argv + 1); + else if (isdigit(argv[0][1])) + fields = atoi(*argv + 1); + else if (argv[0][1] == '\0') + inf = 0; /* - is stdin */ + else + for (p = *argv + 1; *p; p++) { + switch (*p) { + case 'd': + dflag = 1; + uflag = 0; + break; + case 'u': + uflag = 1; + dflag = 0; + break; + case 'c': + cflag = 1; + break; + default: + usage(); + } + } + } + + /* Input file */ + if (argc == 0) { + inf = 0; + } else if (inf == -1) { /* if - was not given */ + fclose(stdin); + xfopen(*argv++, "r"); + argc--; + } + + if (argc == 0) { + outf = 1; + } else { + fclose(stdout); + xfopen(*argv++, "w"); + argc--; + } + + uniq(); + fflush(stdout); + + return (0); +} + +char *skip(char *s) +{ + int n; + + /* Skip fields */ + for (n = fields; n > 0; --n) { + /* Skip blanks */ + while (*s && (*s == ' ' || *s == '\t')) s++; + if (!*s) return s; + while (*s && (*s != ' ' && *s != '\t')) s++; + if (!*s) return s; + } + + /* Skip characters */ + for (n = chars; n > 0; --n) { + if (!*s) return s; + s++; + } + return s; +} + +int equal(char *s1, char *s2) +{ + return !strcmp(skip(s1), skip(s2)); +} + +void show(char *line, int count) +{ + if (cflag) { + printf("%4d %s", count, line); + } else { + if ((uflag && count == 1) || (dflag && count != 1)) + printf("%s", line); + } +} + +/* The meat of the whole affair */ +char *nowline, *prevline, buf1[1024], buf2[1024]; + +int uniq(void) +{ + char *p; + int seen; + + /* Setup */ + prevline = buf1; + if (getline(prevline, 1024) < 0) return (0); + seen = 1; + nowline = buf2; + + /* Get nowline and compare if not equal, dump prevline and swap + * pointers else continue, bumping seen count */ + while (getline(nowline, 1024) > 0) { + if (!equal(prevline, nowline)) { + show(prevline, seen); + seen = 1; + p = nowline; + nowline = prevline; + prevline = p; + } else { + seen += 1; + } + } + show(prevline, seen); + + return 0; +} + +void usage(void) +{ + fprintf(stderr, "Usage: uniq [-udc] [+n] [-n] [input [output]]\n"); + exit(1); +} + +int getline(char *buf, int count) +{ + int c; + int ct = 0; + + while (ct++ < count) { + c = getc(stdin); + if (c < 0) return (-1); + *buf++ = c; + if (c == '\n') { + *buf++ = 0; + return (ct); + } + } + return (ct); +} diff --git a/Applications/util/uud.c b/Applications/util/uud.c new file mode 100644 index 00000000..42d82f8c --- /dev/null +++ b/Applications/util/uud.c @@ -0,0 +1,437 @@ +/* uud - bulletproof version of uudecode */ + +/* + * Uud -- decode a uuencoded file back to binary form. + * + * UZI port of the minix version. + */ + +#include +#include +#include +#include +#include + +#define loop for(;;) + +#define NCHARS 256 +#define LINELEN 256 +#define FILELEN 64 +#define NORMLEN 60 /* allows for 80 encoded chars per line */ + +#define SEQMAX 'z' +#define SEQMIN 'a' +char seqc; +int first, secnd, check, numl; + +FILE *inpf, *outf; +char *pos; +char ifname[FILELEN], ofname[FILELEN]; +char *source = NULL, *target = NULL; +char blank, part = '\0'; +int partn, lens; +int debug = 0, nochk = 0, onedone = 0; +int chtbl[NCHARS], cdlen[NORMLEN + 3]; + +int main(int argc, char **argv); +char *getnword(char *str, int n); +void gettable(void); +void decode(void); +void getfile(char *buf); + +int main(int argc, char *argv[]) +{ + int mode; + register int i, j; + char *curarg; + char dest[FILELEN], buf[LINELEN]; + + while ((curarg = argv[1]) != NULL && curarg[0] == '-') { + if (((curarg[1] == 'd') || (curarg[1] == 'D')) && + (curarg[2] == '\0')) { + debug = 1; + } else if (((curarg[1] == 'n') || (curarg[1] == 'N')) && + (curarg[2] == '\0')) { + nochk = 1; + } else if (((curarg[1] == 't') || (curarg[1] == 'T')) && + (curarg[2] == '\0')) { + argv++; + argc--; + if (argc < 2) { + printf("uud: Missing target directory.\n"); + exit(15); + } + target = argv[1]; + if (debug) + printf("Target dir = %s\n", target); + } else if (((curarg[1] == 's') || (curarg[1] == 'S')) && + (curarg[2] == '\0')) { + argv++; + argc--; + if (argc < 2) { + printf("uud: Missing source directory.\n"); + exit(15); + } + source = argv[1]; + if (debug) + printf("Source dir = %s\n", source); + } else if (curarg[1] != '\0') { + printf("Usage: uud [-n] [-d] [-s dir] [-t dir] [input-file]\n"); + exit(1); + } else + break; + argv++; + argc--; + } + + if (curarg == NULL || ((curarg[0] == '-') && (curarg[1] == '\0'))) { + inpf = stdin; + strcpy(ifname, ""); + } else { + if (source != NULL) { + strcpy(ifname, source); + strcat(ifname, curarg); + } else { + strcpy(ifname, curarg); + } + if ((inpf = fopen(ifname, "r")) == NULL) { + printf("uud: Can't open %s\n", ifname); + exit(2); + } + numl = 0; + } + + /* Set up the default translation table. */ + for (i = 0; i < ' '; i++) chtbl[i] = -1; + for (i = ' ', j = 0; i < ' ' + 64; i++, j++) chtbl[i] = j; + for (i = ' ' + 64; i < NCHARS; i++) chtbl[i] = -1; + chtbl['`'] = chtbl[' ']; /* common mutation */ + chtbl['~'] = chtbl['^']; /* an other common mutation */ + blank = ' '; + + /* Set up the line length table, to avoid computing lotsa * and / ... */ + cdlen[0] = 1; + for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4) + cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j)); + + /* Search for header or translation table line. */ + loop { /* master loop for multiple decodes in one file */ + partn = 'a'; + loop { + if (fgets(buf, sizeof buf, inpf) == NULL) { + if (onedone) { + if (debug) + printf("End of file.\n"); + exit(0); + } else { + printf("uud: No begin line.\n"); + exit(3); + } + } + numl++; + if (strncmp(buf, "table", (size_t) 5) == 0) { + gettable(); + continue; + } + if (strncmp(buf, "begin", (size_t) 5) == 0) { + break; + } + } + lens = strlen(buf); + if (lens) buf[--lens] = '\0'; + + if (sscanf(buf, "begin%o%s", &mode, dest) != 2) { + printf("uud: Missing filename in begin line.\n"); + exit(10); + } + + if (target != NULL) { + strcpy(ofname, target); + strcat(ofname, dest); + } else { + strcpy(ofname, dest); + } + + if ((outf = fopen(ofname, "w")) == NULL) { /* binary! */ + printf("uud: Cannot open output file: %s\n", ofname); + exit(4); + } + + if (debug) + printf("Begin uudecoding: %s\n", ofname); + + seqc = SEQMAX; + check = nochk ? 0 : 1; + first = 1; + secnd = 0; + + decode(); + fclose(outf); + chmod(ofname, mode); + + onedone = 1; + + if (debug) + printf("End uudecoding: %s\n", ofname); + + } /* master loop for multiple decodes in one file */ +} + + +/* Bring back a pointer to the start of the nth word. */ + +char *getnword(char *str, int n) +{ + while ((*str == '\t') || (*str == ' ')) str++; + if (!*str) return NULL; + + while (--n) { + while ((*str != '\t') && (*str != ' ') && (*str)) str++; + if (!*str) return NULL; + while ((*str == '\t') || (*str == ' ')) str++; + if (!*str) return NULL; + } + + return str; +} + + +/* Install the table in memory for later use. */ + +void gettable(void) +{ + register int c, n = 0; + register char *cpt; + char buf[LINELEN]; + + for (c = 0; c < NCHARS; c++) chtbl[c] = -1; + + again: + if (fgets(buf, sizeof buf, inpf) == NULL) { + printf("uud: EOF while in translation table.\n"); + exit(5); + } + numl++; + if (strncmp(buf, "begin", (size_t) 5) == 0) { + printf("uud: Incomplete translation table.\n"); + exit(6); + } + cpt = buf + strlen(buf) - 1; + *cpt = ' '; + while (*(cpt) == ' ') { + *cpt = 0; + cpt--; + } + cpt = buf; + while (c = *cpt) { + if (chtbl[c] != -1) { + printf("uud: Duplicate char in translation table.\n"); + exit(7); + } + if (n == 0) blank = c; + chtbl[c] = n++; + if (n >= 64) return; + cpt++; + } + goto again; +} + + +/* Copy from inpf to outf, decoding as you go along. */ + +void decode(void) +{ + register char *bp, *ut; + register int *trtbl = chtbl; + register int n, c, rlen; + register unsigned int len; + char buf[LINELEN], outl[LINELEN]; + + loop { + if (fgets(buf, sizeof buf, inpf) == NULL) { + printf("uud: EOF before end.\n"); + fclose(outf); + exit(8); + } + numl++; + len = strlen(buf); + if (len) buf[--len] = '\0'; + + /* Is it an unprotected empty line before the end line ? */ + if (len == 0) continue; + + /* Get the binary line length. */ + n = trtbl[*buf]; + if (n >= 0) + goto decod; + + /* End of uuencoded file ? */ + if (strncmp(buf, "end", (size_t) 3) == 0) + return; + + /* End of current file ? : get next one. */ + if (strncmp(buf, "include", (size_t) 7) == 0) { + getfile(buf); + continue; + } + printf("uud: Bad prefix line %d in file: %s\n", numl, ifname); + if (debug) + printf("Bad line = %s\n", buf); + exit(11); + + /* Sequence checking ? */ + decod: + rlen = cdlen[n]; + + /* Is it the empty line before the end line ? */ + if (n == 0) continue; + + /* Pad with blanks. */ + for (bp = &buf[c = len]; c < rlen; c++, bp++) *bp = blank; + + /* Verify if asked for. */ + if (debug) { + for (len = 0, bp = buf; len < rlen; len++) { + if (trtbl[*bp] < 0) { + printf("Non uuencoded char <%c>, line %d in file: %s\n", + *bp, numl, ifname); + printf("Bad line = %s\n", buf); + exit(16); + } + bp++; + } + } + + /* + * All this just to check for uuencodes that append + * a 'z' to each line.... + */ + if (secnd && check) { + secnd = 0; + if (buf[rlen] == SEQMAX) { + check = 0; + if (debug) + printf("Sequence check turned off (2).\n"); + } else if (debug) + printf("Sequence check on (2).\n"); + } else if (first && check) { + first = 0; + secnd = 1; + if (buf[rlen] != SEQMAX) { + check = 0; + if (debug) + printf("No sequence check (1).\n"); + } else if (debug) + printf("Sequence check on (1).\n"); + } + + /* There we check. */ + if (check) { + if (buf[rlen] != seqc) { + printf("uud: Wrong sequence line %d in %s\n", + numl, ifname); + if (debug) + printf("Sequence char is <%c> instead of <%c>.\n", + buf[rlen], seqc); + exit(18); + } + seqc--; + if (seqc < SEQMIN) seqc = SEQMAX; + } + + /* + * Output a group of 3 bytes (4 input characters). The input chars + * are pointed to by p, they are to be output to file f.n is used + * to tell us not to output all of them at the end of the file. + */ + ut = outl; + len = n; + bp = &buf[1]; + while (n > 0) { + *(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4; + n--; + if (n) { + *(ut++) = (trtbl[bp[1]] << 4) | (trtbl[bp[2]] >> 2); + n--; + } + if (n) { + *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]]; + n--; + } + bp += 4; + } + if ((n = fwrite(outl, (size_t) 1, (size_t) len, outf)) <= 0) { + printf("uud: Error on writing decoded file.\n"); + exit(18); + } + } +} + +/* + * Find the next needed file, if existing, otherwise try further + * on next file. + */ +void getfile(char *buf) +{ + if ((pos = getnword(buf, 2)) == NULL) { + printf("uud: Missing include file name.\n"); + exit(17); + } else if (source != NULL) { + strcpy(ifname, source); + strcat(ifname, pos); + } else { + strcpy(ifname, pos); + } + + if (access(ifname, 04)) { + if (debug) { + printf("Can't find: %s\n", ifname); + printf("Continuing to read same file.\n"); + } + } else { + if (freopen(ifname, "r", inpf) == inpf) { + numl = 0; + if (debug) + printf("Reading next section from: %s\n", ifname); + } else { + printf("uud: freopen abort: %s\n", ifname); + exit(9); + } + } + + loop { + if (fgets(buf, LINELEN, inpf) == NULL) { + printf("uud: No begin line after include: %s\n", ifname); + exit(12); + } + numl++; + if (strncmp(buf, "table", (size_t) 5) == 0) { + gettable(); + continue; + } + if (strncmp(buf, "begin", (size_t) 5) == 0) + break; + } + + lens = strlen(buf); + if (lens) buf[--lens] = '\0'; + + /* Check the part suffix. */ + + if ((pos = getnword(buf, 3)) == NULL) { + printf("uud: Missing part name, in included file: %s\n", ifname); + exit(13); + } else { + part = *pos; + partn++; + if (partn > 'z') partn = 'a'; + if (part != partn) { + printf("uud: Part suffix mismatch: <%c> instead of <%c>.\n", + part, partn); + exit(14); + } + if (debug) + printf("Reading part %c\n", *pos); + } +} + diff --git a/Applications/util/uue.c b/Applications/util/uue.c new file mode 100644 index 00000000..a6e664a8 --- /dev/null +++ b/Applications/util/uue.c @@ -0,0 +1,192 @@ +/* uue - bulletproof version of uuencode */ + +/* Uue -- encode a file so that it's printable ascii, short lines + * + * UZI port of the minix version by HPG. + */ + + +#include +#include +#include +#include + +#define FILE_NAME 10 /* affects how long names are truncated */ + +/* ENC is the basic 1 character encoding function to make a char printing */ +#define ENC(c) (((c) & 077) + ' ') + +FILE *fp, *outp; +char ofname[80]; +int lenofname; +int stdo = 0; + +int part = 'a', chap = 'a'; + +#define SEQMAX 'z' +#define SEQMIN 'a' + +char seqc = SEQMAX; + +int split = 0; +int fileln = 32000; + +int main(int argc, char **argv); +void maketable(void); +void makename(void); +void encode(void); +void outdec(char *p); + +int main(int argc, char *argv[]) +{ + char *fname, *prog_name; + int filter; + + prog_name = argv[0] + strlen(argv[0]); + while (prog_name > argv[0] && prog_name[-1] != '/') prog_name--; + filter = strcmp(prog_name, "uuencode") == 0; + + if (argc < 2) { + fprintf(stderr, "Usage: %s [-n] inputfile [-]\n", prog_name); + exit(2); + } + + if (argv[1][0] == '-') { + fileln = -atoi(argv[1]); + if (fileln <= 0) { + fprintf(stderr, "Wrong file length arg.\n"); + exit(3); + } + split = 1; + argv++; + argc--; + } + + if (filter) { /* old uuencode reads from standard input */ + fp = stdin; + } else { + if ((fp = fopen(argv[1], "r")) == NULL) { /* binary input! */ + fprintf(stderr, "Cannot open %s\n", argv[1]); + exit(1); + } + } + + fname = argv[1] + strlen(argv[1]); + while (fname > argv[1] && fname[-1] != '/') fname--; + strcpy(ofname, fname); + fname = ofname; + do { + if (*fname == '.') *fname = '\0'; + } while (*fname++); + + /* 10 char prefix + .uue -> 14 chars MAX */ + lenofname = strlen(ofname); + if (lenofname > FILE_NAME) ofname[FILE_NAME] = '\0'; + strcat(ofname, ".uue"); + lenofname = strlen(ofname); + if (!split && (filter || (argc > 2) && (argv[2][0] == '-'))) { + stdo = 1; + outp = stdout; + } else { + makename(); + if ((outp = fopen(ofname, "w")) == NULL) { + fprintf(stderr, "Cannot open %s\n", ofname); + exit(1); + } + } + maketable(); + fprintf(outp, "begin %o %s\n", 0644, argv[1]); + encode(); + fprintf(outp, "end\n"); + fclose(outp); + + return (0); +} + + +/* + * Create ASCII table so a mailer can screw it up and the decode + * program can restore the error. + */ +void maketable(void) +{ + register int i, j; + + fputs("table\n", outp); + for (i = ' ', j = 0; i < '`'; j++) { + if (j == 32) putc('\n', outp); + fputc(i++, outp); + } + putc('\n', outp); +} + + +/* Generate the names needed for single and multiple part encoding. */ + +void makename(void) +{ + if (split) { + ofname[lenofname - 1] = part; + ofname[lenofname - 2] = chap; + } +} + + +/* Copy from in to out, encoding as you go along. */ + +void encode(void) +{ + char buf[80]; + register int i, n; + register int lines; + lines = 6; + + for (;;) { + n = fread(buf, 1, 45, fp); + putc(ENC(n), outp); + for (i = 0; i < n; i += 3) outdec(&buf[i]); + putc(seqc, outp); + seqc--; + if (seqc < SEQMIN) seqc = SEQMAX; + putc('\n', outp); + ++lines; + if (split && (lines > fileln)) { + part++; + if (part > 'z') { + part = 'a'; + if (chap == 'z') + chap = 'a'; /* loop ... */ + else + chap++; + } + makename(); + fprintf(outp, "include %s\n", ofname); + fclose(outp); + if ((outp = fopen(ofname, "w")) == NULL) { + fprintf(stderr, "Cannot open %s\n", ofname); + exit(1); + } + maketable(); + fprintf(outp, "begin part %c %s\n", part, ofname); + lines = 6; + } + if (n <= 0) break; + } +} + + +/* Output one group of 3 bytes, pointed at by p, on file f. */ + +void outdec(char *p) +{ + register int c1, c2, c3, c4; + + c1 = *p >> 2; + c2 = ((*p << 4) & 060) | ((p[1] >> 4) & 017); + c3 = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03); + c4 = p[2] & 077; + putc(ENC(c1), outp); + putc(ENC(c2), outp); + putc(ENC(c3), outp); + putc(ENC(c4), outp); +} diff --git a/Applications/util/wc.c b/Applications/util/wc.c new file mode 100644 index 00000000..81463bfe --- /dev/null +++ b/Applications/util/wc.c @@ -0,0 +1,148 @@ +/* wc - count lines, words and characters Author: David Messer */ + +#include +#include +#include + +/* + * Usage: wc [-lwc] [names] + * + * Flags: + * l - count lines. + * w - count words. + * c - count characters. + * + * Flags l, w, and c are default. + * Words are delimited by any non-alphabetic character. + * + * Released into the PUBLIC-DOMAIN 02/10/86 + * + * If you find this program to be of use to you, a donation of + * whatever you think it is worth will be cheerfully accepted. + * + * Written by: David L. Messer + * P.O. Box 19130, Mpls, MN, 55119 + * Program (heavily) modified by Andy Tanenbaum + */ + + +int lflag; /* Count lines */ +int wflag; /* Count words */ +int cflag; /* Count characters */ + +long lcount; /* Count of lines */ +long wcount; /* Count of words */ +long ccount; /* Count of characters */ + +long ltotal; /* Total count of lines */ +long wtotal; /* Total count of words */ +long ctotal; /* Total count of characters */ + +void count(FILE *f); +void usage(void); + +int main(int argc, char *argv[]) +{ + int k; + char *cp; + int tflag, files; + + /* Get flags. */ + files = argc - 1; + k = 1; + cp = argv[1]; + if (argc > 1 && *cp++ == '-') { + files--; + k++; /* points to first file */ + while (*cp != 0) { + switch (*cp) { + case 'l': lflag++; break; + case 'w': wflag++; break; + case 'c': cflag++; break; + default: usage(); + } + cp++; + } + } + + /* If no flags are set, treat as wc -lwc. */ + if (!lflag && !wflag && !cflag) { + lflag = 1; + wflag = 1; + cflag = 1; + } + + /* Process files. */ + tflag = (files >= 2); /* set if # files > 1 */ + + /* Check to see if input comes from std input. */ + if (k >= argc) { + count(stdin); + if (lflag) printf(" %6ld", lcount); + if (wflag) printf(" %6ld", wcount); + if (cflag) printf(" %6ld", ccount); + printf(" \n"); + fflush(stdout); + + return 0; + } + + /* There is an explicit list of files. Loop on files. */ + while (k < argc) { + FILE *f; + + if ((f = fopen(argv[k], "r")) == NULL) { + fprintf(stderr, "wc: cannot open %s\n", argv[k]); + } else { + count(f); + if (lflag) printf(" %6ld", lcount); + if (wflag) printf(" %6ld", wcount); + if (cflag) printf(" %6ld", ccount); + printf(" %s\n", argv[k]); + fclose(f); + } + k++; + } + + if (tflag) { + if (lflag) printf(" %6ld", ltotal); + if (wflag) printf(" %6ld", wtotal); + if (cflag) printf(" %6ld", ctotal); + printf(" total\n"); + } + fflush(stdout); + + return 0; +} + +void count(FILE *f) +{ + register int c; + register int word = 0; + + lcount = 0; + wcount = 0; + ccount = 0L; + + while ((c = getc(f)) != EOF) { + ccount++; + + if (isspace(c)) { + if (word) wcount++; + word = 0; + } else { + word = 1; + } + + if (c == '\n' || c == '\f') lcount++; + } + ltotal += lcount; + wtotal += wcount; + ctotal += ccount; +} + +void usage(void) +{ + fprintf(stderr, "Usage: wc [-lwc] [name ...]\n"); + exit(1); +} diff --git a/Applications/util/which.c b/Applications/util/which.c new file mode 100644 index 00000000..b25d33fa --- /dev/null +++ b/Applications/util/which.c @@ -0,0 +1,48 @@ +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int quit, found; + char *envpath; + char *path, *cp; + char buf[200]; + char patbuf[512]; + + if (argc < 2) { + fprintf(stderr, "Usage: which cmd [cmd, ..]\n"); + return 1; + } + if ((envpath = getenv("PATH")) == 0) { + envpath = "."; + } + argv[argc] = 0; + for (argv++; *argv; argv++) { + + strcpy(patbuf, envpath); + cp = path = patbuf; + quit = found = 0; + + while (!quit) { + cp = index(path, ':'); + if (cp == NULL) { + quit++; + } else { + *cp = '\0'; + } + sprintf(buf, "%s/%s", (*path ? path : "."), *argv); + path = ++cp; + + if (access(buf, 1) == 0) { + printf("%s\n", buf); + found++; + } + } + if (!found) { + printf("No %s in %s\n", *argv, envpath); + } + } + + return 0; +} diff --git a/Applications/util/whoami.c b/Applications/util/whoami.c new file mode 100644 index 00000000..3e48db49 --- /dev/null +++ b/Applications/util/whoami.c @@ -0,0 +1,18 @@ +#include +#include +#include + +int main(int argc, const char *argv[]) +{ + register struct passwd *pw; + register uid_t uid; + + uid = geteuid(); + pw = getpwuid(uid); + if (pw) { + printf("%s\n", pw->pw_name); + return 0; + } + + return 1; +} diff --git a/Kernel/BUGS b/Kernel/BUGS new file mode 100644 index 00000000..9b558d1b --- /dev/null +++ b/Kernel/BUGS @@ -0,0 +1,2 @@ +- SIGSTOP/TSTP behaviour wrong +- SIGCHLD not sent diff --git a/Kernel/COPYING b/Kernel/COPYING new file mode 100644 index 00000000..e77696ae --- /dev/null +++ b/Kernel/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Kernel/Makefile b/Kernel/Makefile new file mode 100644 index 00000000..8bfd6f32 --- /dev/null +++ b/Kernel/Makefile @@ -0,0 +1,163 @@ +TARGET_LIST = platform-nc100 platform-micropack platform-pcw8256 platform-socz80 platform-spec3 platform-trs80 platform-z80pack platform-z80pack-lite + +export TARGET= trs80 +export CPU = z80 +#export TARGET = 6809test +#export CPU = 6809 +#export TARGET = 6502test +#export CPU = 6502 +export VERSION = "0.1" +export SUBVERSION = "ac1" + +ifeq ($(CPU),z80) +export CROSS_AS=sdasz80 +export CROSS_LD=sdldz80 +export CROSS_CC=sdcc +#export CROSS_CCOPTS=-c --std-sdcc99 --no-std-crt0 -mz80 -I$(ROOT_DIR)/cpu-z80 -I$(ROOT_DIR)/platform-$(TARGET) -I$(ROOT_DIR)/include --max-allocs-per-node 1000000 --opt-code-size --Werror --stack-auto --constseg CONST +export CROSS_CCOPTS=-c --std-sdcc99 --no-std-crt0 -mz80 -I$(ROOT_DIR)/cpu-z80 -I$(ROOT_DIR)/platform-$(TARGET) -I$(ROOT_DIR)/include --max-allocs-per-node 30000 --opt-code-size --Werror --stack-auto --constseg CONST +#export CROSS_CCOPTS+=--nostdlib --nostdinc -Isdcclib/include +export CROSS_CC_SEG2=--codeseg CODE2 +export CROSS_CC_SEGDISC=--codeseg DISCARD +export CROSS_CC_FONT=--constseg FONT +export ASOPTS=-plosff +export BINEXT = .rel +else ifeq ($(CPU),6502) +export CROSS_AS=ca65 +export CROSS_LD=cl65 +export CROSS_CC=cl65 +export CROSS_CCOPTS=-c -Or -t c128 -I$(ROOT_DIR)/cpu-6502 -I$(ROOT_DIR)/platform-$(TARGET) -I$(ROOT_DIR)/include +export BINEXT = .o +else +export CROSS_AS=m6809-unknown-as +export CROSS_LD=m6809-unknown-ld +export CROSS_CC = m6809-unknown-gcc +#export CROSS_CCOPTS=-Wall -O2 -I$(ROOT_DIR)/cpu-6809 -I$(ROOT_DIR)/platform-$(TARGET) -I$(ROOT_DIR)/include +export CROSS_CCOPTS=-c -Wall -O2 -I$(ROOT_DIR)/cpu-6809 -I$(ROOT_DIR)/platform-$(TARGET) -I$(ROOT_DIR)/include +export ASOPTS= +endif + +ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) + + +# +# We put these into two code segments so that the caller can plan to +# bank them with a ROM banking tool. We pull out const data because on +# such a system you want to the constants unbanked otherwise badness +# happens on stuff like printf("Hello world\n"); when you bank switch +# the code. +# +# This is also useful if you've got an annoying box where the kernel can't +# be a linear chunk eg if you need to put the kernel in two non adjacent 16K +# chunks or compile it around a hole for videomemory or similar +# + +CDSRCS = start.c +C1SRCS = version.c kdata.c filesys.c +C1SRCS += inode.c syscall_fs.c +C2SRCS = devio.c process.c syscall_proc.c timer.c +C2SRCS += syscall_fs2.c syscall_other.c +C2SRCS += bank16k.c bank32k.c bankfixed.c single.c simple.c +C2SRCS += vt.c tty.c devsys.c +C2SRCS += mm.c swap.c usermem.c + +CFONTSRCS += font4x6.c font8x8.c + + +ASRCS = lowlevel-$(CPU).s usermem_std-$(CPU).s + + +CDOBJS = $(CDSRCS:.c=$(BINEXT)) +C1OBJS = $(C1SRCS:.c=$(BINEXT)) +C2OBJS = $(C2SRCS:.c=$(BINEXT)) +CFONTOBJS = $(CFONTSRCS:.c=$(BINEXT)) +AOBJS = $(ASRCS:.s=$(BINEXT)) + +CSRCS = $(CDSRCS) $(C1SRCS) $(C2SRCS) $(CFONTSRCS) +COBJS = $(CDOBJS) $(C1OBJS) $(C2OBJS) $(CFONTOBJS) + +OBJS = $(COBJS) $(AOBJS) + + +JUNK = $(CSRCS:.c=.lst) $(CSRCS:.c=.s) $(CSRCS:.c=.asm) $(CSRCS:.c=.sym) $(ASRCS:.s=.lst) $(ASRCS:.s=.sym) $(CSRCS:.c=.rst) $(CSRCS:.c=.o) $(ASRCS:.s=.rst) + +all: uzi.bin + +.SUFFIXES: # delete the default suffixes +.SUFFIXES: .c .s .rel + +target: + -rm platform + ln -sf platform-$(TARGET) platform + $(MAKE) -C platform-$(TARGET) + +$(C1OBJS): %$(BINEXT): %.c + $(CROSS_CC) $(CROSS_CCOPTS) $< + +$(CDOBJS): %$(BINEXT): %.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEGDISC) $< + +$(C2OBJS): %$(BINEXT): %.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_SEG2) $< + +$(CFONTOBJS): %$(BINEXT): %.c + $(CROSS_CC) $(CROSS_CCOPTS) $(CROSS_CC_FONT) $< + +$(AOBJS): %$(BINEXT): %.s + $(CROSS_AS) $(ASOPTS) -o $*$(BINEXT) $< + +version.c: makeversion + ./makeversion $(VERSION) $(SUBVERSION) $(TARGET) + +toosl/analysemap: tools/analysemap.c + +tools/memhogs: tools/analysemap + cp tools/analysemap tools/memhogs + +tools/binman: tools/binman.c + +tools/filesizes: tools/filesizes.c + +tools/make4x6: tools/make4x6.c + +font4x6.c: tools/make4x6 + tools/make4x6 >font4x6.c + +loader/loader.com: + +make -C loader loader.com + +ifeq ($(CPU), z80) +uzi.ihx: target $(OBJS) platform-$(TARGET)/uzi.lnk + $(CROSS_LD) -n -f platform-$(TARGET)/uzi.lnk + +uzi.bin: uzi.ihx tools/analysemap tools/memhogs tools/binman + tools/analysemap hogs.txt + head -5 hogs.txt + makebin -s 65536 -p uzi.ihx >uzi.tmp + tools/binman uzi.tmp uzi.map uzi.bin + $(MAKE) -C platform-$(TARGET) image +else +uzi.bin: target $(OBJS) + $(MAKE) -C platform-$(TARGET) image +endif + +# srec_cat -disable-sequence-warning uzi.ihx -intel -fill 0x00 0x0000 0x10000 -output uzi.bin -binary +uzi.com: target $(OBJS) loader/loader.com tools/analysemap tools/memhogs + loader/makeloader loader/loader.com uzi.ihx uzi.com --zerotop + +sendcpm: uzi.com + echo -n "!~!~!~" > /dev/ttyUSB1 + sleep 0.1 + echo "rboot 200" > /dev/ttyUSB1 + sleep 0.1 + sendcpm uzi.com + echo "uzi 1" > /dev/ttyUSB1 + +clean: + rm -f $(OBJS) $(JUNK) uzi.cdb uzi.com uzi.bin uzi.map uzi.noi uzi.ihx core *~ include/*~ version.c tools/analysemap tools/memhogs tools/binman hogs.txt hogs.txt.old tools/*~ + +make -C loader clean + +make -C platform-$(TARGET) clean + +clean-all: clean + $(foreach target,$(TARGET_LIST), make -C $(target) clean;) diff --git a/Kernel/PORTING b/Kernel/PORTING new file mode 100644 index 00000000..6abe8e20 --- /dev/null +++ b/Kernel/PORTING @@ -0,0 +1,606 @@ +Minimal Requirements +-------------------- + +- Z80 processor +- 128K memory (the kernel itself wants between 32 and 40K R/O and about + 8-16K R/W depending upon the configuration. +- Some kind of memory banking giving a common area and multiple banks +- A storage device, preferable hard disk or SD card or similar +- A timer interrupt (but you can sort of run single user with just a serial + / keyboard irq) + +In the ideal world + 256K of RAM or more + An RTC + 16K flexible memory banking + +With a bit more work (ie the planning for it is in place but someone needs +to do the work) it should also be possible to run with + +- Other 8bit processors with banked RAM (eg 6809) +- The kernel code banked in ROM in 3 x 16K banks +- Base/limit address space with a common area and ideally two ranges + (eg Z180) +- 16/32bit processors with either segments, base/limit pairs or just + vfork() style switching + +Porting Fuzix to a new Z80 based machine generally requires the following + +- Pick an output device that is easy to drive (serial or video) and write a + mininal test output driver for it standalone. Serial is usually best if + you don't have a character mapped console + +- Extend that into a suitable boot loader, unless loading from existing + firmware (see tips below for CP/M booting) + +- Select the appropriate model + + CONFIG_SINGLETASK + - single tasking (no fast swap device, limited memory). Processes are + run one at a time and the parent is run length compressed into upper + memory by default. This will provide all your pagemap helpers + automatically. This can (untested yet) be combined with SWAP_DEV if + you have a slow swap device to use other than RAM. With a fast swap + device and single process you can define SWAP_DEV and not define this. + + CONFIG_MULTI + - multi process in memory at once (multiple non kernel banks) + + SWAP_DEV + - swap device number if you have a suitable device for swap. This + is usually best done after it boots ok + +- Pick an appropriate platform to clone. + +- A lot of standard code is available to make porting easy + + CONFIG_BANK16 selects support for four flexible 16K bank registers + + CONFIG_BANK32 selects support for two flexible 32K bank registers + + CONFIG_BANK_FIXED selects support for systems where you have a selector for + all of the lower parts of memory in banks, and a fixed common at the top. + It can also be used if the banking is more flexible but has annoying + restrictions like not being able to map banks into other addresses (eg MSX1) + + CONFIG_BANK_LINEAR selects a system where memory is managed linearly with + base/limit pairs or similar and a common. This isn't yet tested but is + intended for Z180 and similar, and might be handy as a basis for M68K etc + + CONFIG_USERMEM_C tells the kernel to use the standard C helpers for user + memory copying. Set this initially for new architectures or for 6502/809, + and define BANK_PROCESS and BANK_KERNEL to switch kernel/user space. Make + sure you keep the code in common. The Z80 tree has a standard asm version + that uses your map_process/map_kernel functions. + + CONFIG_VT + VT_WIDTH, VT_HEIGHT, VT_RIGHT, VT_BOTTOM + + Include a standard virtual terminal core based upon VT52 emulation + + CONFIG_VT_SIMPLE + + Lets you define VT_BASE and it will drive a character mapped display with + typical layout. You may need to wrap vt calls in page switches according + to your platform + + CONFIG_FONT_8x8 and CONFIG_FONT_4x6 will include fonts. For 4x6 font usage + see nc100.s. The fonts are put in a special segment _FONT and your crt0.s + needs to decide where to place it. If you place it after the data then + the binman tool will relocate it to the end of the packed commonmem so it + can be moved into another segment (eg to be with the video screen data). + See pcw8256 for an example of this. + +- Set the basic system parameters + + TICKSPERSEC - clock rate + PROGBASE - low memory address fo applications (should be 0x100 + to run standard binaries). Some bits of start.c + still break if this is not 0x0100 + PROGTOP - first byte above main memory, usually the start of + the udata area and common memory. Typically above + 0xF000 but if your system has a fixed upper common + then this may need to be lower (eg 0xC000) + BOOT_TTY - the device you will use as your 'console' at boot + time + + CMDLINE - pointer to a command line passed from the + loader/firmare. If booting from CP/M (see below) use + 0x88 + + NUM_DEV_TTY - number of tty devices (video consoles/serial) + + NDEVS - number of entries for disk/block devices at the + start of your device table + TTYDEV - device init will use as input/output (usually BOOT_TTY) + + NBUFS - number of buffers for disk cache (each a bit of 512 + bytes) + + NMOUNTS - number of things that can be mounted at a time + (NDEVS or less) + + +If you have non interrupt driven serial ports then poll them in your IRQ +handler and provide a platform_idle which also polls the ports (makes it +feel much snappier). + +Provide a putchar() that writes to your console correctly either via direct +debug code or later via the tty helper. Provide a similar (register +preserving) assembler hook in outchar. That gives you a usable kprintf in C +and outhl/outde/outcharhex/.. series of methods in assembler for debugging. + +On a non single user system provide a pagemap_init which loads a list of +page numbers via pagemap_add. The numbers must *not* include a page 0. If +need be bias or xor with 0x80 or something. At boot you should have 2 or 4 +pages mapped (depending upon your kernel), one of which (usually the top) is +common. Add all the pages that are not kernel. + +In the 16K bank case you then lastly add the common page. This will then be allocated +to init and become the common for the init. That means you must keep kernel +code/data below 0xC000. Right now that is easy enough but once we add TCP/IP +might need banking. + +On 32K banking you can't do this so will need to play uarea swapping games +and keep the top bank as a kernel bank. This is much uglier but unlike +UZI180 only needs to swap uareas around on a true task switch. + +If your system has a fixed common area with single not flexible banks then +load the bank selections into the table rather than just loading pages + +MAX_MAPS is the max number of pages (or banks whatever you have) that you +can have. Set it to the largest you might need and load those present if +your system comes in different memory sizes. + +If you are using swap then + +SWAPBASE - lowest address that will be swapped +SWAPTOP - highest address that will be swapped + (TOP - BASE is usually a round number of blocks + so you don't have to do disk gymnastics in the driver) + Include the uarea in the common bank. + +UDATA_BLOCKS - special use (set to 0) +UDATA_SWAPSIZE +SWAP_SIZE - number of disk blocks needed to hold all the swap + for one process +MAX_SWAPS - largest number of SWAP_SIZE chunks that will be used + (bounded by disks/process table size/common sense) + + + + + +Functions to provide: (*) indicates they should be in COMMONMEM + +init_early - assembler function called right at the start, can be + NULL + +init_hardware - called before main and C entry + + Set _ramsize + Set _procmem + call _program_vectors with HL = 0 + (will map_kernel and set the RST vectors) + Enable any timers + Call _vtinit if you are using VT + Do *not* enable interrupts + +_program_vectors(*) - Program the vectors + + You can usually just re-use the default but this may + vary if you have odd commonmem setups + +_trap_monitor(*) - Return to ROM monitor/debugger or similar + +_trap_reboot(*) - Reboot the machine (may be useful to not do so + during debug) + +map_kernel(*) - Set the page mappings to those used by the kernel + + Must damage no registers + +map_process_always(*)- Set the page mappings to those of the current + process. These are held in the 4 bytes UDATA__U_PAGE + +map_process(*) - If HL is 0 map the kernel, if not map using the 4 + bytes pointed to by HL + +map_save(*) - Save the current mapping state + +map_restore(*) - Restore to the saved mapping state + + These two routines will be called with the same + common mapped in all cases. The state can therefore + be saved to common memory. + +outchar(*) - Output the character in A to your debug device. + Affect no other registers + + +_switchout(*) - Switch out a task + + Copy the one from an appropriate kernel type. This + will hopefully move into the core code soon + +_switchin(*) - Switch in a task + + Make the task we want to run runnable. If it is no + disk and we are swapping then swap it in, if there + is no room in memory swap stuff out + + Scary bits, copy from a suitable example and do not + debug after midnight. + +_dofork(*) - Create two instances of the same task + + This varies by platform type and the code is fairly + scary. Copy a suitable example. This will also + hopefully end up in the core once it's stabilized. + +If you are using vt + +_scroll_up - Scroll display up one line + + The vt layer will ask for the bottom line clear itself + +_scroll_down - Scroll display down one line + + The vt layer will ask for the top line clear itself + +_plot_char - Write a character to the display. Passed arguments + are y, x and the character + +_clear_lines - clear the display from line y for n lines + +_clear_across - clear the current line from y,x for n characters + +_cursor_on - put the cursor at y,x + +_cursor_off - remove the cursor + + +C interfaces +------------ + +Devices.c + +dev_tab is the device table for your platform indicating what is present. +Usually best taken from another platform and hacked up + +bool validdev(uint16_t dev) + +Check a device is valid. Cut and paste, it just needs to live with the +definition + +void device_init(void) + +Called early on before init runs so devices can do initialization before +they are opened. May well be blank + +Devtty.c + +Define a TTYSIZE buffer for each device present +Copy the struct s_queue from another filled in for your devices/buffers. + +Provide putchar(c) if it is not already provided by your asm code + +bool tty_writeready(uint8_t minor) + +Returns true fi you can write bytes to this port (1..n). For things like +video consoles just return true + +void tty_putc(uint8_t minor, char c) + +Write a character to the tty minor + +int tty_carrier(uint8_t minor) + +Return 1 if carrier raised or you arenot implementing the carrier interfaces +yet. + +void tty_setup(uint8_t minor) + +Do any tty set up required. Called on open and when the user changes the +termios parameters for the tty so you can set speed etc. + +void platform_interrupt(void) + +Called every interrupt in kernel context with the process state saved. You +may not sleep/taskswitch, you need to keep stack use fairly low. Every timer +tick you should call timer_interrupt() and the OS will do its other +housekeepking. + +Note: timer_interrupt may switch task and thus common so call it last unless +you are sure you *really* understand what is going on with fork. + +If your tty devices are polled then poll them on the IRQ if not then handle +them here. Either way call tty_inproc(minor, c) with the character to queue +it for input. This may call back to your tty_putc. + + +Main.c + +uint8_t *swapout_prepare_uarea(ptptr p) +uint8_t *swapin_prepare_uarea(ptptr p) + +Just return NULL unless you are doing clever things with udata + +void platform_idle(void) + +Usually you want to either poll the non interrupt driven devices (ttys) or +if they are IRQ driven then execute a halt instruction. In some cases you +may want to enter a processor low power state or drop to the lowest clock +speed. + +void do_beep(void) + +Provided for the vt driver. Make an irritating noise. The emulation is vt52 +so arguably the beep emulation should sound like someone stripping the gears +on a tank while trying to reverse. + +void pagemap_init(void) + +See notes earlier - add your pages to the pagemap. + + +Disk Devices + +_open(uint8_t minor, uint16_t flag) + +is called on opening. Usually it just checks minor is valid but could check +if a disc is loaded etc + +_close(uint8_t minor) + +is called on close (eg to force a final flush or to unlock) + +_read(uint8_t minor, uint8_t rawflag, uint8_t flag) + +is called to read blocks. It has three modes + + rawflag = 0 + + A normal read to kernel space. Must be supported. Fetch the + requested 512 byte block + + udata.u_buf->bf_data is the buffer data to load into + udata.u_buf->bf_blk is the block number + + If your media is 128 or 256 byte sectors you get to read several. + + rawflag = 1 (optional) + + Allows the char equivalent device to be opened for direct copies + to the userspace. This means the copy itself will need to be run + from common memory. + + udata.u_count is the number of blocks + udata.u_base is the address + udata.u_offset.o_blkno is the starting block + + Data goes to the current user process + + rawflag = 2 (swap device only) + + swapcnt is the number of blocks + swapbase is the starting address + swapproc is the process to swap in + swapblk is the block number to start at + +For a simple system you only need to implement rawflag = 0 and error = 1. +rawflag = 2 will only occur if this is your SWAP_DEV. rawflag = 1 support +may become mandatory as it'll be a good way to optimise execve(). + +In the swap case beware of the following. You may get issued a request to +write/read processes other than the current process. The map_process +function is defined on 16K banked platforms to remap banks 0-2, as 3 is +switched on task switching and holds the common copy, uarea and top of +process. That means that while uput/uget do the right thing for the current +process, it will *not* do so for addresses above 0xC000 of another process +and this may require special handling. + +_write(uint8_t minor, uint8_t rawflag, uint8_t flag) + +Same arguments, other direction. This means a lot of drivers turn both into +a call to a common transfer method. + + + +A Note On Geometry Mapping +-------------------------- + +The conventional mapping of block numbers is to start at track 0, side 0, +sector 1 as block 0, and then follow the usual upward pattern. The OS +reserves block 0 as a boot block, and puts the superblock at block 1. + +If you have a disc with a loadable kernel on it then put the kernel on the +*end* of the disc. This means you get a smaller file system on the media but +also means you don't to special case 'boot tracks' or waste any of a data +disc. + +The limit on blocks is 65536. Be careful of wraps and overflows when mapping +the geometry. With large media you can provide several 'disks' with +different minor numbers and add 65536 blocks to the base depending upon the +minor. + +Nothing stops a driver doing partition tables but we don't currently have a +library for it. + +BinMan +------ + +BinMan processes the SDCC final output image from a ROMable format to +something that fits disc loading. It moves the initializers into the +initialized area (so crt0.s doesn't need to) and it then appends the common +memory on the old initializer address and trims the image. It doesn't touch +relocations. On startup crt0.s sorts out any mappings and then copies s__INITIALIZER +into s__COMMONMEM for l__COMMONMEM before zeroing s__DATA for l__DATA + +Tips +---- +The most important bit of debug initially is usually proving you got from +your loader to crt0, and then tracking bank changes until the bank code +works properly. On an emulated system you can make it print out bank +switches in the emulator - very useful + +If you build a FUZIX kernel image so that cmdline is 0x0088 and it starts at +0x0100 then you can run it from unbanked CP/M (banked CP/M may get a bit +odd unless your crt0.s handles it specially). + +Hard Cases +========== + +Machines with low banks and a single fixed common +------------------------------------------------- +This needs mucking around copying the udata area back and forth between the +system and a cached copy (much as is needed on 32K banking). Take a look at +the z80pack virtual platform and port to see how to do this. You can +probably simply import z80pack and adjust the drivers. Note that z80pack +supports multiple bank/fixed divides and numbers of banks, so you can bring +z80pack up with your platform configuration + +You may have to decide between limited process size or being prepared to do +copying tricks to copy big chunks of memory around. + +If you have only a single user bank however it's easy - see z80pack-lite 8) + +Inflexible banking +------------------ +Systems where some banks can only fit at some locations. In this case copy +bank16k or bank32 as appropriate but update your swapper logic to find the +owner of a page in the ranges you need and victimise them, or if they are +not usefully flexible then set up fixed sets of them as "banks" and use the +fixed bank model. + +The pagemap_alloc/realloc and friends will also need updating - perhaps with +2 or more map tables. + +In other cases (eg the TRS80) you can only have one "high" bank mapped. This +really limits the TRS80 to single task with floppy or swapping to disk with +HD. Given the 128K limit that isn't too bad. + +The other examples are things like the Microbee (one 32K bank is flexible +the other is very rigid), and things like the Sinclair Spectrum/Amstrad CPC boxes. + +Research Problems +----------------- +In theory the kernel could be built as 2 or 3 16K banks of pure code, plus data +and some overspill in RAM. This might be very useful for Amstrad CPC type +boxes or the Sinclair Spectrum 128+/+2/+3 type boxes with awkward mapping +limits. Sadly sdcc isn't yet good enough to do this for you. + +Swapping Hints +-------------- + +Your swap device does not need to be a disk. If you have a really demented +memory map and page limits it may actually make sense to treat all the near +unusable memory as swap, especially in singletasking mode. In fact in +singletasking mode your swap acts as a stack. Likewise if your system has +lots of RAM accessible through a small window you can treat it as "swap" +rather than process memory + +Known Performance Problems +-------------------------- + +execve pulls all pages into kernel maps and then copies them to the task. +Fixing this is non trivial but may happen. If so then raw = 1 support for +all disks will become mandatory. + +fork is generally used as fork/execve. This causes a copy which is somewhat +surplus but is very bad on singletasking as it is both slow (the compressor +wants rewriting in Z80 someone) and also may prevent the child task fitting. +BSD unix implemented vfork() some systems implemented forkexecve(). We +should probably support vfork(). + +Other Processors +---------------- + +Currently only Z80 is supported. Clones should also work as should FPGA cores +like T80. The current build uses no undocumented instructions in any core +code. + +Z180 is not yet supported. This requires a rather unique memory banking +module to be debugged plus some driver pieces. It should however then enable +systems like N8VEM Mark IV and maybe even the 'Super TRS80' hacked hardware. + +Platform wise there are lots that could be supported. MSX is a notable gap, +especially given that UZIX has some MSX code. + +It ought to be possible to port UZI to any other small processor with +banking. That would include banked 6809/6309 systems and perhaps 65C816 +(Apple IIGS anyone ?) with a suitable compiler. The current core code has +been test built purely to verify it seems ok on 6809 (gcc) and 6502 (cc65). +Various endianisms in the core code have been fixed but there may be more. + +The constraints roughly speaking for any port are + +- banked memory +- near full 8bit address space +- some way to do udata. (or take the hit of making it a macro pointer) +- an ANSI C compiler +- timer interrupt, and preferably tty I/O interrupts +- blocking disk I/O. Fundamental to the size and design of the UZI core is + the assumption that accessing user space and block I/O do not block and + reschedule +- uniprocessor (well OK there are ways and means to do more but it won't be + too happy above a couple I suspect) + +Without banked memory but with a large address space you would need vfork() +and relocatable binaries. Doable as AmigaOS showed but forget swapping. + +As far as I can tell we have suitable open toolchains for + +6809 (gcc fork) - although 6809 is well served by NitrOS/9. The core code +has been built with gcc 6809 as a minimal sanity test. + +68HC11/2 (for the variants with banked RAM) + +TI990 (gcc development) - http://www.cozx.com/~dpitts/tigccinst.html +(TI 99/4A anyone ;-)) + +8086 is a gap but I'm working on pcc 8086 targets and could do with help +there (http://pcc.ludd.ltu.se/). Once the compiler is done the port should +be easy and cover both XT and 286. + +6502 is probably a cause too far (but prove me wrong...). The core code will +build with cc65. + +658C16 seems to lack a serious open compiler although there is a tcc port ! +(snes-sdk) + +The ANSI ACK can build rather decent 8080 code. Whether the output would fit +in 64K and anyone ever built a banked 8080 who knows 8) + +Various other early minicomputers probably also fit the target. + +Going to early 32bit CPU is hard because +- not all of the core code is 32bit clean (I've tried to begin marking out + the argument parameters and the like to fix it) +- the fs code knows that you can't write a size bigger than the filesystem + so other sanity checks would need adding + +A 2BSD/RetroBSD port might make a lot more sense anyway on such a system + + +Other Things That Would Help +---------------------------- + +Teaching SDCC to generate better code. It's not bad but sometimes it makes a +right mess, especially of long types. Someone also needs to write the +longlongs signed mod function and fix the fact that discarding the output +of a longlong call currently blows up sdcc. + +Writing a longlong implementation of mod for SDCC (needed for the C lib) + +We want 64bit time_t values in the ABI in order to get 2038 safety. We need +32bit versions to support non Z80 systems perhaps using structs for time_t + +SDCC call by register + +A tool to take all the compiler asm output of FUZIX on Z80, identify common +code blocks containing only internal references (jump/call) and (considering +segments) turn chunks of them into calls (sort of an executable compress). +O88 could do this for 8086. If we can shave a few K off this way it would +be brilliant + diff --git a/Kernel/README b/Kernel/README new file mode 100644 index 00000000..63b414b0 --- /dev/null +++ b/Kernel/README @@ -0,0 +1,929 @@ +FUZIX +===== + +FUZIX is a fusion of various elements from the assorted UZI forks and +branches beaten together into some kind of semi-coherent platform and then +extended from V7 to somewhere in the SYS3 to SYS5.x world with bits of POSIX +thrown in for good measure. Various learnings and tricks from ELKS and from +OMU also got blended in + +What does FUZIX have over UZI +============================= + +o Support for multiple processes in banked memory (as per UZI180) but + with Minix style chmem and efficient use of bank allocations. +o Support for multiple processes via hard disk or non mappable RAM + drive switching (as per UZI, UZIX). +o The ability to run single tasking on small devices, for bring up + and for standalone tool execution +o Support for "real" swapping combined with banked memory. +o Proper sane off_t and lseek +o Normal dev_t +o 30 character filenames +o Proper sane time_t +o System 5 signals (half baked) +o Posix termios (does all the original UZI tty did but much can be added) +o Blocking on carrier for terminals +o Optimisations to avoid bogus uarea copying compared to UZI180 +o More modern system call API: 3 argument open, mkdir, rmdir, rename, + chroot (with correct .. semantics), fchdir, fchmod, fchown, fstat, + fcntl, setpgrp, sighold and friends, waitpid, setpgrp, nice + O_NDELAY, O_CLOEXEC, F_SETFL, F_DUPFD etc +o Address validation checks on all syscall copies +o Builds with a modern ANSI C compiler (SDCC) +o Core code can be built for 6809 and 6502 so should be far more + portable +o Core architecture designed to support building and maintaining + multiple target machines without forking each one +o Helpers to make many bits of implementation wrappers to core code +o Lots more bugs right now + +What does UZI have over FUZIX +============================= + +o Can run in 64K of RAM (32K kernel/32K user). FUZIX would need + banked ROM or similar to pull this off. + +What do the UZI branches have that FUZIX has not yet integrated +=============================================================== + +o Minimal TCP/IP (UZIX 2.0). Unfortunately the original TCP was never +released openly. +o Symbolic links (UZIX) +o Various clever fusions of syscalls that may save a few bytes + (UZIX) +o setprio (UZIX) +o Rather crude loadable drivers (UZIX) +o Use of __naked and __asm for Z80 specific bits to avoid more + .S files than are needed (UMZIX) + +Plus OMU has a really clever function passing trick for open/creat and +friends, while UMZIX has a neat unified "make anything" function. + +What Key Features Are Missing Still +=================================== +o ptrace, core dumps, ulimit +o root reserved disk blocks +o banked executables +o TCP/IP +o select/poll() +o Z180 banking support +o /dev/tty alias +o Support for > 32MB filesystems (but first figure out how to fsck + a giant fs on a slow 8bit micro!) +o Uptime +o Smarter scheduler +o Optimisations for disk block/inode allocator (2.11BSD) +o CP/M emulator has not yet been ported to FUZIX syscall API + + +Tool Issues +=========== +o No useful 8086 compiler option (started work on pcc 8086 but help + needed) +o 6809 gcc and cc65 don't have long long 64bit (for sane time_t) +o SDCC has long long bugs and gaps +o SDCC can generate ROMmable binaries but not banked ones +o SDCC has no register passing function call support, and for some + stuff it really shows +o SDCC generates quite bloaty small applications. Needs research + on how to improve. +o None of the above have an O88 style common sequence compressor + + +Platforms +========= +o Z80Pack - used as a dev and test environment for both large swapping + mulitprocess and for small single tasking +o Amstrad NC100 - real hardware sanity check + +Various other platforms are partly filled out to sanity check assumptions +and start making progress on them. The main need there is now to tackle all +the billion different ways of interfacing the floppy controllers. + + + +--------------------------- Historical README files ------------------------------ + + UZI180 - Unix Z80 Implementation for the Z-180 (UZI180) + Adapted from UZI by Doug Braun and UZI280 by Stefan Nitschke + Copyright (C) 1998 by Harold F. Bower + + Portions Copyright (C) 1995 by Stefan Nitschke + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License (file LICENSE.TXT) for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +UZI180 is a multi-tasking, multi-user operating for the Zilog Z180 family +of microprocessors. It is a port of the original UZI incorporating many +fixes from UZI280 and some additional features. Significant changes +include an updated floppy disk driver based on a NEC765 derivative cont- +roller, a restructuring and reorganization of the various kernel modules +to ease porting to different hardware platforms, a simpler loading +structure from CP/M, and an integral (albeit minimal) CP/M 2.2 emulator. +The task was undertaken to learn more about the Unix operating system and +the C programming language with an eye to using it to replace several +aging CP/M systems. + +Like the original UZI, this system is based on Unix Edition 7 which was +one of the direct predecessors of Unix System V. UZI180 incorporates the +original system calls and the UZI280 extensions added by Stefan Nitschke. +Some minor additions were also added to provide additional System V compa- +tible features. As stated in the original documentation, there are only a +few significant differences in the UZI kernel calls. The principal +deviations are: + + - 32-bit return values are not provided, so data structures are passed + via pointers to pass essential information. "seek" is therefore incor- + porated as a kernel function with "lseek" provided as a library call. + + - The system "times" are reported in a different format than the standard + 32-bit count of seconds since 1 January 1970. 32-bit Date/Time struc- + tures are in the packed binary form used in IBM PCs, therefore + resulting in 2-second granularity. As a convention, the 0-99 year + should be interpreted as: 70-99 implying 1970-1999, and 0-69 being + 2000-2069 to provide Year 2000 compliance. Standard functions are + available as library routines. + + - The "stat" call has a different file length format due to the 32-bit + length omission and use of only 16-bit block and inode numbers. A data + structure is used to contain the information (see library source for + details). + +ARCHITECTURE: + +UZI180 makes extensive use of the Memory Management (MMU) of the Z180 core +to provide as much process isolation as possible with the chip. Since the +MMU granularity is 4k, this establishes the basic process structure. The +top 4k of logical address space (one MMU slice) is defined as Common1 memory +space and contains critical routines that either must always be resident in +memory, or are associated with the currently-running process. Some of the +key elements placed in the Common memory space are: + + - Interrupt Handlers + - Process Swapper + - System and Interrupt Stack Space + - User Process Data Structure + - Kernel Service Handler + +A full 64k is assigned to each process, with 60k available to application +code and data, with the remaining 4k used for system storage. This +organization permits one 64k bank for the kernel/common memory and seven +process banks on a 512k system where all RAM is usable. The UZI180 memory +map therefore appears as: + + First 64k Subsequent 64k banks + FFFF +------------+ +------------+ + Common | Common | | Task Store |+ + F000 +------------+ +------------+|+ + | | | |+|+ + | Kernel | | Process ||+| + Banked | Code | | Code |||+ + | | | & Data |||| + | | | |||| + 0100 +------------+ +------------+||| + | Reserved | | Reserved |+|| + 0000 +------------+ +------------+|+| + +------------+|+ + +------------+| + +------------+ + +Areas marked as "Reserved" are used for Restart and Interrupt vectors, +and to host the required Page 0 storage elements for the CP/M Emulator. +Constructing executable code modules starting at 100H also allows use of +normal CP/M tools without conflicting memory use. + +The architecture accomodates MMU base addresses beginning at the first +available RAM address wherever that is. For YASBEC and P112 systems that +shadow the ROM into RAM, the initial BBR (MMU Base Bank Register) reading +is 08H, while on the MicroMint SB180 RAM begins at 40H. 64k Banks will +therefore begin with BBR values of 08H, 18H, ..., 78H for the former; and +40H, 50H, ..., 70H for a 256k SB180. + +For 256k systems that have all RAM available (i.e. do NOT shadow the ROM), +the kernel and only three process banks will be available. While this may +be minimally usable for a single-user system, a 512k system is the minimum +recommended. For systems which DO shadow the system ROM, 32k is normally +reserved (beginning at physical RAM address 0), thereby reducing available +RAM by 32k. This leaves 480k available in a 512k system resulting in only +six process areas after allowing 64k for the kernel and common bank. The +last 32k will be unused. + +The algorithm for computing true 20-bit addresses in a Z180 (for DMA) is: + + BBR 7654 3210 + Addr hhhhhhhh llllllll + ---------------------- + bbbb xxxxxxxx yyyyyyyy + +An initial check should be made for common area access (assumed to be the +top 4k) which will be addresses of the form "1111hhhh llllllll" or FxxxH. +For these addresses, the raw BBR value for the first 64k of usable RAM is +added. As an example, the first byte of the Common Area is computed for +DMA use on a P112 with 512k of memory (ROM shadowed) as: + + BBR 0000 1000 08 + Addr 11110000 00000000 F000 + ---------------------- ----- + 0001 01110000 00000000 17000 + +A kernel variable (osBank) for the Common Area holds the BBR value for the +top 4k which is always accessible by the processor. It is used to specify +the source address when swapping out, and for the destination address when +swapping in. The BBR value associated with each process space is stored +both in the kernel process table, and in each process' user data block. +This value is used for the other address in process swaps. + +Task switching consists of saving the current process status in the User +stack and data area, block moving the user data area and stacks to the +respective process area in the reserved top 4k (via DMA), restoring the +new task's data into common memory (also via DMA), changing the Bank Base +Register in the Z180 MMU to bring the new task in context, resetting the +new process' stack pointer, restoring processor status and continuing as +before. This results in relatively rapid response since the bulk of time +required is due to two 768-byte DMA transfers which consume 1536 * 6 T- +states or 9216 / 18,432,000 = .0005 Sec = 500 microseconds on a 18.432 MHz +P112 or YASBEC upgraded with the Z8S180, and double this time, or 1000 +microseconds (1 millisecond) on a standard 9.216 MHz YASBEC. This ignores +any additional time due to insertion of memory wait states and the +relatively insignificant overhead associated with housekeeping. + +Time slices were initially set to 50 mS (20 ticks per second) based on one +of the internal Z180 Programmable Reload Timers. At that rate, less than +4% of a time slice was consumed in swapping processes. The development +systems have subsequently shortened the slice time to 20 mS to minimize +data loss from polled serial ports. A disadvantage of shortening the time +is that a greater percentage of CPU time is consumed during process swaps +with a subsequent lengthening of task run times. This may be adjusted by +appropriately setting parameters in the C and Assembly include files and +re-building the kernel. + +Since peripherals in small systems often are not capable of Interrupt- +driven operation, UZI180 implements polling of such ports during timer +interrupt cycles. Unfortunately, this can lead to inaccurate timekeeping +if the timer is the sole source of Real Time in the system. A prime +example of this is in the Floppy Disk Driver. Polled operation often +dictates that interrupts be disabled during disk accesses to avoid data +loss and/or corruption. During the comparively long time which may elapse +(up to one revolution of 200 milliseconds for 3.5" drives), several clock +ticks may be lost before timekeeping resumes. + +Wall-Time is corrected automatically by reading the Real-Time Clock every +time the number of ticks-per-second (set by a constant in include files) +elapses and updating a global kernel variable. This variable is then used +by kernel functions when necessary to perform such tasks as time stamping +files and returning current time-of-day. + +Polled IO sampling on timer interrupts is not so easily handled and data +loss may be significant. For systems which must operate in this manner, +it is recommended that low-priority processes be placed on those inter- +faces. Also, use of peripherals that disable interrupts for long periods, +such as polled Floppy Disk drivers, should be minimized. + + +OPERATION: + +The UZI180 kernel is Process 0 and executes in the lowest 64k of RAM in +the system as a standalone CP/M executable program. Several stages of +initialization occur when first started. The code and initial data which +is destined for the Common Memory is moved into position, having been +linked to an executable image during the link process. After initializing +various kernel data elements, Process 1 is initialized in the lower 60k of +the next higher 64k memory region. Normally Process 1 is "init" which +logs in users and starts (forks) a shell or other user interface. Each +consecutive fork without termination of a previous process is loaded into +the lower 60k of successively higher 64k increments. + +When a new process is initiated, data in the process' address is prepared +with several pieces of data. Necessary arguments and environment +variables are copied into high addresses along with the pointer arrays per +standard UZI definitions. Location 0H is initialized with a jump to a +TRAP (illegal instruction fetch) error handler, and location 0030H (RST +30H) with a jump to the kernel service handler. Both of these handlers +reside in the Common Memory bank beginning at 0F000H. Version-specific +locations may also be initialized at this phase such as the Interrupt +Vector at 0038H (RST 38) and the Non-Maskable Interrupt at 0066H. + +Process swaps are initiated by a simple timeout of a per-process counter +which is decremented. When a process is initiated (via an execve kernel +call) or the process is swapped into context, the counter is initiated to +a defined priority value. Each "tick" of the periodic clock interrupt +decrements the counter until it reaches zero. At that time, the User data +and associated stacks (User, Swap and Kernel) are copied to the highest 4k +of the respective process' memory space via DMA, data for the next +runnable process is loaded into the Common area, and the new process is +swapped into context by remapping the Bank Base value of the Z180's Memory +Management Unit. + +UZI180 kernel service calls are initiated by pushing necessary parameters +and the desired function number on the stack and executing a Restart 30H. +A jump to the service handler in common memory was placed at 0030H during +process initialization. Since a Restart functions as a one-byte CALL, a +return address is placed on the stack below the function number. The +Service handler obtains the stack address, switches to a kernel stack in +common memory, extracts information (function number and parameters) from +the user stack, switches the kernel in context, and passes control to the +kernel function process handler. When the function completes (except for +_exit), status information is passed to the kernel exit code in common +memory, the user process is restored to context along with the user stack, +and the Restart "returns" to the user code. Parameters are pushed onto +the stack in standard C form of right to left as specified in the function +declaration (contrary to UZI and UZI280). This places the left-most +declared parameter immediately above the return address on the user stack. + +Executable programs in UZI display the CP/M roots of the system in that +all programs begin execution at 100H. In melding the original Unix tech- +nique of testing the first character(s) of a file for "magic numbers" with +CP/M, all executable programs in UZI require that the first instruction be +a long jump (JP xxxx, opcode 0C3H). For native UZI applications, this +header is contained in the crt.obj file linked with all executable files. +UZI180 modifies this file to follow the jump with a text string containing +the three letters 'UZI'. If these three letters are missing but the +"magic number" 0C3H is present, then a CP/M executable is assumed and +execution commences under a CP/M emulator described below. + + +EMULATOR: + +In addition to the UZI kernel service calls used by native applications, a +minimal CP/M 2.2 emulator is built into UZI180 to allow many existing CP/M +and Z-System utilities to run under UZI180 without modification. The +emulator intercepts CP/M Bios and Bdos function requests and interprets +them into equivalent UZI kernel calls, or processes them directly. To +minimize the amount of memory consumed, only essential functions are +included, and not all programs will function correctly. Some of the more +significant limitations of the emulator are: + + - No Z-System data structures (ENV, IOP, RCP, FCP) are included + - Only Drive A:, User 0 (as the current directory) is available + - No ALV bits are included so Directory programs will be unable + to report free space + - The Bdos size is smaller than 3.5k so programs assuming standard + components by subtracting from Bios WB address will be wrong + - No Command Processor is included + +When needed, the emulator is moved into high process memory below the env +and arg parameters. Instead of transferring execution to the program at +100H as an UZI executable, the process begins by executing the base code +of the emulator. Code at this location is later overwritten by the CP/M +stack since it is only used during process initialization. This sequence +sets up CP/M vectors at 0H (Bios Warm Boot), 5H (Bdos service vector), +catenates argv parameters into a capitalized command line tail in the +default buffer starting at 0080H, and initializes other storage locations +(Current Drive/User, FCBs, etc) before beginning execution at 100H. CP/M +program termination by executing either a Bios Warm Boot or Bdos function +0 will trigger an UZI _exit kernel function and terminate the process. + +In the initial form, env parameters are not used by the emulator, but use +of the PATH variable is planned to make the system more usable. + + +DEVELOPMENT ENVIRONMENT. + +The bulk of UZI is programmed in the C language under the CP/M 2.2 or +compatible operating system. Doug Braun's original UZI was written with +the Codeworks' QC compiler which resulted in some odd interfaces since +parameters were passed the system stack in backwards order (left-to-right) +instead of the conventional right-to-left ordering used in the C program- +ming language. UZI280 and UZI180 were both written for the Hi-Tech ANSI +Standard compiler Version 3.09 released for non-commercial use in 1987 and +included in Walnut Creek's CP/M CD-ROM. The Hi-Tech package also included +a Z80/Z180 assembler, linker, librarian and source code for the CP/M run- +time library. This system forms the complete development environment +(less text editor) for UZI180. + +The Hi-Tech Compiler requires a rather large Transient Program Area to +compile the UZI sources. Consequently, users normally operating with the +Z-System may need to remove several of the standard ZCPR3.x components to +free up enough memory to compile the system. UZI180 was developed on the +author's Banked and Portable (B/P) Bios system with banked ZSDOS2 and +generated using autosizing of the system (BDOS and ZCPR) with no RCP or +IOP. Since the compiler overwrites the Command Processor, the base of +BDOS forms the upper limit of Transient Program Area which is 0E486H in +the author's system. The BIOS Warm Boot vector is at 0EE03H. This is +only slightly larger than a standard 62k CP/M system where the BDOS vector +is at 0E405H and BIOS WB vector at 0F203H. A standard 62k CP/M system +should be sufficient since the majority of initial work occured on a +slightly smaller system. + +Following Stefan Nitschke's lead with UZI280, assembly-language modules +were added to several portions of kernel code to provide platform- +dependant interfaces where necessary. Assembly code modules were also +added to improve performance, particularly to minimize context switches +and change parameter passing to the standard 'C' conventions of placing +parameters on the stack from right-to-left. In some cases, these assembly +modules were necessitated by apparent problems with the Hi-Tech compiler's +ability to handle inline assembly with optimization turned on. To avoid +severe performance penalties and code bloat, all modules were compiled +with optimization turned ON. + +When bringing up UZI180 for the first time, you must first extract all +member files in the basic Kernel library module, and member files for the +specific version for your platform. Begin by tailoring values in the +version-specific files to reflect your needs, particularly the Hard Disk +parameters in HDCONF.H. Check the Z180 initialization values in both +Z180ASM.ASZ and ASMDEF.I to insure that such items as Serial Data rates +and CPU clock frequency are accurate. + +You must next Compile/Assemble all source code C and Assembly modules for +the kernel. The simplest way to perform this is to execute the SUBmit +script CMPILUZI.SUB. In selecting the software tools for this task, use +either the original CP/M 2.2 SUB.COM or an equivalent such as SUPERSUB. +XSUB, EX and ZEX cannot be used since they install in high memory as a +Resident System Extension (RSX) below the Command Processor, thereby +reducing Transient Program Area space and creating problems for the +compiler. Development of UZI180 used SUPERSUB under the B/P Bios/ZSDOS2 +system described earlier. NOTE: with Operating Systems such as ZSDOS +which do not re-log hard disk partitions on warm boots, the $$$.SUB +temporary file is not re-detected to initiate the next line. Relogging +of the hard disk can be forced in a ZSDOS system by executing the ZSDOS +utility RELOG.COM after each line of the submit script. All but the +last line of the script should reflect the appended command when placed +in the Multiple Command Line buffer. An example compile command line +from CMPILUZI.SUB is: + + c -o -c -v process.c;relog + +After each module is compiled/assembled, either manually or via the SUBmit +script, the components must be linked into a loadable kernel image. A +script is provided for this purpose which is read into the Hi-Tech linker. +The script is set to produce an output file of UZI.COM which appears to +CP/M as a normal COMmand file, but siezes complete control and becomes the +UZI kernel when executed. This method of using the script with the Hi- +Tech linker is needed to handle the case-sensitivity of segment names in +the Hi-Tech relocatable format. Invoke the linker redirecting input from +the script file as: + + link