1 ; **************************************************************************** 2 ; sh386.s (sh4.s) - Retro Unix 386 v1.2 Shell - /bin/sh 3 ; ---------------------------------------------------------------------------- 4 ; 5 ; RETRO UNIX 386 (Retro Unix == Turkish Rational Unix) 6 ; Operating System Project (v0.2) by ERDOGAN TAN (Beginning: 24/12/2013) 7 ; 8 ; Derived from 'Retro UNIX 8086 v1' source code by Erdogan Tan 9 ; (v0.1 - Beginning: 11/07/2012) 10 ; 11 ; [ Last Modification: 15/06/2022 ] 12 ; 13 ; Derived from UNIX Operating System (v1.0 for PDP-11) 14 ; (Original) Source Code by Ken Thompson (Bell Laboratories, 1971-1972) 15 ; **************************************************************************** 16 ; 17 ; 18 ; 19 ; 20 ; 21 ; **************************************************************************** 22 23 ; Assembler: NASM v2.15 24 ; ((nasm sh4.s -l sh4.txt -o sh4 -Z error.txt)) 25 26 ; sh4.s (13/06/2022, Retro UNIX 386 v1.2) -- (modified sh2.s) --- 27 ; sh3.s (29/05/2022, Retro UNIX 386 v1) -- (modified sh0.s) --- 28 ; sh2.s (29/05/2022, Retro UNIX 386 v1.1 & v1.2) -- (modified sh1.s) -- 29 ; sh1.s (03/01/2016, Retro UNIX 386 v1.1) 30 ; sh0.s (28/12/2015, Retro UNIX 386 v1, NASM 2.11, 32 bit version of 'sh.asm') 31 ; SHELL03.ASM, 13/11/2013 - 27/06/2014 (sh.asm, Retro UNIX 8086 v1, MASM 6.11) 32 33 ; 12/01/2022 (Retro UNIX 386 v1.2) 34 ; 13/10/2015 35 ; 27/08/2015 36 ; 24/08/2015 37 ; 08/04/2014 38 ; 13/11/2013 39 40 ; UNIX v1 system calls 41 _rele equ 0 42 _exit equ 1 43 _fork equ 2 44 _read equ 3 45 _write equ 4 46 _open equ 5 47 _close equ 6 48 _wait equ 7 49 _creat equ 8 50 _link equ 9 51 _unlink equ 10 52 _exec equ 11 53 _chdir equ 12 54 _time equ 13 55 _mkdir equ 14 56 _chmod equ 15 57 _chown equ 16 58 _break equ 17 59 _stat equ 18 60 _seek equ 19 61 _tell equ 20 62 _mount equ 21 63 _umount equ 22 64 _setuid equ 23 65 _getuid equ 24 66 _stime equ 25 67 _quit equ 26 68 _intr equ 27 69 _fstat equ 28 70 _emt equ 29 71 _mdate equ 30 72 _stty equ 31 73 _gtty equ 32 74 _ilgins equ 33 75 _sleep equ 34 ; Retro UNIX 8086 v1 feature only ! 76 _msg equ 35 ; Retro UNIX 386 v1 feature only ! 77 _geterr equ 36 ; Retro UNIX 386 v1 feature only ! 78 ; 12/01/2022 - Retro UNIX 386 v1.2 79 ; Retro UNIX 386 v2 system calls 80 _setgid equ 37 81 _getgid equ 38 82 _sysver equ 39 ; (get) Retro Unix 386 version 83 84 %macro sys 1-4 85 ; 03/09/2015 86 ; 13/04/2015 87 ; Retro UNIX 386 v1 system call. 88 %if %0 >= 2 89 mov ebx, %2 90 %if %0 >= 3 91 mov ecx, %3 92 ;%if %0 = 4 93 %if %0 >= 4 ; 11/03/2022 94 mov edx, %4 95 %endif 96 %endif 97 %endif 98 mov eax, %1 99 int 30h 100 %endmacro 101 102 ; 14/06/2022 - Retro UNIX 386 v1.2 103 struc stat 104 ; Retro UNIX v1.2 'sysstat' output ! 105 ; (66 bytes) 106 00000000 ???? .inode: resw 1 107 00000002 ???? .mode: resw 1 108 00000004 ???? .nlinks: resw 1 109 00000006 ???? .uid: resw 1 110 00000008 ?? .gid: resb 1 111 00000009 ?? .size_h: resb 1 112 0000000A ???????? .size: resd 1 113 0000000E .dskptr: resd 10 114 00000036 ???????? .atime: resd 1 115 0000003A ???????? .mtime: resd 1 116 0000003E ???????? .ctime: resd 1 117 .strucsize: 118 endstruc 119 120 ; Retro UNIX 386 v1 system call format: 121 ; sys systemcall (eax) , , 122 123 ;----------------------------------------------------------------- 124 ; text - code 125 ;----------------------------------------------------------------- 126 127 [BITS 32] ; 32-bit intructions (for 80386 protected mode) 128 129 [ORG 0] 130 131 START_CODE: 132 ;/ sh -- command interpreter 133 134 ; 13/06/2022 135 ; 29/05/2022 - Erdogan Tan 136 ; (Modified by using disassembled unix v2 'sh' code.) 137 138 ;;27/12/2015 139 ;;clear BSS 140 ;mov ecx, ((bss_end - bss_start) + 3) / 4 141 ;sub eax, eax 142 ;mov edi, bss_start 143 ;rep stosd 144 s0: 145 00000000 89E5 mov ebp, esp 146 ; mov sp,r5 147 00000002 892D[6E0C0000] mov [shellarg], ebp 148 ; mov r5,shellarg / save orig sp in shellarg 149 00000008 8B5D04 mov ebx, [ebp+4] 150 0000000B 803B2D cmp byte [ebx], '-' 151 ; cmpb *2(r5),$'- / was this sh called by init or login 152 0000000E 752E jne short s1 153 ; bne 2f / no 154 sys _intr, 0 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000010 BB00000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000015 B81B000000 <1> mov eax, %1 99 0000001A CD30 <1> int 30h 155 ; sys intr; 0 / yes, turn off interrupts 156 sys _quit, 0 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 0000001C BB00000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000021 B81A000000 <1> mov eax, %1 99 00000026 CD30 <1> int 30h 157 ; sys quit; 0 158 sys _write, 1, msg_unix_sh, msgsh_size 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000028 BB01000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 0000002D B9[E6050000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 00000032 BA1D000000 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000037 B804000000 <1> mov eax, %1 99 0000003C CD30 <1> int 30h 159 s1: ;2: 160 sys _getuid 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 0000003E B818000000 <1> mov eax, %1 99 00000043 CD30 <1> int 30h 161 ; sys getuid / who is user 162 ;and eax, eax 163 00000045 20C0 and al, al 164 ; tst r0 / is it superuser 165 00000047 7507 jnz short s2 166 ; bne 2f / no 167 00000049 C605[74060000]23 mov byte [_at], '#' 168 ; movb $'#,at / yes, set new prompt symbol 169 s2: ;2: 170 00000050 837D0001 cmp dword [ebp], 1 171 ; cmp (r5),$1 / tty input? 172 00000054 7631 jna short newline 173 ; ble newline / yes, call with '-' (or with no command 174 ; / file name) 175 00000056 31DB xor ebx, ebx 176 ; clr r0 / no, set tty 177 sys _close 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000058 B806000000 <1> mov eax, %1 99 0000005D CD30 <1> int 30h 178 ; sys close / close it 179 0000005F 8B5D08 mov ebx, [ebp+8] ; arg 1 180 ; mov 4(r5),0f / get new file name 181 00000062 31C9 xor ecx, ecx ; arg 2 182 sys _open 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000064 B805000000 <1> mov eax, %1 99 00000069 CD30 <1> int 30h 183 ; sys open; 0:..; 0 / open it 184 0000006B 7311 jnc short s3 185 ; bec 1f / branch if no error 186 0000006D BE[10060000] mov esi, msgNotFound 187 00000072 E8EA010000 call error 188 ; jsr r5,error / error in file name 189 ; ; .even 190 sys _exit 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000077 B801000000 <1> mov eax, %1 99 0000007C CD30 <1> int 30h 191 ; sys exit 192 s3: ;1: 193 0000007E C605[74060000]00 mov byte [_at], 0 194 ; clr at / clear prompt character, if reading non-tty 195 ; / input file 196 00000085 EB1F jmp short newcom 197 newline: 198 00000087 803D[74060000]00 cmp byte [_at], 0 199 ; tst at / is there a prompt symbol 200 0000008E 7616 jna short newcom 201 ; beq newcom / no 202 ; mov $1,r0 / yes 203 nl: 204 sys _write, 1, prompt, p_size 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000090 BB01000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000095 B9[72060000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 0000009A BA04000000 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 0000009F B804000000 <1> mov eax, %1 99 000000A4 CD30 <1> int 30h 205 ;sys _write, 1, _at, 2 206 ; sys write; at; 2. / print prompt 207 newcom: 208 000000A6 8B25[6E0C0000] mov esp, [shellarg] 209 ; mov shellarg,sp / 210 000000AC BE[A1060000] mov esi, parbuf 211 ; mov $parbuf,r3 / initialize command list area 212 000000B1 BF[9C0A0000] mov edi, parp 213 ; mov $parp,r4 / initialize command list pointers 214 000000B6 31C0 xor eax, eax 215 000000B8 A3[900A0000] mov [infile], eax ; 0 216 ; clr infile / initialize alternate input 217 000000BD A3[940A0000] mov [outfile], eax ; 0 218 ; clr outfile / initialize alternate output 219 000000C2 A2[8E0A0000] mov [glflag], al ; 0 220 ;mov [glflag], ax ; 0 221 ; clr glflag / initialize global flag 222 ; 27/12/2015 223 000000C7 A2[71060000] mov [FCAT], al ; 0 224 newarg: 225 000000CC E8A1030000 call blank 226 ; jsr pc,blank / squeeze out leading blanks 227 000000D1 E87D030000 call delim 228 000000D6 7467 je short nch4 ; '\n', ';', '&' 229 ; jsr r5,delim / is new character a ; \n or & 230 ; br 2f / yes 231 000000D8 56 push esi 232 ; mov r3,-(sp) / no, push arg pointer onto stack 233 000000D9 3C3C cmp al, '<' 234 ; cmp r0,$'< / new input file? 235 000000DB 7508 jne short na1 236 ; bne 1f / no 237 000000DD 8935[900A0000] mov [infile], esi 238 ; mov (sp),infile / yes, save arg pointer 239 ;jmp short na4 240 000000E3 EB1E jmp short na3 241 ;mov dword [esp], 0 242 ; clr (sp) / clear pointer 243 ;jmp short nch1 244 ; br 3f 245 na1: ;1: 246 000000E5 3C3E cmp al, '>' 247 ; cmp r0,$'> / new output file? 248 000000E7 7530 jne short nch0 249 ;jne short newchar 250 ; bne newchar / no 251 000000E9 8935[940A0000] mov [outfile], esi 252 ; mov (sp),outfile / yes, save arg pointer 253 ; 27/12/2015 254 000000EF E890030000 call getc 255 000000F4 3C3E cmp al, '>' 256 000000F6 7507 jne short na2 257 ; 258 000000F8 A2[71060000] mov [FCAT], al ; '>>' 259 000000FD EB04 jmp short na3 260 na2: 261 000000FF 3C20 cmp al, 20h ; ' ' 262 00000101 7505 jne short na4 263 na3: 264 00000103 E86A030000 call blank 265 na4: 266 00000108 C7042400000000 mov dword [esp], 0 267 ; clr (sp) / clear pointer 268 ;jmp short nch1 269 ; br 3f 270 0000010F EB12 jmp short nch7 271 newchar: 272 00000111 3C20 cmp al, 20h 273 ; cmp $' ,r0 / is character a blank 274 00000113 7415 je short nch2 275 ; beq 1f / branch if it is (blank as arg separator) 276 00000115 3C8D cmp al, 8Dh ; 128 + 13 277 00000117 7411 je short nch2 278 ; cmp $'\n+200,r0 / treat \n preceded by ; beq 1f / as blank 280 nch0: 281 00000119 E8A0010000 call putc 282 ; jsr pc,putc / put this character in parbuf list 283 nch1: ;3: 284 0000011E E861030000 call getc 285 ; jsr pc,getc / get next character 286 nch7: 287 00000123 E82B030000 call delim 288 00000128 75E7 jne short newchar 289 ;jz short nch2 ; '\n', ';', '&' 290 ; jsr r5,delim / is char a ; \n or &, 291 ; br 1f / yes 292 ;jmp short newchar 293 ; br newchar / no, start new character tests 294 nch2: ;1: 295 0000012A C60600 mov byte [esi], 0 296 0000012D 46 inc esi 297 ; clrb (r3)+ / end name with \0 when read blank, 298 ; or delim 299 0000012E 5B pop ebx 300 0000012F 891F mov [edi], ebx 301 ; mov (sp)+,(r4)+ / move arg ptr to parp location 302 00000131 09DB or ebx, ebx 303 00000133 7403 jz short nch3 304 ;jnz short nch3 305 ; bne 1f / if (sp)=0, in file or out file points 306 ; to arg 307 00000135 83C704 add edi, 4 308 ; tst -(r4) / so ignore dummy (0), in pointer list 309 nch3: ;1: 310 00000138 E816030000 call delim 311 0000013D 758D jne short newarg 312 ;jz short nch4 ; '\n', ';', '&' 313 ; jsr r5,delim / is char a ; \n or &. 314 ; br 2f / yes 315 ;jmp short newarg 316 ; br newarg / no, start newarg processing 317 nch4: ;2: 318 0000013F C70700000000 mov dword [edi], 0 319 ; clr (r4) / \n, &, or ; takes to here 320 ; / (end of arg list) after 'delim' call 321 00000145 50 push eax 322 ; mov r0,-(sp) / save delimiter in stack 323 00000146 E827000000 call docom 324 ; jsr pc,docom / go to exec command in parbuf 325 0000014B 803C2426 cmp byte [esp], '&' 326 ; cmpb (sp),$'& / get a new command without wait? 327 ;je newcom 328 ; ; beq newcom / yes 329 ; 29/05/2022 330 0000014F 7505 jne short nch_9 331 nch_8: 332 00000151 E950FFFFFF jmp newcom 333 nch_9: 334 00000156 21D2 and edx, edx 335 ; tst r1 / was chdir just executed or line ended 336 ; / with ampersand? 337 00000158 740D jz short nch6 338 ; beq 2f / yes 339 nch5: ;1: 340 sys _wait 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 0000015A B807000000 <1> mov eax, %1 99 0000015F CD30 <1> int 30h 341 ; sys wait / no, wait for new process to terminate 342 ; / command executed) 343 00000161 7204 jc short nch6 344 ; bcs 2f / no, children not previously waited for 345 00000163 39D0 cmp eax, edx 346 ; cmp r0,r1 / is this my child 347 00000165 75F3 jne short nch5 348 ; bne 1b 349 nch6: ;2: 350 00000167 803C240D cmp byte [esp], 0Dh 351 ;cmp byte [esp], 0Ah 352 ; cmp (sp),$'\n / was delimiter a new line 353 ;je newline 354 ; ; beq newline / yes 355 ; 29/05/2022 356 ;jmp newcom 357 ; ; br newcom / no, pick up next command 358 0000016B 75E4 jne short nch_8 ; jne newcom 359 0000016D E915FFFFFF jmp newline ; je newline 360 docom: 361 00000172 81EF[9C0A0000] sub edi, parp 362 ; sub $parp,r4 / out arg count in r4 363 00000178 7503 jne short dcom1 364 ; bne 1f / any arguments? 365 dcom0: 366 0000017A 29D2 sub edx, edx ; 0 367 ; clr r1 / no, line ended with ampersand 368 0000017C C3 retn 369 ; rts pc / return from call 370 dcom1: ;1: 371 0000017D 89FB mov ebx, edi 372 ; 06/12/2013 373 0000017F BE[76060000] mov esi, qecho 374 00000184 E827010000 call chcom 375 00000189 7543 jnz short dcom7 376 ; 28/12/2015 377 0000018B 89DD mov ebp, ebx 378 0000018D BF[9C0A0000] mov edi, parp 379 dcom9: ; CRLF 380 sys _write, 1, nextline, 2 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000192 BB01000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000197 B9[0D060000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 0000019C BA02000000 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 000001A1 B804000000 <1> mov eax, %1 99 000001A6 CD30 <1> int 30h 381 ; 382 000001A8 83ED04 sub ebp, 4 ; remain arg count x 4 383 000001AB 76CD jna short dcom0 384 000001AD 83C704 add edi, 4 385 000001B0 8B37 mov esi, [edi] 386 ;or esi, esi 387 ;jz short dcom0 388 000001B2 89F2 mov edx, esi ; string address 389 dcom10: 390 000001B4 AC lodsb 391 000001B5 08C0 or al, al 392 000001B7 75FB jnz short dcom10 393 000001B9 87D6 xchg edx, esi 394 000001BB 29F2 sub edx, esi ; byte count 395 000001BD 4A dec edx 396 ;jz short dcom0 397 ; write string 398 sys _write, 1, esi ; edx = byte count 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 000001BE BB01000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 000001C3 89F1 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 000001C5 B804000000 <1> mov eax, %1 99 000001CA CD30 <1> int 30h 399 000001CC EBC4 jmp short dcom9 400 dcom7: 401 000001CE BE[7E060000] mov esi, qchdir 402 000001D3 E8D8000000 call chcom 403 000001D8 752D jnz short dcom4 404 ; jsr r5,chcom; qchdir / is command chdir? 405 ; br 2f / command not chdir 406 dcom12: 407 000001DA 80FB08 cmp bl, 8 ; 8 = arg count x 4 (24/08/2015) 408 ;cmp bx, 8 409 ; cmp r4,$4 / prepare to exec chdir, 410 ; 4 = arg count x 2 411 000001DD 740C je short dcom2 412 ; beq 3f 413 dcom8: 414 000001DF BE[20060000] mov esi, msgArgCount 415 000001E4 E878000000 call error 416 ; jsr r5,error / go to print error 417 ; ; .even 418 ;jmp short dcom3 419 ; br 4f 420 000001E9 EB8F jmp short dcom0 421 dcom2: ;3: 422 000001EB 8B1D[A00A0000] mov ebx, [parp+4] 423 ;mov parp+2,0f / move directory name to sys call 424 sys _chdir 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 000001F1 B80C000000 <1> mov eax, %1 99 000001F6 CD30 <1> int 30h 425 ; sys chdir; 0:0 / exec chdir 426 000001F8 730A jnc short dcom3 427 ; bec 4f / no error exit 428 000001FA BE[2A060000] mov esi, msgBadDir 429 000001FF E85D000000 call error 430 ; jsr r5,error / go to print error 431 ; ; .even 432 ; / this diagnostic 433 dcom3: ;4: 434 00000204 31D2 xor edx, edx ; 0 435 ; clr r1 / set r1 to zero to skip wait 436 00000206 C3 retn 437 ; rts pc / and return 438 dcom4: ;2: 439 ; 06/12/2013 440 00000207 BE[7B060000] mov esi, qcd 441 0000020C E89F000000 call chcom 442 00000211 74C7 jz short dcom12 443 dcom11: 444 00000213 BE[84060000] mov esi, glogin 445 00000218 E893000000 call chcom 446 0000021D 7522 jnz short dcom5 447 ; jsr r5,chcom; glogin / is command login? 448 ; br 2f / not loqin, go to fork 449 sys _exec, parbuf, parp 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 0000021F BB[A1060000] <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000224 B9[9C0A0000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000229 B80B000000 <1> mov eax, %1 99 0000022E CD30 <1> int 30h 450 ; sys exec; parbuf; parp / exec login 451 sys _exec, binpb, parp 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000230 BB[9C060000] <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000235 B9[9C0A0000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 0000023A B80B000000 <1> mov eax, %1 99 0000023F CD30 <1> int 30h 452 ; sys exec; binpb; parp / or /bin/login 453 dcom5: ;2: / no error return?? 454 00000241 BB[F3020000] mov ebx, newproc 455 ; child process will return to 'newproc' address 456 sys _fork 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000246 B802000000 <1> mov eax, %1 99 0000024B CD30 <1> int 30h 457 ; sys fork / generate sh child process 458 ; for command 459 ; br newproc / exec command with 460 ; new process 461 ; parent process will return here 462 0000024D 730F jnc short dcom6 463 ; bec 1f / no error exit, old process 464 0000024F BE[38060000] mov esi, msgTryAgain 465 00000254 E808000000 call error 466 ; jsr r5,error / go to print error 467 ; ; .even / this diagnostic 468 00000259 E929FEFFFF jmp newline 469 ; jmp newline / and return for next try 470 dcom6: ;1: 471 0000025E 89C2 mov edx, eax ; child process ID 472 ; mov r0,r1 / save id of child sh 473 00000260 C3 retn 474 ; rts pc / return to "jsr pc, docom" call 475 ; in parent sh 476 error: 477 sys _write, 1, nextline, 2 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000261 BB01000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000266 B9[0D060000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 0000026B BA02000000 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000270 B804000000 <1> mov eax, %1 99 00000275 CD30 <1> int 30h 478 s4: 479 00000277 AC lodsb 480 00000278 A2[6C0C0000] mov [och], al 481 ; movb (r5)+,och / pick up diagnostic character 482 0000027D 20C0 and al, al 483 0000027F 7418 jz short s5 484 ; beq 1f / 0 is end of line 485 sys _write, 1, och, 1 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000281 BB01000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000286 B9[6C0C0000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 0000028B BA01000000 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000290 B804000000 <1> mov eax, %1 99 00000295 CD30 <1> int 30h 486 ; mov $1,r0 / set for tty output 487 ; sys write; och; 1 / print it 488 00000297 EBDE jmp short s4 489 ;jmp short error 490 ; br error / continue to get characters 491 s5: ;1: 492 ;inc esi 493 ; inc r5 / inc r5 to point to return 494 ;;and si, 0FFFEh 495 ;shr esi, 1 496 ;shl esi, 1 497 ; bic $1,r5 / make it even 498 sys _seek, 0, 0, 2 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000299 BB00000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 0000029E B900000000 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 000002A3 BA02000000 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 000002A8 B813000000 <1> mov eax, %1 99 000002AD CD30 <1> int 30h 499 ; clr r0 / set for input 500 ; sys seek; 0; 2 / exit from runcom. skip to 501 ; / end of input file 502 000002AF C3 retn 503 ;; rts r5 ; unix v2 shell ; 29/05/2022 504 ;; (not in original unix v1 'sh.s') 505 506 chcom: ; / has no effect if tty input 507 ; mov (r5)+,r1 / glogin gchdir r1, bump r5 508 000002B0 BF[A1060000] mov edi, parbuf 509 ; mov $parbuf,r2 / command address r2 'login' 510 s6: ;1: 511 000002B5 AC lodsb 512 ; movb (r1)+,r0 / is this command 'chdir' 513 000002B6 AE scasb 514 ; cmpb (r2)+,r0 / compare command name byte 515 ; / with 'login' or 'chdir' 516 000002B7 7504 jne short s7 517 ; bne 1f / doesn't compare 518 000002B9 08C0 or al, al 519 ; tst r0 / is this 520 000002BB 75F8 jnz short s6 521 ; bne 1b / end of names 522 ; tst (r5)+ / yes, bump r5 again to execute 523 ; / login or chdir 524 s7: ;1: 525 000002BD C3 retn 526 ; rts r5 / no, return to exec command 527 528 putc: 529 000002BE 3C27 cmp al, 27h ; ' 530 ; cmp r0,$'' / single quote? 531 000002C0 740A je short pch1 532 ; beq 1f / yes 533 000002C2 3C22 cmp al, 22h ; " 534 ; cmp r0,$'" / double quote 535 000002C4 7406 je short pch1 536 ; beq 1f / yes 537 000002C6 247F and al, 7Fh 538 ; bic $!177,r0 / no, remove 200, if present 539 000002C8 8806 mov [esi], al 540 000002CA 46 inc esi 541 ; movb r0,(r3)+ / store character in parbuf 542 000002CB C3 retn 543 ; rts pc 544 pch1: ;1: 545 000002CC 50 push eax 546 ; mov r0,-(sp) / push quote mark onto stack 547 pch2: ;1: 548 000002CD E8B2010000 call getc 549 ; jsr pc,getc / get a quoted character 550 000002D2 3C0D cmp al, 0Dh 551 ;cmp al, 0Ah ; \n 552 ; cmp r0,$'\n / is it end or line 553 000002D4 750F jne short pch3 554 ; bne 2f / no 555 000002D6 BE[42060000] mov esi, msgImbalance 556 000002DB E881FFFFFF call error 557 ; jsr r5,error / yes, indicate missing 558 ; quote mark 559 ; <"' imbalance\n\0>; .even 560 000002E0 E9A2FDFFFF jmp newline 561 ; jmp newline / ask for new line 562 pch3: ;2: 563 000002E5 380424 cmp [esp], al 564 ; cmp r0,(sp) / is this closing quote mark 565 000002E8 7407 je short pch4 566 ; beq 1f / yes 567 000002EA 247F and al, 7Fh 568 ; bic $!177,r0 / no, strip off 200 569 ; if present 570 000002EC 8806 mov [esi], al 571 000002EE 46 inc esi 572 ; movb r0,(r3)+ / store quoted character 573 ; in parbuf 574 000002EF EBDC jmp short pch2 575 ; br 1b / continue 576 pch4: ;1: 577 000002F1 58 pop eax 578 ; tst (sp)+ / pop quote mark off stack 579 000002F2 C3 retn 580 ; rts pc / return 581 582 ; / thp`e new process 583 584 newproc: 585 000002F3 8B35[900A0000] mov esi, [infile] 586 000002F9 09F6 or esi, esi 587 000002FB 744F jz short np2 588 ; mov infile,0f / move pointer to new file name 589 ; beq 1f / branch if no alternate read file given 590 000002FD 803E00 cmp byte [esi], 0 591 ; tstb *0f 592 00000300 7639 jna short np1 593 ; beq 3f / branch if no file name given 594 595 ; 15/06/2022 - Retro UNIX 386 v1.2 596 sys _stat, esi, stbuf ; get file (inode) status 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000302 89F3 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000304 B9[740C0000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000309 B812000000 <1> mov eax, %1 99 0000030E CD30 <1> int 30h 597 00000310 7229 jc short np1 598 ; 599 00000312 A0[770C0000] mov al, [stbuf+stat.mode+1] 600 00000317 A880 test al, 80h ; regular file ? 601 00000319 7504 jnz short np13 ; yes 602 603 ; Character devices must not be input/source 604 0000031B A840 test al, 40h ; block device ? 605 0000031D 741C jz short np1 ; no, character device ! 606 ; 607 ; (disk blocks may be used as input source) 608 ; ((pseudo tty input redirection not allowed)) 609 np13: 610 sys _close, 0 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 0000031F BB00000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000324 B806000000 <1> mov eax, %1 99 00000329 CD30 <1> int 30h 611 ; clr r0 / set tty input file name 612 ; sys close / close it 613 sys _open, esi, 0 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 0000032B 89F3 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 0000032D B900000000 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000332 B805000000 <1> mov eax, %1 99 00000337 CD30 <1> int 30h 614 ; sys open; 0:..; 0 / open new input file 615 ; for reading 616 00000339 7311 jnc short np2 617 ; bcc 1f / branch if input file ok 618 np1: ;3: 619 0000033B BE[4F060000] mov esi, msgInputFile 620 00000340 E81CFFFFFF call error 621 ; jsr r5,error / file not ok, print error 622 ; ; .even / this diagnostic 623 sys _exit 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000345 B801000000 <1> mov eax, %1 99 0000034A CD30 <1> int 30h 624 ; sys exit / terminate this process 625 ; and make parent sh 626 np2: ;1: 627 0000034C 8B35[940A0000] mov esi, [outfile] 628 ; mov outfile,r2 / more pointer to new file name 629 00000352 21F6 and esi, esi 630 ;jz short np6 631 ; beq 1f / branch if no alternate write file 632 ; 14/06/2022 633 00000354 7505 jnz short np11 634 00000356 E99B000000 jmp np6 635 np11: 636 ; 27/12/2015 637 0000035B 803E00 cmp byte [esi], 0 638 0000035E 7636 jna short np4 639 ; 640 ;cmp byte [esi], '>' 641 ; cmpb (r2),$'> / is > at beqinning of file name? 642 ;jne short np3 643 ; bne 4f / branch if it isn't 644 ;inc esi 645 ; inc r2 / yes, increment pointer 646 647 ; 14/06/2022 - Retro UNIX 386 v1.2 648 ; 27/12/2015 649 ;cmp byte [FCAT], '>' ; '>>' 650 ;jne short np3 651 652 ; 14/06/2022 - Retro UNIX 386 v1.2 653 sys _stat, esi, stbuf ; get file (inode) status 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000360 89F3 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000362 B9[740C0000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000367 B812000000 <1> mov eax, %1 99 0000036C CD30 <1> int 30h 654 0000036E 7237 jc short np3 655 ; 656 00000370 A0[770C0000] mov al, byte [stbuf+stat.mode+1] 657 ; Block devices and dirs must not be target 658 00000375 A840 test al, 40h ; block device or directory ? 659 00000377 751D jnz short np4 ; yes, error 660 661 00000379 A880 test al, 80h ; regular file ? 662 0000037B 7409 jz short np12 ; no, character device 663 664 0000037D 803D[71060000]3E cmp byte [FCAT], '>' ; '>>' ? 665 00000384 7521 jne short np3 ; no, '>' 666 ; yes, '>>' 667 np12: 668 sys _open, esi, 1 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000386 89F3 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000388 B901000000 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 0000038D B805000000 <1> mov eax, %1 99 00000392 CD30 <1> int 30h 669 ; mov r2,0f 670 ; sys open; 0:..; 1 / open file for writing 671 00000394 7321 jnc short np5 672 ; bec 3f / if no error 673 674 ; 14/06/2022 675 np4: ;2: 676 00000396 BE[5A060000] mov esi, msgOutputFile 677 0000039B E8C1FEFFFF call error 678 ; jsr r5,error 679 ; ; .even 680 sys _exit 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 000003A0 B801000000 <1> mov eax, %1 99 000003A5 CD30 <1> int 30h 681 ; sys exit 682 683 ;jmp short np4 684 685 np3: ;4: 686 ;sys _creat, esi, 15 ; Decimal 15 = Octal 17 687 ; 13/06/2022 - Retro UNIX 386 1.2 (runix v2 inode) 688 sys _creat, esi, 01B6h ; Decimal 438 = Octal 666 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 000003A7 89F3 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 000003A9 B9B6010000 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 000003AE B808000000 <1> mov eax, %1 99 000003B3 CD30 <1> int 30h 689 ; mov r2,0f 690 ; sys creat; 0:..; 17 / create new file 691 ; with this name 692 ;jnc short np5 693 ; bec 3f / branch if no error 694 ; 14/06/2022 695 000003B5 72DF jc short np4 696 697 np5: ;3: 698 sys _close, eax 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 000003B7 89C3 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 000003B9 B806000000 <1> mov eax, %1 99 000003BE CD30 <1> int 30h 699 ; sys close / close the new write file 700 ; mov r2,0f / move new name to open 701 np10: 702 sys _close, 1 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 000003C0 BB01000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 000003C5 B806000000 <1> mov eax, %1 99 000003CA CD30 <1> int 30h 703 ; mov $1,r0 / set tty file name 704 ; sys close / close it 705 sys _open, esi, 1 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 000003CC 89F3 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 000003CE B901000000 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 000003D3 B805000000 <1> mov eax, %1 99 000003D8 CD30 <1> int 30h 706 ; sys open; 0:..; 1 / open new output file, 707 ; /it now has file descriptor 1 708 ; 27/12/2015 709 000003DA 803D[71060000]3E cmp byte [FCAT], '>' ; '>>' 710 000003E1 7513 jne short np6 711 ; 712 sys _seek, eax, 0, 2 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 000003E3 89C3 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 000003E5 B900000000 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 000003EA BA02000000 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 000003EF B813000000 <1> mov eax, %1 99 000003F4 CD30 <1> int 30h 713 ; sys seek; 0; 2 / set pointer to 714 ; current end of file 715 np6: ;1: 716 000003F6 803D[8E0A0000]00 cmp byte [glflag], 0 717 ; tst glflag / was *, ? or [ encountered? 718 000003FD 7739 ja short np9 719 ; bne 1f / yes 720 sys _exec, parbuf, parp 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 000003FF BB[A1060000] <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000404 B9[9C0A0000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000409 B80B000000 <1> mov eax, %1 99 0000040E CD30 <1> int 30h 721 ; sys exec; parbuf; parp / no, execute 722 ; this command 723 sys _exec, binpb, parp 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000410 BB[9C060000] <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000415 B9[9C0A0000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 0000041A B80B000000 <1> mov eax, %1 99 0000041F CD30 <1> int 30h 724 ; sys exec; binpb; parp / or /bin/this command 725 726 ;------ 29/05/2022 - unix v2 shell 727 ; (source code from disassembled /bin/sh binary) 728 ; following part is not existing in v2 shell 729 ; 730 ;np7: ;2: 731 ; sys _stat, binpb, inbuf 732 ; ; sys stat; binpb; inbuf / if can't execute 733 ; ; / does it exist? 734 ; jc short np8 735 ; ; bes 2f / branch if it doesn't 736 ; mov esi, parp-4 737 ; mov dword [esi], shell 738 ; ; mov $shell,parp-2 / does exist, 739 ; ; not executable 740 ; mov eax, binpb 741 ; mov [parp], eax 742 ; ; mov $binpb,parp / so it must be 743 ; sys _exec, shell, esi 744 ; ; sys exec; shell; parp-2 / a command file, 745 ; ; / get it with sh /bin/x (if x name of file) 746 ;------ 747 748 np8: ;2: 749 00000421 BE[66060000] mov esi, msgNoCmd 750 00000426 E836FEFFFF call error 751 ; jsr r5,error / a return for exec 752 ; is the diagnostic 753 ; ; .even 754 0000042B 8B25[6E0C0000] mov esp, [shellarg] 755 sys _exit 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000431 B801000000 <1> mov eax, %1 99 00000436 CD30 <1> int 30h 756 ; sys exit 757 np9: ;1: 758 00000438 BE[980A0000] mov esi, parp-4 759 0000043D C706[92060000] mov dword [esi], glob 760 ; mov $glob,parp-2 / prepare to process *,? 761 sys _exec, glob, esi 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000443 BB[92060000] <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000448 89F1 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 0000044A B80B000000 <1> mov eax, %1 99 0000044F CD30 <1> int 30h 762 ; sys exec; glob; parp-2 763 ; / execute modified command 764 00000451 EBCE jmp short np8 765 ; br 2b 766 767 delim: 768 00000453 3C0D cmp al, 0Dh ; carriage return 769 00000455 741A je short dlim2 770 ;cmp al, 0Ah 771 ; cmp r0,$'\n / is character a newline 772 ;je short dlim2 773 ; beq 1f 774 00000457 3C26 cmp al, '&' 775 ;cmp r0,$'& / is it & 776 00000459 7416 je short dlim2 777 ; beq 1f / yes 778 0000045B 3C3B cmp al, ';' 779 ; cmp r0,$'; / is it ; 780 0000045D 7412 je short dlim2 781 ; beq 1f / yes 782 0000045F 3C3F cmp al, '?' 783 ; cmp r0,$'? / is it ? 784 00000461 7408 je short dlim1 785 ; beq 3f 786 ; 787 ;------ 29/05/2022 - unix v2 shell 788 ; (source code from disassembled /bin/sh binary) 789 00000463 3C2A cmp al, '*' 790 ; cmp r0,$'* / is it * 791 00000465 7404 je short dlim1 792 ; beq 3f 793 794 00000467 3C5B cmp al, '[' 795 ; cmp r0,$'[ / is it beginning of character string 796 ; / (for glob) 797 00000469 7506 jne short dlim2 798 ; bne 2f 799 dlim1: ;3: 800 0000046B FE05[8E0A0000] inc byte [glflag] 801 ; inc glflag / ? or * or [ set flag 802 ;2: 803 ;tst (r5)+ / bump to process all except \n,;,& 804 dlim2: ;1: 805 ; zf = 1 if the char is '\n' or ';' or '&' 806 00000471 C3 retn 807 ; rts r5 808 blank: 809 00000472 E80D000000 call getc 810 ; jsr pc,getc / get next character 811 00000477 3C20 cmp al, 20h 812 ; cmp $' ,r0 / leading blanks 813 00000479 74F7 je short blank 814 ; beq blank / yes, 'squeeze out' 815 0000047B 3C8D cmp al, 8Dh ; 80h + 0Dh 816 ;cmp al, 8Ah ; 80h + 0Ah 817 0000047D 74F3 je short blank 818 ; cmp r0,$200+'\n / new-line preceded by ; is translated 820 ; beq blank / into blank 821 ; 28/12/2015 822 0000047F 3C0A cmp al, 0Ah 823 00000481 74EF je short blank 824 ; 825 00000483 C3 retn 826 ; rts pc 827 getc: 828 00000484 833D[8A0A0000]00 cmp dword [param], 0 829 ; tst param / are we substituting for $n 830 0000048B 773D ja short gch3 831 ; bne 2f/ yes 832 gch0: 833 0000048D 8B1D[640C0000] mov ebx, [inbufp] 834 ; mov inbufp,r1 / no, move normal input pointer to r1 835 s8: 836 00000493 3B1D[680C0000] cmp ebx, [einbuf] 837 ; cmp r1,einbuf / end of input line? 838 00000499 7207 jb short gch1 839 ; bne 1f / no 840 0000049B E877000000 call getbuf 841 ; jsr pc,getbuf / yes, put next console line 842 ; in buffer 843 000004A0 EBEB jmp short gch0 844 ; br getc 845 gch1: ;1: 846 000004A2 8A03 mov al, [ebx] 847 000004A4 43 inc ebx 848 ; movb (r1)+,r0 / move byte from input buffer to r0 849 000004A5 891D[640C0000] mov [inbufp], ebx 850 ; mov r1,inbufp / increment routine 851 000004AB 0A05[720C0000] or al, [escap] 852 ;or ax, escap 853 ; bis escap,r0 / if last character was \ this adds 854 ; / 200 to current character 855 ;mov byte [escap], 0 856 ;mov word [escap], 0 857 ; clr escap / clear, so escap normally zero 858 000004B1 3C5C cmp al, '\' 859 ; cmp r0,$'\\ / note that \\ is equal \ in as 860 000004B3 740C je short gch2 861 ; beq 1f 862 000004B5 C605[720C0000]00 mov byte [escap], 0 863 000004BC 3C24 cmp al, '$' 864 ; cmp r0,$'$ / is it $ 865 000004BE 7429 je short gch5 866 ; beq 3f / yes 867 000004C0 C3 retn 868 ; rts pc / no 869 gch2: ;1: 870 000004C1 C605[720C0000]80 mov byte [escap], 80h 871 ;mov word [escap], 128 872 ; mov $200,escap / mark presence of \ in command line 873 000004C8 EBC9 jmp short s8 874 ;jmp short gch0 875 ; br getc / get next character 876 gch3: ;2: 877 000004CA 8B1D[8A0A0000] mov ebx, [param] 878 000004D0 8A03 mov al, [ebx] 879 ; movb *param,r0 / pick up substitution character 880 ; / put in r0 881 000004D2 08C0 or al, al 882 000004D4 7407 jz short gch4 883 ; beq 1f / if end of substitution arg, branch 884 000004D6 FF05[8A0A0000] inc dword [param] 885 ; inc param / if not end, set for next character 886 000004DC C3 retn 887 ; rts pc / return as though character in ro is normal 888 ; / input 889 gch4: ;1: 890 000004DD C705[8A0A0000]0000- mov dword [param], 0 890 000004E5 0000 891 ; clr param / unset substitution pointer 892 000004E7 EBA4 jmp short gch0 893 ; br getc / get next char in normal input 894 gch5: ;3: 895 000004E9 E89FFFFFFF call gch0 896 ;call getc 897 ; jsr pc,getc / get digit after $ 898 000004EE 2C30 sub al, '0' 899 ; sub $'0,r0 / strip off zone bits 900 000004F0 3C09 cmp al, 9 901 ; cmp r0,$9. / compare with digit 9 902 000004F2 7602 jna short gch6 903 ; blos 1f / less than or equal 9 904 000004F4 B009 mov al, 9 905 ; mov $9.,r0 / if larger than 9, force 9 906 gch6: ;1: 907 000004F6 8B1D[6E0C0000] mov ebx, [shellarg] 908 ; mov shellarg,r1 / get pointer to stack for 909 ; / this call of shell 910 000004FC 0FB6C0 movzx eax, al ; al->eax 911 000004FF FEC0 inc al 912 ;inc eax 913 ; inc r0 / digit +1 914 00000501 3B03 cmp eax, [ebx] 915 ; cmp r0,(r1) / is it less than # of args 916 ; in this call 917 00000503 7388 jnb short gch0 918 ; bge getc / no, ignore it. so this $n is not replaced 919 00000505 C0E002 shl al, 2 ; multiply by 4 (24/08/2015) 920 ;shl al, 1 921 ;;shl ax, 1 922 ; asl r0 / yes, multiply by 2 (to skip words) 923 00000508 01C3 add ebx, eax 924 ; add r1,r0 / form pointer to arg pointer (-2) 925 0000050A 8B4304 mov eax, [ebx+4] 926 0000050D A3[8A0A0000] mov [param], eax 927 ; mov 2(r0),param / move arg pointer to param 928 00000512 E96DFFFFFF jmp getc 929 ; br getc / go to get substitution arg for $n 930 getbuf: 931 00000517 B9[640B0000] mov ecx, inbuf 932 ; mov $inbuf,r0 / move input buffer address 933 0000051C 890D[640C0000] mov [inbufp], ecx 934 ; mov r0,inbufp / to input buffer pointer 935 00000522 890D[680C0000] mov [einbuf], ecx 936 ; mov r0,einbuf / and initialize pointer to end of 937 ; / character string 938 00000528 49 dec ecx 939 ; dec r0 / decrement pointer so can utilize normal 940 ; / 100p starting at 1f 941 ; mov r0,0f / initialize address for reading 1st char 942 00000529 BA01000000 mov edx, 1 943 gbuf0: ;1: 944 0000052E 41 inc ecx 945 ; inc 0f / this routine filles inbuf with line from 946 ; / console - if there is cnc 947 0000052F 51 push ecx 948 ; edx = 1 949 sys _read, 0, och 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000530 BB00000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000535 B9[6C0C0000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 0000053A B803000000 <1> mov eax, %1 99 0000053F CD30 <1> int 30h 950 00000541 59 pop ecx 951 ;xor ebx, ebx ; 0 952 ;sys _read ; sys _read, ebx, ecx, edx ; ebx = 0, edx = 1 953 ; sys read; 0:0; 1 / read next char into inbuf 954 00000542 7254 jc short xit1 ; 29/05/2022 955 ; bcs xit1 / error exit 956 00000544 21C0 and eax, eax 957 ; tst r0 / a zero input is end of file 958 00000546 7450 jz short xit1 ; 29/05/2022 959 ; beq xit1 / exit 960 00000548 FF05[680C0000] inc dword [einbuf] ; 08/04/2014 (24/08/2015, 32 bit) 961 0000054E A0[6C0C0000] mov al, [och] 962 00000553 803D[74060000]00 cmp byte [_at], 0 963 0000055A 7608 jna short gbuf1 964 0000055C 3C08 cmp al, 8 ; backspace 965 0000055E 746B je short gbuf3 966 00000560 3C7F cmp al, 127 ; delete 967 00000562 7460 je short gbuf6 ; 06/12/2013 968 gbuf1: 969 ;mov ebx, ecx 970 ;inc dword [einbuf] 971 ; inc einbuf / eventually einbuf points to \n 972 ; / (+1) of this line 973 00000564 81F9[640C0000] cmp ecx, inbuf + 256 974 ; cmp 0b,$inbuf+256. / have we exceeded 975 ; input buffer size 976 0000056A 732C jnb short xit1 ; 29/05/2022 977 ; bhis xit1 / if so, exit assume some sort of binary 978 ; 08/04/2014 979 0000056C 3C0D cmp al, 0Dh 980 0000056E 752F jne short gbuf8 981 00000570 8B1D[680C0000] mov ebx, [einbuf] 982 00000576 4B dec ebx 983 00000577 8803 mov [ebx], al 984 00000579 C3 retn 985 986 gbuf2: 987 ; 28/12/2015 988 0000057A 803D[74060000]00 cmp byte [_at], 0 989 00000581 76AB jna short gbuf0 ; 29/05/2022 990 gbuf7: 991 00000583 51 push ecx 992 ;mov [och], al 993 ; edx = 1 994 sys _write, 1, och 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 00000584 BB01000000 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 00000589 B9[6C0C0000] <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 0000058E B804000000 <1> mov eax, %1 99 00000593 CD30 <1> int 30h 995 ;sys _write, 1, och, 1 ; echo (write char on tty) 996 00000595 59 pop ecx 997 00000596 EB96 jmp short gbuf0 ; 29/05/2022 998 999 xit1: ; 29/05/2022 1000 sys _exit 85 <1> 86 <1> 87 <1> 88 <1> %if %0 >= 2 89 <1> mov ebx, %2 90 <1> %if %0 >= 3 91 <1> mov ecx, %3 92 <1> 93 <1> %if %0 >= 4 94 <1> mov edx, %4 95 <1> %endif 96 <1> %endif 97 <1> %endif 98 00000598 B801000000 <1> mov eax, %1 99 0000059D CD30 <1> int 30h 1001 ; sys exit 1002 1003 gbuf8: 1004 0000059F 89CB mov ebx, ecx 1005 000005A1 8803 mov [ebx], al 1006 ;cmp al, 0Ah ; \n 1007 ; cmpb *0b,$'\n / end of line? 1008 ;je short gbuf5 1009 ;jne short gbuf1 1010 ; bne 1b / no, go to get next char 1011 ;cmp al, 0Dh ; ENTER 1012 ;je short gbuf5 1013 000005A3 803D[74060000]00 cmp byte [_at], 0 ; at > 0 --> tty input 1014 000005AA 7682 jna short gbuf0 1015 000005AC 3C1B cmp al, 1Bh ; ESC 1016 000005AE 75CA jne short gbuf2 1017 000005B0 B8[640B0000] mov eax, inbuf 1018 000005B5 A3[640C0000] mov [inbufp], eax 1019 000005BA A3[680C0000] mov [einbuf], eax 1020 000005BF E9CCFAFFFF jmp nl ; cancel current command, new line 1021 1022 ; 29/05/2022 1023 ;gbuf2: 1024 ; ; 28/12/2015 1025 ; cmp byte [_at], 0 1026 ; jna gbuf0 1027 ;gbuf7: 1028 ; push ecx 1029 ; ;mov [och], al 1030 ; ; edx = 1 1031 ; sys _write, 1, och 1032 ; ;sys _write, 1, och, 1 ; echo (write char on tty) 1033 ; pop ecx 1034 ; jmp gbuf0 1035 1036 gbuf6: ; DELETE key -> BACKSPACE key 1037 ;mov al, 8 1038 000005C4 C605[6C0C0000]08 mov byte [och], 8 ; 06/12/2013 1039 gbuf3: 1040 ; 08/04/2014 1041 000005CB FF0D[680C0000] dec dword [einbuf] ; (24/08/2015, 32 bit code) 1042 ; 12/12/2013 1043 000005D1 49 dec ecx 1044 000005D2 81F9[640B0000] cmp ecx, inbuf 1045 000005D8 7203 jb short gbuf4 1046 000005DA 49 dec ecx 1047 ; 08/04/2014 1048 ;jmp short gbuf2 1049 000005DB EBA6 jmp short gbuf7 1050 gbuf4: 1051 ;mov al, 7 1052 000005DD C605[6C0C0000]07 mov byte [och], 07h ; beep 1053 ; 08/04/2014 1054 ;jmp short gbuf2 1055 000005E4 EB9D jmp short gbuf7 1056 ;gbuf5: 1057 ; retn 1058 ; rts pc / yes, return 1059 1060 ; 29/05/2022 1061 ;xit1: 1062 ; sys _exit 1063 ; ; sys exit 1064 1065 ;----------------------------------------------------------------- 1066 ; data - initialized data 1067 ;----------------------------------------------------------------- 1068 1069 ; /// Messages 1070 1071 000005E6 0D0A msg_unix_sh: db 0Dh, 0Ah 1072 000005E8 526574726F20556E69- db 'Retro Unix 386 v1.2 - shell' 1072 000005F1 78203338362076312E- 1072 000005FA 32202D207368656C6C 1073 ;db 0Dh, 0Ah 1074 msgsh_size equ $ - msg_unix_sh 1075 ;db 0 1076 00000603 31352F30362F323032- db '15/06/2022' 1076 0000060C 32 1077 0000060D 0D0A00 nextline: db 0Dh, 0Ah, 0 1078 ;Error messages: 1079 00000610 496E707574206E6F74- msgNotFound: db 'Input not found', 0 1079 00000619 20666F756E6400 1080 00000620 41726720636F756E74- msgArgCount: db 'Arg count', 0 1080 00000629 00 1081 0000062A 426164206469726563- msgBadDir: db 'Bad directory', 0 1081 00000633 746F727900 1082 00000638 54727920616761696E- msgTryAgain: db 'Try again', 0 1082 00000641 00 1083 00000642 222720696D62616C61- msgImbalance: db 22h, 27h, 20h, 'imbalance', 0 1083 0000064B 6E636500 1084 0000064F 496E7075742066696C- msgInputFile: db 'Input file', 0 1084 00000658 6500 1085 0000065A 4F7574707574206669- msgOutputFile: db 'Output file', 0 1085 00000663 6C6500 1086 00000666 4E6F20636F6D6D616E- msgNoCmd: db 'No command', 0 1086 0000066F 6400 1087 1088 ; /// Commands, files, parameters 1089 1090 ; 27/12/2015 1091 FCAT: ; '>>' 1092 00000671 00 db 0 1093 1094 ;quest: 1095 ;db '?', 0Dh, 0Ah 1096 ; 1097 1098 prompt: 1099 00000672 0D0A db 0Dh, 0Ah 1100 _at: 1101 00000674 4020 db '@ ' 1102 ;<@ > 1103 p_size equ $ - prompt 1104 1105 00000676 6563686F00 qecho: db 'echo', 0 1106 ; 1107 0000067B 636400 qcd: db 'cd', 0 1108 ; 1109 qchdir: 1110 0000067E 636864697200 db 'chdir', 0 1111 ; 1112 glogin: 1113 00000684 6C6F67696E00 db 'login', 0 1114 ; 1115 shell: 1116 0000068A 2F62696E2F736800 db '/bin/sh', 0 1117 ; 1118 glob: 1119 00000692 2F6574632F676C6F62- db '/etc/glob', 0 1119 0000069B 00 1120 ; 1121 binpb: 1122 0000069C 2F62696E2F db '/bin/' 1123 ; 1124 1125 ;----------------------------------------------------------------- 1126 ; bss - uninitialized data 1127 ;----------------------------------------------------------------- 1128 1129 bss_start: 1130 1131 ABSOLUTE bss_start 1132 1133 parbuf: 1134 000006A1 resb 1000 1135 ; .=.+1000. 1136 00000A89 ?? alignb 2 1137 ;.even 1138 param: 1139 00000A8A ???????? resd 1 1140 ;.=.+2 1141 glflag: 1142 00000A8E ?? resb 1 1143 00000A8F ?? resb 1 1144 ;.=.+2 1145 infile: 1146 00000A90 ???????? resd 1 1147 ; .=.+2 1148 outfile: 1149 00000A94 ???????? resd 1 1150 ;.=.+2 1151 ; parp-4 1152 00000A98 ???????? resd 1 1153 ;.=.+2 / room for glob 1154 parp: 1155 00000A9C resb 200 1156 ;.=.+200. 1157 inbuf: 1158 00000B64 resb 256 1159 ;.=.+256. 1160 ;escap: 1161 ;resw 1 1162 ;.=.+2 1163 inbufp: 1164 00000C64 ???????? resd 1 1165 ;.=.+2 1166 einbuf: 1167 00000C68 ???????? resd 1 1168 ;.=.+2 1169 och: 1170 00000C6C ?? resb 1 1171 00000C6D ?? resb 1 1172 ;.=.+2 1173 shellarg: 1174 00000C6E ???????? resd 1 1175 ;.=.+2 1176 escap: 1177 00000C72 ?? resb 1 1178 ; 1179 00000C73 ?? resb 1 1180 1181 stbuf: ; 14/06/2022 - Retro UNIX 386 v1.2 1182 00000C74 resb 66 ; sysstat output buffer 1183 1184 bss_end: 1185 1186 ; 29/05/2022 1187 ;----------------------------------------------------------------- 1188 ; Original UNIX v2 - shell - PDP-11 assembly source code (sh.s) 1189 ;----------------------------------------------------------------- 1190 ; UNIX V2 source code: see www.tuhs.org for details. 1191 ;----------------------------------------------------------------- 1192 ; /// Modified unix v1 shell (sh.s) source code by Erdogan Tan /// 1193 ;----------------------------------------------------------------- 1194 ; s2.tar.gz - \bin\sh 1195 ; 1196 ; Source code modified via disassembled unix v2 /bin/sh binary file 1197 ; Dissasembler: Hex-Rays Interactive Disassembler (IDA) 1198 ; 1199 ;/ sh -- command interpreter 1200 ; mov sp,r5 1201 ; mov r5,shellarg / save orig sp in shellarg 1202 ; cmpb *2(r5),$'- / was this sh called by init or login 1203 ; bne 2f / no 1204 ; sys intr; 0 / yes, turn off interrupts 1205 ; sys quit; 0 1206 ;2: 1207 ; sys getuid / who is user 1208 ; tst r0 / is it superuser 1209 ; bne 2f / no 1210 ; movb $'#,at / yes, set new prompt symbol 1211 ;2: 1212 ; cmp (r5),$1 / tty input? 1213 ; ble newline / yes, call with '-(or with no command 1214 ; / file name) 1215 ; clr r0 / no, set ttv 1216 ; sys close / close it 1217 ; mov 4(r5),0f / get new file name 1218 ; sys open; 0:..; 0 / open it 1219 ; bec 1f / branch if no error 1220 ; jsr r5,error / error in file name 1221 ; ; .even 1222 ; sys exit 1223 ;1: 1224 ; clr at / clear prompt character, if reading non-tty 1225 ; / input file 1226 ;newline: 1227 ; tst at / is there a prompt symbol 1228 ; beq newcom / no 1229 ; mov $1,r0 / yes 1230 ; sys write; at; 2. / print prompt 1231 ;newcom: 1232 ; mov shellarg,sp / 1233 ; mov $parbuf,r3 / initialize command list area 1234 ; mov $parp,r4 / initialize command list pointers 1235 ; clr infile / initialize alternate input 1236 ; clr outfile / initialize alternate output 1237 ; clr glflag / initialize global flag 1238 ;newarg: 1239 ; jsr pc,blank / squeeze out leading blanks 1240 ; jsr r5,delim / is new character a ; \n or & 1241 ; br 2f / yes 1242 ; mov r3,-(sp) / no, push arg pointer onto stack 1243 ; cmp r0,$'< / new input file? 1244 ; bne 1f / no 1245 ; mov (sp),infile / yes, save arg pointer 1246 ; clr (sp) / clear pointer 1247 ; br 3f 1248 ;1: 1249 ; cmp r0,$'> / new output file? 1250 ; bne newchar / no 1251 ; mov (sp),outfile / yes, save arg pointer 1252 ; clr (sp) / clear pointer 1253 ; br 3f 1254 ;newchar: 1255 ; cmp $' ,r0 / is character a blank 1256 ; beq 1f / branch if it is (blank as arg separator) 1257 ; cmp $'\n+200,r0 / treat \n preceded by ; beq 1f / as blank 1259 ; jsr pc,putc / put this character in parbuf list 1260 ;3: 1261 ; jsr pc,getc / get next character 1262 ; jsr r5,delim / is char a ; \n or &, 1263 ; br 1f / yes 1264 ; br newchar / no, start new character tests 1265 ;1: 1266 ; clrb (r3)+ / end name with \0 when read blank, or 1267 ; / delim 1268 ; mov (sp)+,(r4)+ / move arg ptr to parp location 1269 ; bne 1f / if (sp)=0, in file or out file points to arg 1270 ; tst -(r4) / so ignore dummy (0), in pointer list 1271 ;1: 1272 ; jsr r5,delim / is char a ; \n or &. 1273 ; br 2f / yes 1274 ; br newarg / no, start newarg processing 1275 ;2: 1276 ; clr (r4) / \n, &, or ; takes to here (end of arg list) 1277 ; / after 'delim' call 1278 ; mov r0,-(sp) / save delimiter in stack 1279 ; jsr pc,docom / go to exec command in parbuf 1280 ; cmpb (sp),$'& / get a new command without wait? 1281 ; beq newcom / yes 1282 ; tst r1 / was chdir just executed or line ended with 1283 ; / ampersand? 1284 ; beq 2f / yes 1285 ;1: 1286 ; sys wait / no, wait for new process to terminate 1287 ; / command executed) 1288 ; bcs 2f / no, children not previously waited for 1289 ; cmp r0,r1 / is this my child 1290 ; bne 1b 1291 ;2: 1292 ; cmp (sp),$'\n / was delimiter a new line 1293 ; beq newline / yes 1294 ; br newcom / no, pick up next command 1295 ;docom: 1296 ; sub $parp,r4 / out arg count in r4 1297 ; bne 1f / any arguments? 1298 ; clr r1 / no, line ended with ampersand 1299 ; rts pc / return from call 1300 ;1: 1301 ; jsr r5,chcom; qchdir / is command chdir? 1302 ; br 2f / command not chdir 1303 ; cmp r4,$4 / prepare to exec chdir, 4=arg count x 2 1304 ; beq 3f 1305 ; jsr r5,error / go to print error 1306 ; ; .even 1307 ; br 4f 1308 ;3: 1309 ; mov parp+2,0f / more directory name to sys coll 1310 ; sys chdir; 0:0 / exec chdir 1311 ; bec 4f / no error exit 1312 ; jsr r5,error / go to print error 1313 ; ; .even / this diagnostic 1314 ;4: 1315 ; clr r1 / set r1 to zero to dkip wait 1316 ; rts pc / and return 1317 ;2: 1318 ; jsr r5,chcom; glogin / is command login? 1319 ; br 2f / not loqin, go to fork 1320 ; sys exec; parbuf; parp / exec login 1321 ; sys exec; binpb; parp / or /bin/login 1322 ;2: / no error return?? 1323 ; sys fork / generate sh child process for command 1324 ; br newproc / exec command with new process 1325 ; bec 1f / no error exit, old orocess 1326 ; jsr r5,error / go to print error 1327 ; ; .even / this diaonostic 1328 ; jmp newline / and return for next try 1329 ;1: 1330 ; mov r0,r1 / save id of child sh 1331 ; rts pc / return to "jsr pc, docom" call in parent sh 1332 ; 1333 ;error: 1334 ; movb (r5)+,och / pick up diagnostic character 1335 ; beq 1f / 0 is end of line 1336 ; mov $1,r0 / set for tty output 1337 ; sys write; och; 1 / print it 1338 ; br error / continue to get characters 1339 ;1: 1340 ; inc r5 / inc r5 to point to return 1341 ; bic $1,r5 / make it even 1342 ; clr r0 / set for input 1343 ; sys seek; 0; 2 / exit from runcom. skip to end of 1344 ; / input file 1345 ; 1346 ;/------ 29/05/2022 - unix v2 shell 1347 ;/ (source code from disassembled /bin/sh binary) 1348 ; rts r5 1349 ; 1350 ;chcom: / has no effect if tty input 1351 ; mov (r5)+,r1 / glogin gchdir r1, bump r5 1352 ; mov $parbuf,r2 / command address r2 'login' 1353 ;1: 1354 ; movb (r1)+,r0 / is this command 'chdir' 1355 ; cmpb (r2)+,r0 / compare command name byte with 'login' 1356 ; / or 'chdir' 1357 ; bne 1f / doesn't compare 1358 ; tst r0 / is this 1359 ; bne 1b / end of names 1360 ; tst (r5)+ / yes, bump r5 again to execute login 1361 ; / chdir 1362 ;1: 1363 ; rts r5 / no, return to exec command 1364 ; 1365 ;putc: 1366 ; cmp r0,$'' / single quote? 1367 ; beq 1f / yes 1368 ; cmp r0,$'" / double quote 1369 ; beq 1f / yes 1370 ; bic $!177,r0 / no, remove 200, if present 1371 ; movb r0,(r3)+ / store character in parbuf 1372 ; rts pc 1373 ;1: 1374 ; mov r0,-(sp) / push quote mark onto stack 1375 ;1: 1376 ; jsr pc,getc / get a quoted character 1377 ; cmp r0,$'\n / is it end or line 1378 ; bne 2f / no 1379 ; jsr r5,error / yes, indicate missing quote mark 1380 ; <"' imbalance\n\0>; .even 1381 ; jmp newline / ask for new line 1382 ;2: 1383 ; cmp r0,(sp) / is this closing quote mark 1384 ; beq 1f / yes 1385 ; bic $!177,r0 / no, strip off 200 if present 1386 ; movb r0,(r3)+ / store quoted character in parbuf 1387 ; br 1b / continue 1388 ;1: 1389 ; tst (sp)+ / pop quote mark off stack 1390 ; rts pc / return 1391 ; 1392 ;/ thp`e new process 1393 ; 1394 ;newproc: 1395 ; mov infile,0f / move pointer to new file name 1396 ; beq 1f / branch if no alternate read file given 1397 ; tstb *0f 1398 ; beq 3f / branch if no file name miven 1399 ; clr r0 / set tty input file name 1400 ; sys close / close it 1401 ; sys open; 0:..; 0 / open new input file for reading 1402 ; bcc 1f / branch if input file ok 1403 ;3: 1404 ; jsr r5,error / file not ok, print error 1405 ; ; .even / this diagnostic 1406 ; sys exit / terminate this process and make parent sh 1407 ;1: 1408 ; mov outfile,r2 / more pointer to new file name 1409 ; beq 1f / branch if no alternate write file 1410 ; cmpb (r2),$'> / is > at beqinning of file name? 1411 ; bne 4f / branch if it isn't 1412 ; inc r2 / yes, increment pointer 1413 ; mov r2,0f 1414 ; sys open; 0:..; 1 / open file for writing 1415 ; bec 3f / if no error 1416 ;4: 1417 ; mov r2,0f 1418 ; sys creat; 0:..; 17 / create new file with this name 1419 ; bec 3f / branch if no error 1420 ;2: 1421 ; jsr r5,error 1422 ; ; .even 1423 ; sys exit 1424 ;3: 1425 ; sys close / close the new write file 1426 ; mov r2,0f / move new name to open 1427 ; mov $1,r0 / set ttv file name 1428 ; sys close / close it 1429 ; sys open; 0:..; 1 / open new output file, it now has 1430 ; / file descriptor 1 1431 ; sys seek; 0; 2 / set pointer to current end of file 1432 ;1: 1433 ; tst glflag / was *, ? or [ encountered? 1434 ; bne 1f / yes 1435 ; sys exec; parbuf; parp / no, execute this commend 1436 ; sys exec; binpb; parp / or /bin/this command 1437 ; 1438 ;/------ 29/05/2022 - unix v2 shell 1439 ;/ (source code from disassembled /bin/sh binary) 1440 ;/ following part is not existing in v2 shell 1441 ; 1442 ;/2: 1443 ;/ sys stat; binpb; inbuf / if can't execute does it 1444 ;/ / exist? 1445 ;/ bes 2f / branch if it doesn't 1446 ;/ mov $shell,parp-2 / does exist, not executable 1447 ;/ mov $binpb,parp / so it must be 1448 ;/ sys exec; shell; parp-2 / a command file, get it with 1449 ;/ / sh /bin/x (if x name of file) 1450 ;/------ 1451 ;2: 1452 ; jsr r5,error / a return for exec is the diagnostic 1453 ; ; .even 1454 ; sys exit 1455 ;1: 1456 ; mov $glob,parp-2 / prepare to process *,? 1457 ; sys exec; glob; parp-2 / execute modified command 1458 ; br 2b 1459 ; 1460 ;delim: 1461 ; cmp r0,$'\n / is character a newline 1462 ; beq 1f 1463 ; cmp r0,$'& / is it & 1464 ; beq 1f / yes 1465 ; cmp r0,$'; / is it ; 1466 ; beq 1f / yes 1467 ; cmp r0,$'? / is it ? 1468 ; beq 3f 1469 ; 1470 ;/------ 29/05/2022 - unix v2 shell 1471 ;/ (source code from disassembled /bin/sh binary) 1472 ; cmp r0,$'* / is it * 1473 ; beq 3f 1474 ; 1475 ; cmp r0,$'[ / is it beginning of character string 1476 ; / (for glob) 1477 ; bne 2f 1478 ;3: 1479 ; inc glflag / ? or * or [ set flag 1480 ;2: 1481 ; tst (r5)+ / bump to process all except \n,;,& 1482 ;1: 1483 ; rts r5 1484 ; 1485 ;blank: 1486 ; jsr pc,getc / get next character 1487 ; cmp $' ,r0 / leading blanks 1488 ; beq blank / yes, 'squeeze out' 1489 ; cmp r0,$200+'\n / new-line preceded by \ is translated 1490 ; beq blank / into blank 1491 ; rts pc 1492 ;getc: 1493 ; tst param / are we substituting for $n 1494 ; bne 2f/ yes 1495 ; mov inbufp,r1 / no, move normal input pointer to r1 1496 ; cmp r1,einbuf / end of input line? 1497 ; bne 1f / no 1498 ; jsr pc,getbuf / yes, put next console line in buffer 1499 ; br getc 1500 ;1: 1501 ; movb (r1)+,r0 / move byte from input buffer to r0 1502 ; mov r1,inbufp / increment routine 1503 ; bis escap,r0 / if last character was \ this adds 1504 ; / 200 to current character 1505 ; clr escap / clear, so escap normally zero 1506 ; cmp r0,$'\\ / note that \\ is equal \ in as 1507 ; beq 1f 1508 ; cmp r0,$'$ / is it $ 1509 ; beq 3f / yes 1510 ; rts pc / no 1511 ;1: 1512 ; mov $200,escap / mark presence of \ in command line 1513 ; br getc / get next character 1514 ;2: 1515 ; movb *param,r0 / pick up substitution character put in 1516 ; / r0 1517 ; beq 1f / if end of substitution arg, branch 1518 ; inc param / if not end, set for next character 1519 ; rts pc / return as though character in ro is normal 1520 ; / input 1521 ;1: 1522 ; clr param / unset substitution pointer 1523 ; br getc / get next char in normal input 1524 ;3: 1525 ; jsr pc,getc / get digit after $ 1526 ; sub $'0,r0 / strip off zone bits 1527 ; cmp r0,$9. / compare with digit 9 1528 ; blos 1f / less than or equal 9 1529 ; mov $9.,r0 / if larger than 9, force 9 1530 ;1: 1531 ; mov shellarg,r1 / get pointer to stack for 1532 ; / this call of shell 1533 ; inc r0 / digit +1 1534 ; cmp r0,(r1) / is it less than # of args in this call 1535 ; bge getc / no, ignore it. so this $n is not replaced 1536 ; asl r0 / yes, multiply by 2 (to skip words) 1537 ; add r1,r0 / form pointer to arg pointer (-2) 1538 ; mov 2(r0),param / move arg pointer to param 1539 ; br getc / go to get substitution arg for $n 1540 ;getbuf: 1541 ; mov $inbuf,r0 / move input buffer address 1542 ; mov r0,inbufp / to input buffer pointer 1543 ; mov r0,einbuf / and initialize pointer to end of 1544 ; / character string 1545 ; dec r0 / decrement pointer so can utilize normal 1546 ; / 100p starting at 1f 1547 ; mov r0,0f / initialize address for reading 1st char 1548 ;1: 1549 ; inc 0f / this routine filles inbuf with line from 1550 ; / console - if there is cnc 1551 ; clr r0 / set for tty input 1552 ; sys read; 0:0; 1 / read next char into inbuf 1553 ; bcs xit1 / error exit 1554 ; tst r0 / a zero input is end of file 1555 ; beq xit1 / exit 1556 ; inc einbuf / eventually einbuf points to \n 1557 ; / (+1) of this line 1558 ; cmp 0b,$inbuf+256. / have we exceeded input buffer size 1559 ; bhis xit1 / if so, exit assume some sort of binary 1560 ; cmpb *0b,$'\n / end of line? 1561 ; bne 1b / no, go to get next char 1562 ; rts pc / yes, return 1563 ; 1564 ;xit1: 1565 ; sys exit 1566 ; 1567 ;quest: 1568 ; 1569 ; 1570 ;at: 1571 ; <@ > 1572 ; 1573 ;qchdir: 1574 ; 1575 ;glogin: 1576 ; 1577 ;shell: 1578 ; 1579 ;glob: 1580 ; 1581 ;binpb: 1582 ; 1583 ;parbuf: .=.+1000. 1584 ; .even 1585 ;param: .=.+2 1586 ;glflag: .=.+2 1587 ;infile: .=.+2 1588 ;outfile:.=.+2 1589 ; .=.+2 / room for glob 1590 ;parp: .=.+200. 1591 ;inbuf: .=.+256. 1592 ;escap: .=.+2 1593 ;inbufp: .=.+2 1594 ;einbuf: .=.+2 1595 ;och: .=.+2 1596 ;shellarg:.=.+2 1597 1598 ; 29/05/2022 1599 ;----------------------------------------------------------------- 1600 ; Original UNIX v1 - shell - PDP-11 assembly source code (sh.s) 1601 ;----------------------------------------------------------------- 1602 ; UNIX V1 source code: see www.tuhs.org for details. 1603 ;----------------------------------------------------------------- 1604 ; PreliminaryUnixImplementationDocument_Jun72.pdf - Section: E11 1605 ;----------------------------------------------------------------- 1606 ; https://minnie.tuhs.org/cgi-bin/utree.pl?file=V1/sh.s 1607 ; 1608 ;/ sh -- command interpreter 1609 ; mov sp,r5 1610 ; mov r5,shellarg / save orig sp in shellarg 1611 ; cmpb *2(r5),$'- / was this sh called by init or login 1612 ; bne 2f / no 1613 ; sys intr; 0 / yes, turn off interrupts 1614 ; sys quit; 0 1615 ;2: 1616 ; sys getuid / who is user 1617 ; tst r0 / is it superuser 1618 ; bne 2f / no 1619 ; movb $'#,at / yes, set new prompt symbol 1620 ;2: 1621 ; cmp (r5),$1 / tty input? 1622 ; ble newline / yes, call with '-(or with no command 1623 ; / file name) 1624 ; clr r0 / no, set ttv 1625 ; sys close / close it 1626 ; mov 4(r5),0f / get new file name 1627 ; sys open; 0:..; 0 / open it 1628 ; bec 1f / branch if no error 1629 ; jsr r5,error / error in file name 1630 ; ; .even 1631 ; sys exit 1632 ;1: 1633 ; clr at / clear prompt character, if reading non-tty 1634 ; / input file 1635 ;newline: 1636 ; tst at / is there a prompt symbol 1637 ; beq newcom / no 1638 ; mov $1,r0 / yes 1639 ; sys write; at; 2. / print prompt 1640 ;newcom: 1641 ; mov shellarg,sp / 1642 ; mov $parbuf,r3 / initialize command list area 1643 ; mov $parp,r4 / initialize command list pointers 1644 ; clr infile / initialize alternate input 1645 ; clr outfile / initialize alternate output 1646 ; clr glflag / initialize global flag 1647 ;newarg: 1648 ; jsr pc,blank / squeeze out leading blanks 1649 ; jsr r5,delim / is new character a ; \n or & 1650 ; br 2f / yes 1651 ; mov r3,-(sp) / no, push arg pointer onto stack 1652 ; cmp r0,$'< / new input file? 1653 ; bne 1f / no 1654 ; mov (sp),infile / yes, save arg pointer 1655 ; clr (sp) / clear pointer 1656 ; br 3f 1657 ;1: 1658 ; cmp r0,$'> / new output file? 1659 ; bne newchar / no 1660 ; mov (sp),outfile / yes, save arg pointer 1661 ; clr (sp) / clear pointer 1662 ; br 3f 1663 ;newchar: 1664 ; cmp $' ,r0 / is character a blank 1665 ; beq 1f / branch if it is (blank as arg separator) 1666 ; cmp $'\n+200,r0 / treat \n preceded by ; beq 1f / as blank 1668 ; jsr pc,putc / put this character in parbuf list 1669 ;3: 1670 ; jsr pc,getc / get next character 1671 ; jsr r5,delim / is char a ; \n or &, 1672 ; br 1f / yes 1673 ; br newchar / no, start new character tests 1674 ;1: 1675 ; clrb (r3)+ / end name with \0 when read blank, or 1676 ; / delim 1677 ; mov (sp)+,(r4)+ / move arg ptr to parp location 1678 ; bne 1f / if (sp)=0, in file or out file points to arg 1679 ; tst -(r4) / so ignore dummy (0), in pointer list 1680 ;1: 1681 ; jsr r5,delim / is char a ; \n or &. 1682 ; br 2f / yes 1683 ; br newarg / no, start newarg processing 1684 ;2: 1685 ; clr (r4) / \n, &, or ; takes to here (end of arg list) 1686 ; / after 'delim' call 1687 ; mov r0,-(sp) / save delimiter in stack 1688 ; jsr pc,docom / go to exec command in parbuf 1689 ; cmpb (sp),$'& / get a new command without wait? 1690 ; beq newcom / yes 1691 ; tst r1 / was chdir just executed or line ended with 1692 ; / ampersand? 1693 ; beq 2f / yes 1694 ;1: 1695 ; sys wait / no, wait for new process to terminate 1696 ; / command executed) 1697 ; bcs 2f / no, children not previously waited for 1698 ; cmp r0,r1 / is this my child 1699 ; bne 1b 1700 ;2: 1701 ; cmp (sp),$'\n / was delimiter a new line 1702 ; beq newline / yes 1703 ; br newcom / no, pick up next command 1704 ;docom: 1705 ; sub $parp,r4 / out arg count in r4 1706 ; bne 1f / any arguments? 1707 ; clr r1 / no, line ended with ampersand 1708 ; rts pc / return from call 1709 ;1: 1710 ; jsr r5,chcom; qchdir / is command chdir? 1711 ; br 2f / command not chdir 1712 ; cmp r4,$4 / prepare to exec chdir, 4=arg count x 2 1713 ; beq 3f 1714 ; jsr r5,error / go to print error 1715 ; ; .even 1716 ; br 4f 1717 ;3: 1718 ; mov parp+2,0f / more directory name to sys coll 1719 ; sys chdir; 0:0 / exec chdir 1720 ; bec 4f / no error exit 1721 ; jsr r5,error / go to print error 1722 ; ; .even / this diagnostic 1723 ;4: 1724 ; clr r1 / set r1 to zero to dkip wait 1725 ; rts pc / and return 1726 ;2: 1727 ; jsr r5,chcom; glogin / is command login? 1728 ; br 2f / not loqin, go to fork 1729 ; sys exec; parbuf; parp / exec login 1730 ; sys exec; binpb; parp / or /bin/login 1731 ;2: / no error return?? 1732 ; sys fork / generate sh child process for command 1733 ; br newproc / exec command with new process 1734 ; bec 1f / no error exit, old orocess 1735 ; jsr r5,error / go to print error 1736 ; ; .even / this diaonostic 1737 ; jmp newline / and return for next try 1738 ;1: 1739 ; mov r0,r1 / save id of child sh 1740 ; rts pc / return to "jsr pc, docom" call in parent sh 1741 ; 1742 ;error: 1743 ; movb (r5)+,och / pick up diagnostic character 1744 ; beq 1f / 0 is end of line 1745 ; mov $1,r0 / set for tty output 1746 ; sys write; och; 1 / print it 1747 ; br error / continue to get characters 1748 ;1: 1749 ; inc r5 / inc r5 to point to return 1750 ; bic $1,r5 / make it even 1751 ; clr r0 / set for input 1752 ; sys seek; 0; 2 / exit from runcom. skip to end of 1753 ; / input file 1754 ;chcom: / has no effect if tty input 1755 ; mov (r5)+,r1 / glogin gchdir r1, bump r5 1756 ; mov $parbuf,r2 / command address r2 'login' 1757 ;1: 1758 ; movb (r1)+,r0 / is this command 'chdir' 1759 ; cmpb (r2)+,r0 / compare command name byte with 'login' 1760 ; / or 'chdir' 1761 ; bne 1f / doesn't compare 1762 ; tst r0 / is this 1763 ; bne 1b / end of names 1764 ; tst (r5)+ / yes, bump r5 again to execute login 1765 ; / chdir 1766 ;1: 1767 ; rts r5 / no, return to exec command 1768 ; 1769 ;putc: 1770 ; cmp r0,$'' / single quote? 1771 ; beq 1f / yes 1772 ; cmp r0,$'" / double quote 1773 ; beq 1f / yes 1774 ; bic $!177,r0 / no, remove 200, if present 1775 ; movb r0,(r3)+ / store character in parbuf 1776 ; rts pc 1777 ;1: 1778 ; mov r0,-(sp) / push quote mark onto stack 1779 ;1: 1780 ; jsr pc,getc / get a quoted character 1781 ; cmp r0,$'\n / is it end or line 1782 ; bne 2f / no 1783 ; jsr r5,error / yes, indicate missing quote mark 1784 ; <"' imbalance\n\0>; .even 1785 ; jmp newline / ask for new line 1786 ;2: 1787 ; cmp r0,(sp) / is this closing quote mark 1788 ; beq 1f / yes 1789 ; bic $!177,r0 / no, strip off 200 if present 1790 ; movb r0,(r3)+ / store quoted character in parbuf 1791 ; br 1b / continue 1792 ;1: 1793 ; tst (sp)+ / pop quote mark off stack 1794 ; rts pc / return 1795 ; 1796 ;/ thp`e new process 1797 ; 1798 ;newproc: 1799 ; mov infile,0f / move pointer to new file name 1800 ; beq 1f / branch if no alternate read file given 1801 ; tstb *0f 1802 ; beq 3f / branch if no file name miven 1803 ; clr r0 / set tty input file name 1804 ; sys close / close it 1805 ; sys open; 0:..; 0 / open new input file for reading 1806 ; bcc 1f / branch if input file ok 1807 ;3: 1808 ; jsr r5,error / file not ok, print error 1809 ; ; .even / this diagnostic 1810 ; sys exit / terminate this process and make parent sh 1811 ;1: 1812 ; mov outfile,r2 / more pointer to new file name 1813 ; beq 1f / branch if no alternate write file 1814 ; cmpb (r2),$'> / is > at beqinning of file name? 1815 ; bne 4f / branch if it isn't 1816 ; inc r2 / yes, increment pointer 1817 ; mov r2,0f 1818 ; sys open; 0:..; 1 / open file for writing 1819 ; bec 3f / if no error 1820 ;4: 1821 ; mov r2,0f 1822 ; sys creat; 0:..; 17 / create new file with this name 1823 ; bec 3f / branch if no error 1824 ;2: 1825 ; jsr r5,error 1826 ; ; .even 1827 ; sys exit 1828 ;3: 1829 ; sys close / close the new write file 1830 ; mov r2,0f / move new name to open 1831 ; mov $1,r0 / set ttv file name 1832 ; sys close / close it 1833 ; sys open; 0:..; 1 / open new output file, it now has 1834 ; / file descriptor 1 1835 ; sys seek; 0; 2 / set pointer to current end of file 1836 ;1: 1837 ; tst glflag / was *, ? or [ encountered? 1838 ; bne 1f / yes 1839 ; sys exec; parbuf; parp / no, execute this commend 1840 ; sys exec; binpb; parp / or /bin/this command 1841 ;2: 1842 ; sys stat; binpb; inbuf / if can't execute does it 1843 ; / exist? 1844 ; bes 2f / branch if it doesn't 1845 ; mov $shell,parp-2 / does exist, not executable 1846 ; mov $binpb,parp / so it must be 1847 ; sys exec; shell; parp-2 / a command file, get it with 1848 ; / sh /bin/x (if x name of file) 1849 ;2: 1850 ; jsr r5,error / a return for exec is the diagnostic 1851 ; ; .even 1852 ; sys exit 1853 ;1: 1854 ; mov $glob,parp-2 / prepare to process *,? 1855 ; sys exec; glob; parp-2 / execute modified command 1856 ; br 2b 1857 ; 1858 ;delim: 1859 ; cmp r0,$'\n / is character a newline 1860 ; beq 1f 1861 ; cmp r0,$'& / is it & 1862 ; beq 1f / yes 1863 ; cmp r0,$'; / is it ; 1864 ; beq 1f / yes 1865 ; cmp r0,$'? / is it ? 1866 ; beq 3f 1867 ; cmp r0,$'[ / is it beginning of character string 1868 ; / (for glob) 1869 ; bne 2f 1870 ;3: 1871 ; inc glflag / ? or * or [ set flag 1872 ;2: 1873 ; tst (r5)+ / bump to process all except \n,;,& 1874 ;1: 1875 ; rts r5 1876 ; 1877 ;blank: 1878 ; jsr pc,getc / get next character 1879 ; cmp $' ,r0 / leading blanks 1880 ; beq blank / yes, 'squeeze out' 1881 ; cmp r0,$200+'\n / new-line preceded by \ is translated 1882 ; beq blank / into blank 1883 ; rts pc 1884 ;getc: 1885 ; tst param / are we substituting for $n 1886 ; bne 2f/ yes 1887 ; mov inbufp,r1 / no, move normal input pointer to r1 1888 ; cmp r1,einbuf / end of input line? 1889 ; bne 1f / no 1890 ; jsr pc,getbuf / yes, put next console line in buffer 1891 ; br getc 1892 ;1: 1893 ; movb (r1)+,r0 / move byte from input buffer to r0 1894 ; mov r1,inbufp / increment routine 1895 ; bis escap,r0 / if last character was \ this adds 1896 ; / 200 to current character 1897 ; clr escap / clear, so escap normally zero 1898 ; cmp r0,$'\\ / note that \\ is equal \ in as 1899 ; beq 1f 1900 ; cmp r0,$'$ / is it $ 1901 ; beq 3f / yes 1902 ; rts pc / no 1903 ;1: 1904 ; mov $200,escap / mark presence of \ in command line 1905 ; br getc / get next character 1906 ;2: 1907 ; movb *param,r0 / pick up substitution character put in 1908 ; / r0 1909 ; beq 1f / if end of substitution arg, branch 1910 ; inc param / if not end, set for next character 1911 ; rts pc / return as though character in ro is normal 1912 ; / input 1913 ;1: 1914 ; clr param / unset substitution pointer 1915 ; br getc / get next char in normal input 1916 ;3: 1917 ; jsr pc,getc / get digit after $ 1918 ; sub $'0,r0 / strip off zone bits 1919 ; cmp r0,$9. / compare with digit 9 1920 ; blos 1f / less than or equal 9 1921 ; mov $9.,r0 / if larger than 9, force 9 1922 ;1: 1923 ; mov shellarg,r1 / get pointer to stack for 1924 ; / this call of shell 1925 ; inc r0 / digit +1 1926 ; cmp r0,(r1) / is it less than # of args in this call 1927 ; bge getc / no, ignore it. so this $n is not replaced 1928 ; asl r0 / yes, multiply by 2 (to skip words) 1929 ; add r1,r0 / form pointer to arg pointer (-2) 1930 ; mov 2(r0),param / move arg pointer to param 1931 ; br getc / go to get substitution arg for $n 1932 ;getbuf: 1933 ; mov $inbuf,r0 / move input buffer address 1934 ; mov r0,inbufp / to input buffer pointer 1935 ; mov r0,einbuf / and initialize pointer to end of 1936 ; / character string 1937 ; dec r0 / decrement pointer so can utilize normal 1938 ; / 100p starting at 1f 1939 ; mov r0,0f / initialize address for reading 1st char 1940 ;1: 1941 ; inc 0f / this routine filles inbuf with line from 1942 ; / console - if there is cnc 1943 ; clr r0 / set for tty input 1944 ; sys read; 0:0; 1 / read next char into inbuf 1945 ; bcs xit1 / error exit 1946 ; tst r0 / a zero input is end of file 1947 ; beq xit1 / exit 1948 ; inc einbuf / eventually einbuf points to \n 1949 ; / (+1) of this line 1950 ; cmp 0b,$inbuf+256. / have we exceeded input buffer size 1951 ; bhis xit1 / if so, exit assume some sort of binary 1952 ; cmpb *0b,$'\n / end of line? 1953 ; bne 1b / no, go to get next char 1954 ; rts pc / yes, return 1955 ; 1956 ;xit1: 1957 ; sys exit 1958 ; 1959 ;quest: 1960 ; 1961 ; 1962 ;at: 1963 ; <@ > 1964 ; 1965 ;qchdir: 1966 ; 1967 ;glogin: 1968 ; 1969 ;shell: 1970 ; 1971 ;glob: 1972 ; 1973 ;binpb: 1974 ; 1975 ;parbuf: .=.+1000. 1976 ; .even 1977 ;param: .=.+2 1978 ;glflag: .=.+2 1979 ;infile: .=.+2 1980 ;outfile:.=.+2 1981 ; .=.+2 / room for glob 1982 ;parp: .=.+200. 1983 ;inbuf: .=.+256. 1984 ;escap: .=.+2 1985 ;inbufp: .=.+2 1986 ;einbuf: .=.+2 1987 ;och: .=.+2 1988 ;shellarg:.=.+2