1 ; **************************************************************************** 2 ; sh386.s (sh5.s) - Retro Unix 386 v1.1 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: 17/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 sh5.s -l sh5.txt -o sh5 -Z error.txt)) 25 26 ; sh5.s (17/06/2022, Retro UNIX 386 v1.1) -- (modified sh2.s) -- 27 ; sh4.s (13/06/2022, Retro UNIX 386 v1.2) -- (modified sh2.s) --- 28 ; sh3.s (29/05/2022, Retro UNIX 386 v1) -- (modified sh0.s) --- 29 ; sh2.s (29/05/2022, Retro UNIX 386 v1.1 & v1.2) -- (modified sh1.s) -- 30 ; sh1.s (03/01/2016, Retro UNIX 386 v1.1) 31 ; sh0.s (28/12/2015, Retro UNIX 386 v1, NASM 2.11, 32 bit version of 'sh.asm') 32 ; SHELL03.ASM, 13/11/2013 - 27/06/2014 (sh.asm, Retro UNIX 8086 v1, MASM 6.11) 33 34 ; 12/01/2022 (Retro UNIX 386 v1.2) 35 ; 13/10/2015 36 ; 27/08/2015 37 ; 24/08/2015 38 ; 08/04/2014 39 ; 13/11/2013 40 41 ; UNIX v1 system calls 42 _rele equ 0 43 _exit equ 1 44 _fork equ 2 45 _read equ 3 46 _write equ 4 47 _open equ 5 48 _close equ 6 49 _wait equ 7 50 _creat equ 8 51 _link equ 9 52 _unlink equ 10 53 _exec equ 11 54 _chdir equ 12 55 _time equ 13 56 _mkdir equ 14 57 _chmod equ 15 58 _chown equ 16 59 _break equ 17 60 _stat equ 18 61 _seek equ 19 62 _tell equ 20 63 _mount equ 21 64 _umount equ 22 65 _setuid equ 23 66 _getuid equ 24 67 _stime equ 25 68 _quit equ 26 69 _intr equ 27 70 _fstat equ 28 71 _emt equ 29 72 _mdate equ 30 73 _stty equ 31 74 _gtty equ 32 75 _ilgins equ 33 76 _sleep equ 34 ; Retro UNIX 8086 v1 feature only ! 77 _msg equ 35 ; Retro UNIX 386 v1 feature only ! 78 _geterr equ 36 ; Retro UNIX 386 v1 feature only ! 79 ; 12/01/2022 - Retro UNIX 386 v1.2 80 ; Retro UNIX 386 v2 system calls 81 _setgid equ 37 82 _getgid equ 38 83 _sysver equ 39 ; (get) Retro Unix 386 version 84 85 %macro sys 1-4 86 ; 03/09/2015 87 ; 13/04/2015 88 ; Retro UNIX 386 v1 system call. 89 %if %0 >= 2 90 mov ebx, %2 91 %if %0 >= 3 92 mov ecx, %3 93 ;%if %0 = 4 94 %if %0 >= 4 ; 11/03/2022 95 mov edx, %4 96 %endif 97 %endif 98 %endif 99 mov eax, %1 100 int 30h 101 %endmacro 102 103 ; 17/06/2022 - Retro UNIX 386 v1.1 104 struc stat 105 ; Retro UNIX v1 'sysstat' output ! 106 ; (34 bytes) 107 00000000 ???? .inode: resw 1 108 00000002 ???? .mode: resw 1 109 00000004 ?? .nlinks: resb 1 110 00000005 ?? .uid: resb 1 111 00000006 ???? .size: resw 1 112 00000008 .dskptr: resw 8 113 00000018 ???????? .ctime: resd 1 114 0000001C ???????? .mtime: resd 1 115 00000020 ???? .rsvd: resw 1 116 .strucsize: 117 endstruc 118 119 ; Retro UNIX 386 v1 system call format: 120 ; sys systemcall (eax) , , 121 122 ;----------------------------------------------------------------- 123 ; text - code 124 ;----------------------------------------------------------------- 125 126 [BITS 32] ; 32-bit intructions (for 80386 protected mode) 127 128 [ORG 0] 129 130 START_CODE: 131 ;/ sh -- command interpreter 132 133 ; 17/06/2022 134 ; 29/05/2022 - Erdogan Tan 135 ; (Modified by using disassembled unix v2 'sh' code.) 136 137 ;;27/12/2015 138 ;;clear BSS 139 ;mov ecx, ((bss_end - bss_start) + 3) / 4 140 ;sub eax, eax 141 ;mov edi, bss_start 142 ;rep stosd 143 s0: 144 00000000 89E5 mov ebp, esp 145 ; mov sp,r5 146 00000002 892D[840C0000] mov [shellarg], ebp 147 ; mov r5,shellarg / save orig sp in shellarg 148 00000008 8B5D04 mov ebx, [ebp+4] 149 0000000B 803B2D cmp byte [ebx], '-' 150 ; cmpb *2(r5),$'- / was this sh called by init or login 151 0000000E 752E jne short s1 152 ; bne 2f / no 153 sys _intr, 0 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000010 BB00000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000015 B81B000000 <1> mov eax, %1 100 0000001A CD30 <1> int 30h 154 ; sys intr; 0 / yes, turn off interrupts 155 sys _quit, 0 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 0000001C BB00000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000021 B81A000000 <1> mov eax, %1 100 00000026 CD30 <1> int 30h 156 ; sys quit; 0 157 sys _write, 1, msg_unix_sh, msgsh_size 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000028 BB01000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 0000002D B9[FD050000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 00000032 BA1D000000 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000037 B804000000 <1> mov eax, %1 100 0000003C CD30 <1> int 30h 158 s1: ;2: 159 sys _getuid 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 0000003E B818000000 <1> mov eax, %1 100 00000043 CD30 <1> int 30h 160 ; sys getuid / who is user 161 ;and eax, eax 162 00000045 20C0 and al, al 163 ; tst r0 / is it superuser 164 00000047 7507 jnz short s2 165 ; bne 2f / no 166 00000049 C605[8B060000]23 mov byte [_at], '#' 167 ; movb $'#,at / yes, set new prompt symbol 168 s2: ;2: 169 00000050 837D0001 cmp dword [ebp], 1 170 ; cmp (r5),$1 / tty input? 171 00000054 7631 jna short newline 172 ; ble newline / yes, call with '-' (or with no command 173 ; / file name) 174 00000056 31DB xor ebx, ebx 175 ; clr r0 / no, set tty 176 sys _close 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000058 B806000000 <1> mov eax, %1 100 0000005D CD30 <1> int 30h 177 ; sys close / close it 178 0000005F 8B5D08 mov ebx, [ebp+8] ; arg 1 179 ; mov 4(r5),0f / get new file name 180 00000062 31C9 xor ecx, ecx ; arg 2 181 sys _open 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000064 B805000000 <1> mov eax, %1 100 00000069 CD30 <1> int 30h 182 ; sys open; 0:..; 0 / open it 183 0000006B 7311 jnc short s3 184 ; bec 1f / branch if no error 185 0000006D BE[27060000] mov esi, msgNotFound 186 00000072 E8EA010000 call error 187 ; jsr r5,error / error in file name 188 ; ; .even 189 sys _exit 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000077 B801000000 <1> mov eax, %1 100 0000007C CD30 <1> int 30h 190 ; sys exit 191 s3: ;1: 192 0000007E C605[8B060000]00 mov byte [_at], 0 193 ; clr at / clear prompt character, if reading non-tty 194 ; / input file 195 00000085 EB1F jmp short newcom 196 newline: 197 00000087 803D[8B060000]00 cmp byte [_at], 0 198 ; tst at / is there a prompt symbol 199 0000008E 7616 jna short newcom 200 ; beq newcom / no 201 ; mov $1,r0 / yes 202 nl: 203 sys _write, 1, prompt, p_size 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000090 BB01000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 00000095 B9[89060000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 0000009A BA04000000 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 0000009F B804000000 <1> mov eax, %1 100 000000A4 CD30 <1> int 30h 204 ;sys _write, 1, _at, 2 205 ; sys write; at; 2. / print prompt 206 newcom: 207 000000A6 8B25[840C0000] mov esp, [shellarg] 208 ; mov shellarg,sp / 209 000000AC BE[B8060000] mov esi, parbuf 210 ; mov $parbuf,r3 / initialize command list area 211 000000B1 BF[B20A0000] mov edi, parp 212 ; mov $parp,r4 / initialize command list pointers 213 000000B6 31C0 xor eax, eax 214 000000B8 A3[A60A0000] mov [infile], eax ; 0 215 ; clr infile / initialize alternate input 216 000000BD A3[AA0A0000] mov [outfile], eax ; 0 217 ; clr outfile / initialize alternate output 218 000000C2 A2[A40A0000] mov [glflag], al ; 0 219 ;mov [glflag], ax ; 0 220 ; clr glflag / initialize global flag 221 ; 27/12/2015 222 000000C7 A2[88060000] mov [FCAT], al ; 0 223 newarg: 224 000000CC E8B8030000 call blank 225 ; jsr pc,blank / squeeze out leading blanks 226 000000D1 E894030000 call delim 227 000000D6 7467 je short nch4 ; '\n', ';', '&' 228 ; jsr r5,delim / is new character a ; \n or & 229 ; br 2f / yes 230 000000D8 56 push esi 231 ; mov r3,-(sp) / no, push arg pointer onto stack 232 000000D9 3C3C cmp al, '<' 233 ; cmp r0,$'< / new input file? 234 000000DB 7508 jne short na1 235 ; bne 1f / no 236 000000DD 8935[A60A0000] mov [infile], esi 237 ; mov (sp),infile / yes, save arg pointer 238 ;jmp short na4 239 000000E3 EB1E jmp short na3 240 ;mov dword [esp], 0 241 ; clr (sp) / clear pointer 242 ;jmp short nch1 243 ; br 3f 244 na1: ;1: 245 000000E5 3C3E cmp al, '>' 246 ; cmp r0,$'> / new output file? 247 000000E7 7530 jne short nch0 248 ;jne short newchar 249 ; bne newchar / no 250 000000E9 8935[AA0A0000] mov [outfile], esi 251 ; mov (sp),outfile / yes, save arg pointer 252 ; 27/12/2015 253 000000EF E8A7030000 call getc 254 000000F4 3C3E cmp al, '>' 255 000000F6 7507 jne short na2 256 ; 257 000000F8 A2[88060000] mov [FCAT], al ; '>>' 258 000000FD EB04 jmp short na3 259 na2: 260 000000FF 3C20 cmp al, 20h ; ' ' 261 00000101 7505 jne short na4 262 na3: 263 00000103 E881030000 call blank 264 na4: 265 00000108 C7042400000000 mov dword [esp], 0 266 ; clr (sp) / clear pointer 267 ;jmp short nch1 268 ; br 3f 269 0000010F EB12 jmp short nch7 270 newchar: 271 00000111 3C20 cmp al, 20h 272 ; cmp $' ,r0 / is character a blank 273 00000113 7415 je short nch2 274 ; beq 1f / branch if it is (blank as arg separator) 275 00000115 3C8D cmp al, 8Dh ; 128 + 13 276 00000117 7411 je short nch2 277 ; cmp $'\n+200,r0 / treat \n preceded by ; beq 1f / as blank 279 nch0: 280 00000119 E8A0010000 call putc 281 ; jsr pc,putc / put this character in parbuf list 282 nch1: ;3: 283 0000011E E878030000 call getc 284 ; jsr pc,getc / get next character 285 nch7: 286 00000123 E842030000 call delim 287 00000128 75E7 jne short newchar 288 ;jz short nch2 ; '\n', ';', '&' 289 ; jsr r5,delim / is char a ; \n or &, 290 ; br 1f / yes 291 ;jmp short newchar 292 ; br newchar / no, start new character tests 293 nch2: ;1: 294 0000012A C60600 mov byte [esi], 0 295 0000012D 46 inc esi 296 ; clrb (r3)+ / end name with \0 when read blank, 297 ; or delim 298 0000012E 5B pop ebx 299 0000012F 891F mov [edi], ebx 300 ; mov (sp)+,(r4)+ / move arg ptr to parp location 301 00000131 09DB or ebx, ebx 302 00000133 7403 jz short nch3 303 ;jnz short nch3 304 ; bne 1f / if (sp)=0, in file or out file points 305 ; to arg 306 00000135 83C704 add edi, 4 307 ; tst -(r4) / so ignore dummy (0), in pointer list 308 nch3: ;1: 309 00000138 E82D030000 call delim 310 0000013D 758D jne short newarg 311 ;jz short nch4 ; '\n', ';', '&' 312 ; jsr r5,delim / is char a ; \n or &. 313 ; br 2f / yes 314 ;jmp short newarg 315 ; br newarg / no, start newarg processing 316 nch4: ;2: 317 0000013F C70700000000 mov dword [edi], 0 318 ; clr (r4) / \n, &, or ; takes to here 319 ; / (end of arg list) after 'delim' call 320 00000145 50 push eax 321 ; mov r0,-(sp) / save delimiter in stack 322 00000146 E827000000 call docom 323 ; jsr pc,docom / go to exec command in parbuf 324 0000014B 803C2426 cmp byte [esp], '&' 325 ; cmpb (sp),$'& / get a new command without wait? 326 ;je newcom 327 ; ; beq newcom / yes 328 ; 29/05/2022 329 0000014F 7505 jne short nch_9 330 nch_8: 331 00000151 E950FFFFFF jmp newcom 332 nch_9: 333 00000156 21D2 and edx, edx 334 ; tst r1 / was chdir just executed or line ended 335 ; / with ampersand? 336 00000158 740D jz short nch6 337 ; beq 2f / yes 338 nch5: ;1: 339 sys _wait 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 0000015A B807000000 <1> mov eax, %1 100 0000015F CD30 <1> int 30h 340 ; sys wait / no, wait for new process to terminate 341 ; / command executed) 342 00000161 7204 jc short nch6 343 ; bcs 2f / no, children not previously waited for 344 00000163 39D0 cmp eax, edx 345 ; cmp r0,r1 / is this my child 346 00000165 75F3 jne short nch5 347 ; bne 1b 348 nch6: ;2: 349 00000167 803C240D cmp byte [esp], 0Dh 350 ;cmp byte [esp], 0Ah 351 ; cmp (sp),$'\n / was delimiter a new line 352 ;je newline 353 ; ; beq newline / yes 354 ; 29/05/2022 355 ;jmp newcom 356 ; ; br newcom / no, pick up next command 357 0000016B 75E4 jne short nch_8 ; jne newcom 358 0000016D E915FFFFFF jmp newline ; je newline 359 docom: 360 00000172 81EF[B20A0000] sub edi, parp 361 ; sub $parp,r4 / out arg count in r4 362 00000178 7503 jne short dcom1 363 ; bne 1f / any arguments? 364 dcom0: 365 0000017A 29D2 sub edx, edx ; 0 366 ; clr r1 / no, line ended with ampersand 367 0000017C C3 retn 368 ; rts pc / return from call 369 dcom1: ;1: 370 0000017D 89FB mov ebx, edi 371 ; 06/12/2013 372 0000017F BE[8D060000] mov esi, qecho 373 00000184 E827010000 call chcom 374 00000189 7543 jnz short dcom7 375 ; 28/12/2015 376 0000018B 89DD mov ebp, ebx 377 0000018D BF[B20A0000] mov edi, parp 378 dcom9: ; CRLF 379 sys _write, 1, nextline, 2 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000192 BB01000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 00000197 B9[24060000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 0000019C BA02000000 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 000001A1 B804000000 <1> mov eax, %1 100 000001A6 CD30 <1> int 30h 380 ; 381 000001A8 83ED04 sub ebp, 4 ; remain arg count x 4 382 000001AB 76CD jna short dcom0 383 000001AD 83C704 add edi, 4 384 000001B0 8B37 mov esi, [edi] 385 ;or esi, esi 386 ;jz short dcom0 387 000001B2 89F2 mov edx, esi ; string address 388 dcom10: 389 000001B4 AC lodsb 390 000001B5 08C0 or al, al 391 000001B7 75FB jnz short dcom10 392 000001B9 87D6 xchg edx, esi 393 000001BB 29F2 sub edx, esi ; byte count 394 000001BD 4A dec edx 395 ;jz short dcom0 396 ; write string 397 sys _write, 1, esi ; edx = byte count 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 000001BE BB01000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 000001C3 89F1 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 000001C5 B804000000 <1> mov eax, %1 100 000001CA CD30 <1> int 30h 398 000001CC EBC4 jmp short dcom9 399 dcom7: 400 000001CE BE[95060000] mov esi, qchdir 401 000001D3 E8D8000000 call chcom 402 000001D8 752D jnz short dcom4 403 ; jsr r5,chcom; qchdir / is command chdir? 404 ; br 2f / command not chdir 405 dcom12: 406 000001DA 80FB08 cmp bl, 8 ; 8 = arg count x 4 (24/08/2015) 407 ;cmp bx, 8 408 ; cmp r4,$4 / prepare to exec chdir, 409 ; 4 = arg count x 2 410 000001DD 740C je short dcom2 411 ; beq 3f 412 dcom8: 413 000001DF BE[37060000] mov esi, msgArgCount 414 000001E4 E878000000 call error 415 ; jsr r5,error / go to print error 416 ; ; .even 417 ;jmp short dcom3 418 ; br 4f 419 000001E9 EB8F jmp short dcom0 420 dcom2: ;3: 421 000001EB 8B1D[B60A0000] mov ebx, [parp+4] 422 ;mov parp+2,0f / move directory name to sys call 423 sys _chdir 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 000001F1 B80C000000 <1> mov eax, %1 100 000001F6 CD30 <1> int 30h 424 ; sys chdir; 0:0 / exec chdir 425 000001F8 730A jnc short dcom3 426 ; bec 4f / no error exit 427 000001FA BE[41060000] mov esi, msgBadDir 428 000001FF E85D000000 call error 429 ; jsr r5,error / go to print error 430 ; ; .even 431 ; / this diagnostic 432 dcom3: ;4: 433 00000204 31D2 xor edx, edx ; 0 434 ; clr r1 / set r1 to zero to skip wait 435 00000206 C3 retn 436 ; rts pc / and return 437 dcom4: ;2: 438 ; 06/12/2013 439 00000207 BE[92060000] mov esi, qcd 440 0000020C E89F000000 call chcom 441 00000211 74C7 jz short dcom12 442 dcom11: 443 00000213 BE[9B060000] mov esi, glogin 444 00000218 E893000000 call chcom 445 0000021D 7522 jnz short dcom5 446 ; jsr r5,chcom; glogin / is command login? 447 ; br 2f / not loqin, go to fork 448 sys _exec, parbuf, parp 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 0000021F BB[B8060000] <1> mov ebx, %2 91 <1> %if %0 >= 3 92 00000224 B9[B20A0000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000229 B80B000000 <1> mov eax, %1 100 0000022E CD30 <1> int 30h 449 ; sys exec; parbuf; parp / exec login 450 sys _exec, binpb, parp 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000230 BB[B3060000] <1> mov ebx, %2 91 <1> %if %0 >= 3 92 00000235 B9[B20A0000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 0000023A B80B000000 <1> mov eax, %1 100 0000023F CD30 <1> int 30h 451 ; sys exec; binpb; parp / or /bin/login 452 dcom5: ;2: / no error return?? 453 00000241 BB[F3020000] mov ebx, newproc 454 ; child process will return to 'newproc' address 455 sys _fork 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000246 B802000000 <1> mov eax, %1 100 0000024B CD30 <1> int 30h 456 ; sys fork / generate sh child process 457 ; for command 458 ; br newproc / exec command with 459 ; new process 460 ; parent process will return here 461 0000024D 730F jnc short dcom6 462 ; bec 1f / no error exit, old process 463 0000024F BE[4F060000] mov esi, msgTryAgain 464 00000254 E808000000 call error 465 ; jsr r5,error / go to print error 466 ; ; .even / this diagnostic 467 00000259 E929FEFFFF jmp newline 468 ; jmp newline / and return for next try 469 dcom6: ;1: 470 0000025E 89C2 mov edx, eax ; child process ID 471 ; mov r0,r1 / save id of child sh 472 00000260 C3 retn 473 ; rts pc / return to "jsr pc, docom" call 474 ; in parent sh 475 error: 476 sys _write, 1, nextline, 2 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000261 BB01000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 00000266 B9[24060000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 0000026B BA02000000 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000270 B804000000 <1> mov eax, %1 100 00000275 CD30 <1> int 30h 477 s4: 478 00000277 AC lodsb 479 00000278 A2[820C0000] mov [och], al 480 ; movb (r5)+,och / pick up diagnostic character 481 0000027D 20C0 and al, al 482 0000027F 7418 jz short s5 483 ; beq 1f / 0 is end of line 484 sys _write, 1, och, 1 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000281 BB01000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 00000286 B9[820C0000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 0000028B BA01000000 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000290 B804000000 <1> mov eax, %1 100 00000295 CD30 <1> int 30h 485 ; mov $1,r0 / set for tty output 486 ; sys write; och; 1 / print it 487 00000297 EBDE jmp short s4 488 ;jmp short error 489 ; br error / continue to get characters 490 s5: ;1: 491 ;inc esi 492 ; inc r5 / inc r5 to point to return 493 ;;and si, 0FFFEh 494 ;shr esi, 1 495 ;shl esi, 1 496 ; bic $1,r5 / make it even 497 sys _seek, 0, 0, 2 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000299 BB00000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 0000029E B900000000 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 000002A3 BA02000000 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 000002A8 B813000000 <1> mov eax, %1 100 000002AD CD30 <1> int 30h 498 ; clr r0 / set for input 499 ; sys seek; 0; 2 / exit from runcom. skip to 500 ; / end of input file 501 000002AF C3 retn 502 ;; rts r5 ; unix v2 shell ; 29/05/2022 503 ;; (not in original unix v1 'sh.s') 504 505 chcom: ; / has no effect if tty input 506 ; mov (r5)+,r1 / glogin gchdir r1, bump r5 507 000002B0 BF[B8060000] mov edi, parbuf 508 ; mov $parbuf,r2 / command address r2 'login' 509 s6: ;1: 510 000002B5 AC lodsb 511 ; movb (r1)+,r0 / is this command 'chdir' 512 000002B6 AE scasb 513 ; cmpb (r2)+,r0 / compare command name byte 514 ; / with 'login' or 'chdir' 515 000002B7 7504 jne short s7 516 ; bne 1f / doesn't compare 517 000002B9 08C0 or al, al 518 ; tst r0 / is this 519 000002BB 75F8 jnz short s6 520 ; bne 1b / end of names 521 ; tst (r5)+ / yes, bump r5 again to execute 522 ; / login or chdir 523 s7: ;1: 524 000002BD C3 retn 525 ; rts r5 / no, return to exec command 526 527 putc: 528 000002BE 3C27 cmp al, 27h ; ' 529 ; cmp r0,$'' / single quote? 530 000002C0 740A je short pch1 531 ; beq 1f / yes 532 000002C2 3C22 cmp al, 22h ; " 533 ; cmp r0,$'" / double quote 534 000002C4 7406 je short pch1 535 ; beq 1f / yes 536 000002C6 247F and al, 7Fh 537 ; bic $!177,r0 / no, remove 200, if present 538 000002C8 8806 mov [esi], al 539 000002CA 46 inc esi 540 ; movb r0,(r3)+ / store character in parbuf 541 000002CB C3 retn 542 ; rts pc 543 pch1: ;1: 544 000002CC 50 push eax 545 ; mov r0,-(sp) / push quote mark onto stack 546 pch2: ;1: 547 000002CD E8C9010000 call getc 548 ; jsr pc,getc / get a quoted character 549 000002D2 3C0D cmp al, 0Dh 550 ;cmp al, 0Ah ; \n 551 ; cmp r0,$'\n / is it end or line 552 000002D4 750F jne short pch3 553 ; bne 2f / no 554 000002D6 BE[59060000] mov esi, msgImbalance 555 000002DB E881FFFFFF call error 556 ; jsr r5,error / yes, indicate missing 557 ; quote mark 558 ; <"' imbalance\n\0>; .even 559 000002E0 E9A2FDFFFF jmp newline 560 ; jmp newline / ask for new line 561 pch3: ;2: 562 000002E5 380424 cmp [esp], al 563 ; cmp r0,(sp) / is this closing quote mark 564 000002E8 7407 je short pch4 565 ; beq 1f / yes 566 000002EA 247F and al, 7Fh 567 ; bic $!177,r0 / no, strip off 200 568 ; if present 569 000002EC 8806 mov [esi], al 570 000002EE 46 inc esi 571 ; movb r0,(r3)+ / store quoted character 572 ; in parbuf 573 000002EF EBDC jmp short pch2 574 ; br 1b / continue 575 pch4: ;1: 576 000002F1 58 pop eax 577 ; tst (sp)+ / pop quote mark off stack 578 000002F2 C3 retn 579 ; rts pc / return 580 581 ; / thp`e new process 582 583 newproc: 584 000002F3 8B35[A60A0000] mov esi, [infile] 585 000002F9 09F6 or esi, esi 586 000002FB 7456 jz short np2 587 ; mov infile,0f / move pointer to new file name 588 ; beq 1f / branch if no alternate read file given 589 000002FD 803E00 cmp byte [esi], 0 590 ; tstb *0f 591 00000300 7640 jna short np1 592 ; beq 3f / branch if no file name given 593 594 ; 17/06/2022 - Retro UNIX 386 v1.1 595 sys _stat, esi, stbuf ; get file (inode) status 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000302 89F3 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 00000304 B9[8A0C0000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000309 B812000000 <1> mov eax, %1 100 0000030E CD30 <1> int 30h 596 00000310 7230 jc short np1 597 ; 598 ; (regular files, disk blocks may be used as input source) 599 ; ((pseudo tty input redirection not allowed)) 600 601 00000312 66A1[8A0C0000] mov ax, [stbuf] ; inode number 602 00000318 6683F813 cmp ax, 19 ; > tty9 inode number (regular file) ? 603 0000031C 7708 ja short np13 ; yes 604 0000031E 3C0A cmp al, 10 ; < tty0 ? 605 00000320 7320 jnb short np1 ; no (input error) 606 00000322 3C01 cmp al, 1 607 00000324 741C je short np1 608 np13: 609 sys _close, 0 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000326 BB00000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 0000032B B806000000 <1> mov eax, %1 100 00000330 CD30 <1> int 30h 610 ; clr r0 / set tty input file name 611 ; sys close / close it 612 sys _open, esi, 0 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000332 89F3 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 00000334 B900000000 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000339 B805000000 <1> mov eax, %1 100 0000033E CD30 <1> int 30h 613 ; sys open; 0:..; 0 / open new input file 614 ; for reading 615 00000340 7311 jnc short np2 616 ; bcc 1f / branch if input file ok 617 np1: ;3: 618 00000342 BE[66060000] mov esi, msgInputFile 619 00000347 E815FFFFFF call error 620 ; jsr r5,error / file not ok, print error 621 ; ; .even / this diagnostic 622 sys _exit 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 0000034C B801000000 <1> mov eax, %1 100 00000351 CD30 <1> int 30h 623 ; sys exit / terminate this process 624 ; and make parent sh 625 np2: ;1: 626 00000353 8B35[AA0A0000] mov esi, [outfile] 627 ; mov outfile,r2 / more pointer to new file name 628 00000359 21F6 and esi, esi 629 ;jz short np6 630 ; beq 1f / branch if no alternate write file 631 ; 17/06/2022 632 0000035B 7505 jnz short np11 633 0000035D E9AB000000 jmp np6 634 np11: 635 ; 27/12/2015 636 00000362 803E00 cmp byte [esi], 0 637 00000365 763D jna short np4 638 ; 639 ;cmp byte [esi], '>' 640 ; cmpb (r2),$'> / is > at beqinning of file name? 641 ;jne short np3 642 ; bne 4f / branch if it isn't 643 ;inc esi 644 ; inc r2 / yes, increment pointer 645 ; 646 ; 17/06/2022 647 ;cmp byte [FCAT], '>' ; '>>' 648 ;jne short np3 649 650 ; 17/06/2022 - Retro UNIX 386 v1.1 651 sys _stat, esi, stbuf ; get file (inode) status 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000367 89F3 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 00000369 B9[8A0C0000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 0000036E B812000000 <1> mov eax, %1 100 00000373 CD30 <1> int 30h 652 00000375 7247 jc short np3 653 654 ; Block devices and dirs must not be target 655 00000377 F605[8D0C0000]40 test byte [stbuf+stat.mode+1], 40h ; directory ? 656 0000037E 7524 jnz short np4 ; yes ; error 657 658 00000380 66A1[8A0C0000] mov ax, [stbuf] ; inode number 659 00000386 6683F829 cmp ax, 41 ; regular file ? 660 0000038A 7729 ja short np14 ; yes 661 662 0000038C 3C08 cmp al, 8 ; > hd3 inode number ? 663 0000038E 7704 ja short np12 ; yes ; character device 664 665 00000390 3C03 cmp al, 3 ; >= fd0 inode number ? 666 00000392 7310 jnb short np4 ; yes ; output file error 667 np12: 668 sys _open, esi, 1 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000394 89F3 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 00000396 B901000000 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 0000039B B805000000 <1> mov eax, %1 100 000003A0 CD30 <1> int 30h 669 ; mov r2,0f 670 ; sys open; 0:..; 1 / open file for writing 671 000003A2 732A jnc short np5 672 ; bec 3f / if no error 673 np4: ;2: 674 000003A4 BE[71060000] mov esi, msgOutputFile 675 000003A9 E8B3FEFFFF call error 676 ; jsr r5,error 677 ; ; .even 678 sys _exit 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 000003AE B801000000 <1> mov eax, %1 100 000003B3 CD30 <1> int 30h 679 ; sys exit 680 681 ;jmp short np4 682 683 ; 17/06/2022 684 np14: 685 000003B5 803D[88060000]3E cmp byte [FCAT], '>' ; '>>' ? 686 000003BC 74D6 je short np12 ; no, '>' 687 np3: ;4: 688 sys _creat, esi, 15 ; Decimal 15 = Octal 17 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 000003BE 89F3 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 000003C0 B90F000000 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 000003C5 B808000000 <1> mov eax, %1 100 000003CA 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 ; 17/06/2022 695 000003CC 72D6 jc short np4 696 697 np5: ;3: 698 sys _close, eax 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 000003CE 89C3 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 000003D0 B806000000 <1> mov eax, %1 100 000003D5 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 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 000003D7 BB01000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 000003DC B806000000 <1> mov eax, %1 100 000003E1 CD30 <1> int 30h 703 ; mov $1,r0 / set tty file name 704 ; sys close / close it 705 sys _open, esi, 1 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 000003E3 89F3 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 000003E5 B901000000 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 000003EA B805000000 <1> mov eax, %1 100 000003EF 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 000003F1 803D[88060000]3E cmp byte [FCAT], '>' ; '>>' 710 000003F8 7513 jne short np6 711 ; 712 sys _seek, eax, 0, 2 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 000003FA 89C3 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 000003FC B900000000 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 00000401 BA02000000 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000406 B813000000 <1> mov eax, %1 100 0000040B CD30 <1> int 30h 713 ; sys seek; 0; 2 / set pointer to 714 ; current end of file 715 np6: ;1: 716 0000040D 803D[A40A0000]00 cmp byte [glflag], 0 717 ; tst glflag / was *, ? or [ encountered? 718 00000414 7739 ja short np9 719 ; bne 1f / yes 720 sys _exec, parbuf, parp 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000416 BB[B8060000] <1> mov ebx, %2 91 <1> %if %0 >= 3 92 0000041B B9[B20A0000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000420 B80B000000 <1> mov eax, %1 100 00000425 CD30 <1> int 30h 721 ; sys exec; parbuf; parp / no, execute 722 ; this command 723 sys _exec, binpb, parp 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000427 BB[B3060000] <1> mov ebx, %2 91 <1> %if %0 >= 3 92 0000042C B9[B20A0000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000431 B80B000000 <1> mov eax, %1 100 00000436 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 00000438 BE[7D060000] mov esi, msgNoCmd 750 0000043D E81FFEFFFF call error 751 ; jsr r5,error / a return for exec 752 ; is the diagnostic 753 ; ; .even 754 00000442 8B25[840C0000] mov esp, [shellarg] 755 sys _exit 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000448 B801000000 <1> mov eax, %1 100 0000044D CD30 <1> int 30h 756 ; sys exit 757 np9: ;1: 758 0000044F BE[AE0A0000] mov esi, parp-4 759 00000454 C706[A9060000] mov dword [esi], glob 760 ; mov $glob,parp-2 / prepare to process *,? 761 sys _exec, glob, esi 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 0000045A BB[A9060000] <1> mov ebx, %2 91 <1> %if %0 >= 3 92 0000045F 89F1 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000461 B80B000000 <1> mov eax, %1 100 00000466 CD30 <1> int 30h 762 ; sys exec; glob; parp-2 763 ; / execute modified command 764 00000468 EBCE jmp short np8 765 ; br 2b 766 767 delim: 768 0000046A 3C0D cmp al, 0Dh ; carriage return 769 0000046C 741A je short dlim2 770 ;cmp al, 0Ah 771 ; cmp r0,$'\n / is character a newline 772 ;je short dlim2 773 ; beq 1f 774 0000046E 3C26 cmp al, '&' 775 ;cmp r0,$'& / is it & 776 00000470 7416 je short dlim2 777 ; beq 1f / yes 778 00000472 3C3B cmp al, ';' 779 ; cmp r0,$'; / is it ; 780 00000474 7412 je short dlim2 781 ; beq 1f / yes 782 00000476 3C3F cmp al, '?' 783 ; cmp r0,$'? / is it ? 784 00000478 7408 je short dlim1 785 ; beq 3f 786 ; 787 ;------ 29/05/2022 - unix v2 shell 788 ; (source code from disassembled /bin/sh binary) 789 0000047A 3C2A cmp al, '*' 790 ; cmp r0,$'* / is it * 791 0000047C 7404 je short dlim1 792 ; beq 3f 793 794 0000047E 3C5B cmp al, '[' 795 ; cmp r0,$'[ / is it beginning of character string 796 ; / (for glob) 797 00000480 7506 jne short dlim2 798 ; bne 2f 799 dlim1: ;3: 800 00000482 FE05[A40A0000] 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 00000488 C3 retn 807 ; rts r5 808 blank: 809 00000489 E80D000000 call getc 810 ; jsr pc,getc / get next character 811 0000048E 3C20 cmp al, 20h 812 ; cmp $' ,r0 / leading blanks 813 00000490 74F7 je short blank 814 ; beq blank / yes, 'squeeze out' 815 00000492 3C8D cmp al, 8Dh ; 80h + 0Dh 816 ;cmp al, 8Ah ; 80h + 0Ah 817 00000494 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 00000496 3C0A cmp al, 0Ah 823 00000498 74EF je short blank 824 ; 825 0000049A C3 retn 826 ; rts pc 827 getc: 828 0000049B 833D[A00A0000]00 cmp dword [param], 0 829 ; tst param / are we substituting for $n 830 000004A2 773D ja short gch3 831 ; bne 2f/ yes 832 gch0: 833 000004A4 8B1D[7A0C0000] mov ebx, [inbufp] 834 ; mov inbufp,r1 / no, move normal input pointer to r1 835 s8: 836 000004AA 3B1D[7E0C0000] cmp ebx, [einbuf] 837 ; cmp r1,einbuf / end of input line? 838 000004B0 7207 jb short gch1 839 ; bne 1f / no 840 000004B2 E877000000 call getbuf 841 ; jsr pc,getbuf / yes, put next console line 842 ; in buffer 843 000004B7 EBEB jmp short gch0 844 ; br getc 845 gch1: ;1: 846 000004B9 8A03 mov al, [ebx] 847 000004BB 43 inc ebx 848 ; movb (r1)+,r0 / move byte from input buffer to r0 849 000004BC 891D[7A0C0000] mov [inbufp], ebx 850 ; mov r1,inbufp / increment routine 851 000004C2 0A05[880C0000] 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 000004C8 3C5C cmp al, '\' 859 ; cmp r0,$'\\ / note that \\ is equal \ in as 860 000004CA 740C je short gch2 861 ; beq 1f 862 000004CC C605[880C0000]00 mov byte [escap], 0 863 000004D3 3C24 cmp al, '$' 864 ; cmp r0,$'$ / is it $ 865 000004D5 7429 je short gch5 866 ; beq 3f / yes 867 000004D7 C3 retn 868 ; rts pc / no 869 gch2: ;1: 870 000004D8 C605[880C0000]80 mov byte [escap], 80h 871 ;mov word [escap], 128 872 ; mov $200,escap / mark presence of \ in command line 873 000004DF EBC9 jmp short s8 874 ;jmp short gch0 875 ; br getc / get next character 876 gch3: ;2: 877 000004E1 8B1D[A00A0000] mov ebx, [param] 878 000004E7 8A03 mov al, [ebx] 879 ; movb *param,r0 / pick up substitution character 880 ; / put in r0 881 000004E9 08C0 or al, al 882 000004EB 7407 jz short gch4 883 ; beq 1f / if end of substitution arg, branch 884 000004ED FF05[A00A0000] inc dword [param] 885 ; inc param / if not end, set for next character 886 000004F3 C3 retn 887 ; rts pc / return as though character in ro is normal 888 ; / input 889 gch4: ;1: 890 000004F4 C705[A00A0000]0000- mov dword [param], 0 890 000004FC 0000 891 ; clr param / unset substitution pointer 892 000004FE EBA4 jmp short gch0 893 ; br getc / get next char in normal input 894 gch5: ;3: 895 00000500 E89FFFFFFF call gch0 896 ;call getc 897 ; jsr pc,getc / get digit after $ 898 00000505 2C30 sub al, '0' 899 ; sub $'0,r0 / strip off zone bits 900 00000507 3C09 cmp al, 9 901 ; cmp r0,$9. / compare with digit 9 902 00000509 7602 jna short gch6 903 ; blos 1f / less than or equal 9 904 0000050B B009 mov al, 9 905 ; mov $9.,r0 / if larger than 9, force 9 906 gch6: ;1: 907 0000050D 8B1D[840C0000] mov ebx, [shellarg] 908 ; mov shellarg,r1 / get pointer to stack for 909 ; / this call of shell 910 00000513 0FB6C0 movzx eax, al ; al->eax 911 00000516 FEC0 inc al 912 ;inc eax 913 ; inc r0 / digit +1 914 00000518 3B03 cmp eax, [ebx] 915 ; cmp r0,(r1) / is it less than # of args 916 ; in this call 917 0000051A 7388 jnb short gch0 918 ; bge getc / no, ignore it. so this $n is not replaced 919 0000051C 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 0000051F 01C3 add ebx, eax 924 ; add r1,r0 / form pointer to arg pointer (-2) 925 00000521 8B4304 mov eax, [ebx+4] 926 00000524 A3[A00A0000] mov [param], eax 927 ; mov 2(r0),param / move arg pointer to param 928 00000529 E96DFFFFFF jmp getc 929 ; br getc / go to get substitution arg for $n 930 getbuf: 931 0000052E B9[7A0B0000] mov ecx, inbuf 932 ; mov $inbuf,r0 / move input buffer address 933 00000533 890D[7A0C0000] mov [inbufp], ecx 934 ; mov r0,inbufp / to input buffer pointer 935 00000539 890D[7E0C0000] mov [einbuf], ecx 936 ; mov r0,einbuf / and initialize pointer to end of 937 ; / character string 938 0000053F 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 00000540 BA01000000 mov edx, 1 943 gbuf0: ;1: 944 00000545 41 inc ecx 945 ; inc 0f / this routine filles inbuf with line from 946 ; / console - if there is cnc 947 00000546 51 push ecx 948 ; edx = 1 949 sys _read, 0, och 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 00000547 BB00000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 0000054C B9[820C0000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 00000551 B803000000 <1> mov eax, %1 100 00000556 CD30 <1> int 30h 950 00000558 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 00000559 7254 jc short xit1 ; 29/05/2022 955 ; bcs xit1 / error exit 956 0000055B 21C0 and eax, eax 957 ; tst r0 / a zero input is end of file 958 0000055D 7450 jz short xit1 ; 29/05/2022 959 ; beq xit1 / exit 960 0000055F FF05[7E0C0000] inc dword [einbuf] ; 08/04/2014 (24/08/2015, 32 bit) 961 00000565 A0[820C0000] mov al, [och] 962 0000056A 803D[8B060000]00 cmp byte [_at], 0 963 00000571 7608 jna short gbuf1 964 00000573 3C08 cmp al, 8 ; backspace 965 00000575 746B je short gbuf3 966 00000577 3C7F cmp al, 127 ; delete 967 00000579 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 0000057B 81F9[7A0C0000] cmp ecx, inbuf + 256 974 ; cmp 0b,$inbuf+256. / have we exceeded 975 ; input buffer size 976 00000581 732C jnb short xit1 ; 29/05/2022 977 ; bhis xit1 / if so, exit assume some sort of binary 978 ; 08/04/2014 979 00000583 3C0D cmp al, 0Dh 980 00000585 752F jne short gbuf8 981 00000587 8B1D[7E0C0000] mov ebx, [einbuf] 982 0000058D 4B dec ebx 983 0000058E 8803 mov [ebx], al 984 00000590 C3 retn 985 986 gbuf2: 987 ; 28/12/2015 988 00000591 803D[8B060000]00 cmp byte [_at], 0 989 00000598 76AB jna short gbuf0 ; 29/05/2022 990 gbuf7: 991 0000059A 51 push ecx 992 ;mov [och], al 993 ; edx = 1 994 sys _write, 1, och 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 0000059B BB01000000 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 000005A0 B9[820C0000] <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 000005A5 B804000000 <1> mov eax, %1 100 000005AA CD30 <1> int 30h 995 ;sys _write, 1, och, 1 ; echo (write char on tty) 996 000005AC 59 pop ecx 997 000005AD EB96 jmp short gbuf0 ; 29/05/2022 998 999 xit1: ; 29/05/2022 1000 sys _exit 86 <1> 87 <1> 88 <1> 89 <1> %if %0 >= 2 90 <1> mov ebx, %2 91 <1> %if %0 >= 3 92 <1> mov ecx, %3 93 <1> 94 <1> %if %0 >= 4 95 <1> mov edx, %4 96 <1> %endif 97 <1> %endif 98 <1> %endif 99 000005AF B801000000 <1> mov eax, %1 100 000005B4 CD30 <1> int 30h 1001 ; sys exit 1002 1003 gbuf8: 1004 000005B6 89CB mov ebx, ecx 1005 000005B8 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 000005BA 803D[8B060000]00 cmp byte [_at], 0 ; at > 0 --> tty input 1014 000005C1 7682 jna short gbuf0 1015 000005C3 3C1B cmp al, 1Bh ; ESC 1016 000005C5 75CA jne short gbuf2 1017 000005C7 B8[7A0B0000] mov eax, inbuf 1018 000005CC A3[7A0C0000] mov [inbufp], eax 1019 000005D1 A3[7E0C0000] mov [einbuf], eax 1020 000005D6 E9B5FAFFFF 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 000005DB C605[820C0000]08 mov byte [och], 8 ; 06/12/2013 1039 gbuf3: 1040 ; 08/04/2014 1041 000005E2 FF0D[7E0C0000] dec dword [einbuf] ; (24/08/2015, 32 bit code) 1042 ; 12/12/2013 1043 000005E8 49 dec ecx 1044 000005E9 81F9[7A0B0000] cmp ecx, inbuf 1045 000005EF 7203 jb short gbuf4 1046 000005F1 49 dec ecx 1047 ; 08/04/2014 1048 ;jmp short gbuf2 1049 000005F2 EBA6 jmp short gbuf7 1050 gbuf4: 1051 ;mov al, 7 1052 000005F4 C605[820C0000]07 mov byte [och], 07h ; beep 1053 ; 08/04/2014 1054 ;jmp short gbuf2 1055 000005FB 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 000005FD 0D0A msg_unix_sh: db 0Dh, 0Ah 1072 000005FF 526574726F20556E69- db 'Retro Unix 386 v1.1 - shell' 1072 00000608 78203338362076312E- 1072 00000611 31202D207368656C6C 1073 ;db 0Dh, 0Ah 1074 msgsh_size equ $ - msg_unix_sh 1075 ;db 0 1076 0000061A 31372F30362F323032- db '17/06/2022' 1076 00000623 32 1077 00000624 0D0A00 nextline: db 0Dh, 0Ah, 0 1078 ;Error messages: 1079 00000627 496E707574206E6F74- msgNotFound: db 'Input not found', 0 1079 00000630 20666F756E6400 1080 00000637 41726720636F756E74- msgArgCount: db 'Arg count', 0 1080 00000640 00 1081 00000641 426164206469726563- msgBadDir: db 'Bad directory', 0 1081 0000064A 746F727900 1082 0000064F 54727920616761696E- msgTryAgain: db 'Try again', 0 1082 00000658 00 1083 00000659 222720696D62616C61- msgImbalance: db 22h, 27h, 20h, 'imbalance', 0 1083 00000662 6E636500 1084 00000666 496E7075742066696C- msgInputFile: db 'Input file', 0 1084 0000066F 6500 1085 00000671 4F7574707574206669- msgOutputFile: db 'Output file', 0 1085 0000067A 6C6500 1086 0000067D 4E6F20636F6D6D616E- msgNoCmd: db 'No command', 0 1086 00000686 6400 1087 1088 ; /// Commands, files, parameters 1089 1090 ; 27/12/2015 1091 FCAT: ; '>>' 1092 00000688 00 db 0 1093 1094 ;quest: 1095 ;db '?', 0Dh, 0Ah 1096 ; 1097 1098 prompt: 1099 00000689 0D0A db 0Dh, 0Ah 1100 _at: 1101 0000068B 4020 db '@ ' 1102 ;<@ > 1103 p_size equ $ - prompt 1104 1105 0000068D 6563686F00 qecho: db 'echo', 0 1106 ; 1107 00000692 636400 qcd: db 'cd', 0 1108 ; 1109 qchdir: 1110 00000695 636864697200 db 'chdir', 0 1111 ; 1112 glogin: 1113 0000069B 6C6F67696E00 db 'login', 0 1114 ; 1115 shell: 1116 000006A1 2F62696E2F736800 db '/bin/sh', 0 1117 ; 1118 glob: 1119 000006A9 2F6574632F676C6F62- db '/etc/glob', 0 1119 000006B2 00 1120 ; 1121 binpb: 1122 000006B3 2F62696E2F db '/bin/' 1123 ; 1124 1125 ;----------------------------------------------------------------- 1126 ; bss - uninitialized data 1127 ;----------------------------------------------------------------- 1128 1129 bss_start: 1130 1131 ABSOLUTE bss_start 1132 1133 parbuf: 1134 000006B8 resb 1000 1135 ; .=.+1000. 1136 alignb 2 1137 ;.even 1138 param: 1139 00000AA0 ???????? resd 1 1140 ;.=.+2 1141 glflag: 1142 00000AA4 ?? resb 1 1143 00000AA5 ?? resb 1 1144 ;.=.+2 1145 infile: 1146 00000AA6 ???????? resd 1 1147 ; .=.+2 1148 outfile: 1149 00000AAA ???????? resd 1 1150 ;.=.+2 1151 ; parp-4 1152 00000AAE ???????? resd 1 1153 ;.=.+2 / room for glob 1154 parp: 1155 00000AB2 resb 200 1156 ;.=.+200. 1157 inbuf: 1158 00000B7A resb 256 1159 ;.=.+256. 1160 ;escap: 1161 ;resw 1 1162 ;.=.+2 1163 inbufp: 1164 00000C7A ???????? resd 1 1165 ;.=.+2 1166 einbuf: 1167 00000C7E ???????? resd 1 1168 ;.=.+2 1169 och: 1170 00000C82 ?? resb 1 1171 00000C83 ?? resb 1 1172 ;.=.+2 1173 shellarg: 1174 00000C84 ???????? resd 1 1175 ;.=.+2 1176 escap: 1177 00000C88 ?? resb 1 1178 ; 1179 00000C89 ?? resb 1 1180 1181 stbuf: ; 17/06/2022 - Retro UNIX 386 v1.1 1182 00000C8A resb 34 ; 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