1 ; **************************************************************************** 2 ; ln8086.s (ln0.s) - by Erdogan Tan - 18/05/2022 3 ; ---------------------------------------------------------------------------- 4 ; Retro UNIX 8086 v1 - ln -- link file (to file) 5 ; 6 ; [ Last Modification: 21/05/2022 ] 7 ; 8 ; Derived from (original) UNIX v2 (ln.s) and v5 'ln.c' source Code 9 ; Ref: 10 ; www.tuhs.org (https://minnie.tuhs.org) 11 ; **************************************************************************** 12 ; [ v5root.tar - usr/source/s1/ln.c (archive date: 27-11-1974) ] 13 ; 14 ; Assembler: NASM v2.15 15 ; ((nasm ln0.s -l ln0.txt -o ln0 -Z error.txt)) 16 17 ; ln0.s - 21/05/2022 - Retro UNIX 8086 v1 (16 bit 'ln1.s') 18 ; ln1.s - 18/05/2022 - Retro UNIX 386 v1 & v1.1 & v1.2 19 20 ; 12/01/2022 (Retro UNIX 386 v1.2) 21 ; 13/10/2015 22 23 ; UNIX v1 system calls 24 _rele equ 0 25 _exit equ 1 26 _fork equ 2 27 _read equ 3 28 _write equ 4 29 _open equ 5 30 _close equ 6 31 _wait equ 7 32 _creat equ 8 33 _link equ 9 34 _unlink equ 10 35 _exec equ 11 36 _chdir equ 12 37 _time equ 13 38 _mkdir equ 14 39 _chmod equ 15 40 _chown equ 16 41 _break equ 17 42 _stat equ 18 43 _seek equ 19 44 _tell equ 20 45 _mount equ 21 46 _umount equ 22 47 _setuid equ 23 48 _getuid equ 24 49 _stime equ 25 50 _quit equ 26 51 _intr equ 27 52 _fstat equ 28 53 _emt equ 29 54 _mdate equ 30 55 _stty equ 31 56 _gtty equ 32 57 _ilgins equ 33 58 _sleep equ 34 ; Retro UNIX 8086 v1 feature only ! 59 _msg equ 35 ; Retro UNIX 386 v1 feature only ! 60 _geterr equ 36 ; Retro UNIX 386 v1 feature only ! 61 ; 12/01/2022 - Retro UNIX 386 v1.2 62 ; Retro UNIX 386 v2 system calls 63 _setgid equ 37 64 _getgid equ 38 65 _sysver equ 39 ; (get) Retro Unix 386 version 66 67 ;;; 68 ESCKey equ 1Bh 69 EnterKey equ 0Dh 70 71 ;%macro sys 1-4 72 ; ; 03/09/2015 73 ; ; 13/04/2015 74 ; ; Retro UNIX 386 v1 system call. 75 ; %if %0 >= 2 76 ; mov ebx, %2 77 ; %if %0 >= 3 78 ; mov ecx, %3 79 ; ;%if %0 = 4 80 ; %if %0 >= 4 ; 11/03/2022 81 ; mov edx, %4 82 ; %endif 83 ; %endif 84 ; %endif 85 ; mov eax, %1 86 ; int 30h 87 ;%endmacro 88 89 %macro sys 1-4 90 ; Retro UNIX 8086 v1 system call. 91 %if %0 >= 2 92 mov bx, %2 93 %if %0 >= 3 94 mov cx, %3 95 %if %0 >= 4 96 mov dx, %4 97 %endif 98 %endif 99 %endif 100 mov ax, %1 101 int 20h 102 %endmacro 103 104 ;; Retro UNIX 386 v1 system call format: 105 ;; sys systemcall (eax) , , 106 107 ;; 11/03/2022 108 ;; Note: Above 'sys' macro has limitation about register positions; 109 ;; ebx, ecx, edx registers must not be used after their 110 ;; positions in sys macro. 111 ;; for example: 112 ;; 'sys _write, 1, msg, ecx' is defective, because 113 ;; ecx will be used/assigned before edx in 'sys' macro. 114 ;; correct order may be: 115 ;; 'sys _write, 1, msg, eax ; (eax = byte count) 116 117 ; Retro UNIX 8086 v1 system call format: 118 ; sys systemcall (ax) , , 119 120 ;struc stat 121 ; ; Note: This is for Retro UNIX v1.2 'sysstat' output !!! 122 ; ; (66 bytes) 123 ; .inode: resw 1 124 ; .mode: resw 1 125 ; .nlinks: resw 1 126 ; .uid: resw 1 127 ; .gid: resb 1 128 ; .size_h: resb 1 129 ; .size: resd 1 130 ; .dskptr: resd 10 131 ; .atime: resd 1 132 ; .mtime: resd 1 133 ; .ctime: resd 1 134 ; .strucsize: 135 ;endstruc 136 137 ;;struc stat 138 ;; ; Note: Retro UNIX v2 'sysstat' output DRAFT !!! 139 ;; ; (72 bytes) 140 ;; .idev: resb 1 141 ;; .rsvd: resb 3 142 ;; .inum: resd 1 143 ;; .mode: resw 1 144 ;; .nlinks: resw 1 145 ;; .uid: resw 1 146 ;; .gid: resb 1 147 ;; .size_h: resb 1 148 ;; .size: resd 1 149 ;; .dskptr: resd 10 150 ;; .atime: resd 1 151 ;; .mtime: resd 1 152 ;; .ctime: resd 1 153 ;; .strucsize: 154 ;;endstruc 155 156 ;;S_IFMT equ 0F000h ; /* type of file */ 157 ;;S_IFDIR equ 04000h ; /* directory */ 158 ;;S_IFCHR equ 02000h ; /* character special */ 159 ;;S_IFBLK equ 06000h ; /* block special */ 160 ;;S_IFREG equ 08000h ; /* regular */ 161 ;;S_ISUID equ 00800h ; /* set user id on execution */ 162 ;;S_ISGID equ 00400h ; /* set group id on execution */ 163 ;;S_IREAD equ 00100h ; /* read permission, owner */ 164 ;;S_IWRITE equ 00080h ; /* write permission, owner */ 165 ;;S_IEXEC equ 00040h ; /* execute/search permission, owner */ 166 ; 167 ;S_IFMT equ 0F0h ; /* type of file */ 168 ;S_IFDIR equ 040h ; /* directory */ 169 ;S_IFCHR equ 020h ; /* character special */ 170 ;S_IFBLK equ 060h ; /* block special */ 171 ;S_IFREG equ 080h ; /* regular */ 172 ;S_ISUID equ 008h ; /* set user id on execution */ 173 ;S_ISGID equ 004h ; /* set group id on execution */ 174 ;S_IREAD equ 001h ; /* read permission, owner */ 175 ;S_IWRITE equ 080h ; /* write permission, owner */ 176 ;S_IEXEC equ 040h ; /* execute/search permission, owner */ 177 178 struc stat 179 ; Note: This is for Retro UNIX v1 'sysstat' output !!! 180 ; (34 bytes) 181 00000000 ???? .inode: resw 1 182 00000002 ???? .mode: resw 1 183 00000004 ?? .nlinks: resb 1 184 00000005 ?? .uid: resb 1 185 00000006 ???? .size: resw 1 186 00000008 .dskptr: resw 8 187 00000018 ???????? .ctime: resd 1 188 0000001C ???????? .mtime: resd 1 189 00000020 ???? .rsvd: resw 1 190 .strucsize: 191 endstruc 192 193 ; UNIX v1 inode 194 ; byte 1 195 S_ALLOC equ 080h ; Allocated flag 196 S_IFDIR equ 040h ; Directory flag 197 S_IFMDF equ 020h ; File modified flag (always on) 198 S_IFLRG equ 010h ; Large File flag 199 ; byte 0 200 S_ISUID equ 020h ; Set User ID On Execution flag 201 S_IEXEC equ 010h ; Executable File flag 202 S_IREAD equ 008h ; Owner's Read Permission flag 203 S_IWRITE equ 004h ; Owner's Write Permission flag 204 205 ; ---------------------------------------------------------------------------- 206 207 [BITS 16] ; 16-bit intructions (for 8086/x86 real mode) 208 209 [ORG 0] 210 211 START_CODE: 212 ; 21/05/2022 213 ; 18/05/2022 214 ; 17/05/2022 215 00000000 89E6 mov si, sp 216 00000002 58 pop ax ; number of arguments 217 00000003 5A pop dx ; argv[0] 218 ;;mov [argc], ax 219 ;mov [argc], al 220 221 ;cmp ax, 2 222 00000004 3C02 cmp al, 2 223 00000006 730F jnb short ln_0 224 00000008 FEC8 dec al 225 0000000A 7506 jnz short ln_usage 226 ; 21/05/2022 227 0000000C B8[9D00] mov ax, program_msg 228 0000000F E87300 call print_msg 229 ln_usage: 230 00000012 B8[D400] mov ax, usage_msg 231 ;call print_msg 232 00000015 EB57 jmp short ln_5 233 ;ln_exit: 234 ; sys _exit ; sys exit 235 ;;hlt: 236 ;; nop 237 ;; nop 238 ;; jmp short hlt 239 240 ln_0: 241 ; 21/05/2022 242 00000017 5F pop di ; argv[1] 243 00000018 7719 ja short ln_3 ; al > 2 244 245 ; same file name (different directories) 246 ; (new file is in current directory) 247 0000001A 89FE mov si, di 248 0000001C 89F2 mov dx, si 249 ln_1: 250 0000001E AC lodsb 251 0000001F 08C0 or al, al 252 00000021 7408 jz short ln_2 253 00000023 3C2F cmp al, '/' 254 00000025 75F7 jne short ln_1 255 00000027 89F2 mov dx, si ; last '/' + 1 256 00000029 EBF3 jmp short ln_1 257 ln_2: 258 0000002B 4A dec dx ; last '/' 259 0000002C 39FA cmp dx, di 260 0000002E 762C jna short err 261 00000030 42 inc dx ; last '/' + 1 ; = argv[2] 262 00000031 EB01 jmp short ln_4 263 ln_3: 264 ; different file name 265 00000033 5A pop dx ; argv[2] 266 ln_4: 267 sys _stat, di, stbuf 90 <1> 91 <1> %if %0 >= 2 92 00000034 89FB <1> mov bx, %2 93 <1> %if %0 >= 3 94 00000036 B9[4601] <1> mov cx, %3 95 <1> %if %0 >= 4 96 <1> mov dx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000039 B81200 <1> mov ax, %1 101 0000003C CD20 <1> int 20h 268 0000003E 723B jc short ln_not_exists 269 270 ; check if it is a directory.. 271 00000040 A0[4901] mov al, [stbuf+stat.mode+1] 272 ; 21/05/2022 273 ;and al, S_IFDIR|S_ALLOC ; (S_ALLOC = S_IFREG) 274 ;cmp al, S_IFDIR|S_ALLOC ; directory ? 275 ;je short ln_is_dir ; yes 276 00000043 2440 and al, S_IFDIR 277 00000045 7539 jnz short ln_is_dir ; yes 278 279 sys _link, di, dx 90 <1> 91 <1> %if %0 >= 2 92 00000047 89FB <1> mov bx, %2 93 <1> %if %0 >= 3 94 00000049 89D1 <1> mov cx, %3 95 <1> %if %0 >= 4 96 <1> mov dx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 0000004B B80900 <1> mov ax, %1 101 0000004E CD20 <1> int 20h 280 00000050 7324 jnc short ln_6 281 282 ; 21/05/2022 283 00000052 B8[2201] mov ax, cant_link_msg 284 00000055 E82D00 call print_msg 285 00000058 89F8 mov ax, di 286 0000005A EB12 jmp short ln_5 287 288 err: 289 0000005C B8[3201] mov ax, err_msg 290 0000005F EB0D jmp short ln_5 291 292 ln_p_error: 293 00000061 B8[F500] mov ax, ln_header 294 00000064 E81E00 call print_msg 295 00000067 89F8 mov ax, di 296 00000069 E81900 call print_msg 297 0000006C 89E8 mov ax, bp 298 ln_5: 299 0000006E E81400 call print_msg 300 ln_exit: 301 sys _exit ; sys exit 90 <1> 91 <1> %if %0 >= 2 92 <1> mov bx, %2 93 <1> %if %0 >= 3 94 <1> mov cx, %3 95 <1> %if %0 >= 4 96 <1> mov dx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000071 B80100 <1> mov ax, %1 101 00000074 CD20 <1> int 20h 302 ;hlt: 303 ; nop 304 ; nop 305 ; jmp short hlt 306 307 ln_6: 308 00000076 B8[3E01] mov ax, ok_msg 309 00000079 EBF3 jmp short ln_5 310 311 ln_not_exists: 312 0000007B BD[FC00] mov bp, not_exists_msg 313 0000007E EBE1 jmp short ln_p_error 314 315 ln_is_dir: 316 00000080 BD[0F01] mov bp, is_dir_msg 317 00000083 EBDC jmp short ln_p_error 318 319 ;----------------------------------------------------------------- 320 321 print_msg: 322 ; ax = asciiz string address 323 00000085 89C6 mov si, ax 324 00000087 4E dec si 325 nextchr: 326 00000088 46 inc si 327 00000089 803C00 cmp byte [si], 0 328 0000008C 77FA ja short nextchr 329 ;cmp [si], 0Dh 330 ;ja short nextchr 331 0000008E 29C6 sub si, ax 332 ; si = asciiz string length 333 ; 334 sys _write, 1, ax, si 90 <1> 91 <1> %if %0 >= 2 92 00000090 BB0100 <1> mov bx, %2 93 <1> %if %0 >= 3 94 00000093 89C1 <1> mov cx, %3 95 <1> %if %0 >= 4 96 00000095 89F2 <1> mov dx, %4 97 <1> %endif 98 <1> %endif 99 <1> %endif 100 00000097 B80400 <1> mov ax, %1 101 0000009A CD20 <1> int 20h 335 ; 336 0000009C C3 retn 337 338 ;----------------------------------------------------------------- 339 ; data - initialized data 340 ;----------------------------------------------------------------- 341 342 ;;argc: dd 0 343 ;argc: db 0 344 345 ; ---------------------------------------------------------------- 346 347 program_msg: 348 0000009D 0D0A db 0Dh, 0Ah 349 0000009F 526574726F20554E49- db 'Retro UNIX 386 v1 LINK by Erdogan TAN - 21/05/2022' 349 000000A8 582033383620763120- 349 000000B1 4C494E4B2062792045- 349 000000BA 72646F67616E205441- 349 000000C3 4E202D2032312F3035- 349 000000CC 2F32303232 350 000000D1 0D0A00 db 0Dh, 0Ah, 0 351 352 usage_msg: 353 000000D4 0D0A db 0Dh, 0Ah 354 000000D6 55736167653A206C6E- db 'Usage: ln target [ newname ]' 354 000000DF 20746172676574205B- 354 000000E8 206E65776E616D6520- 354 000000F1 5D 355 nextline: 356 000000F2 0D0A00 db 0Dh, 0Ah, 0 357 ln_header: 358 000000F5 0D0A db 0Dh, 0Ah 359 000000F7 6C6E3A20 db 'ln: ' 360 000000FB 00 db 0 361 not_exists_msg: 362 ;db 0Dh, 0Ah 363 000000FC 20646F6573206E6F74- db ' does not exist ' 363 00000105 20657869737420 364 0000010C 0D0A00 db 0Dh, 0Ah, 0 365 366 is_dir_msg: 367 0000010F 206973206120646972- db ' is a directory ' 367 00000118 6563746F727920 368 0000011F 0D0A00 db 0Dh, 0Ah, 0 369 370 cant_link_msg: 371 00000122 0D0A db 0Dh, 0Ah 372 00000124 43616E206E6F74206C- db 'Can not link ' 372 0000012D 696E6B20 373 ;db 0Dh, 0Ah, 0 374 00000131 00 db 0 ; 21/05/2022 375 376 err_msg: 377 00000132 0D0A db 0Dh, 0Ah 378 00000134 4572726F722120 db 'Error! ' 379 0000013B 0D0A00 db 0Dh, 0Ah, 0 380 381 ok_msg: 382 0000013E 0D0A db 0Dh, 0Ah 383 00000140 4F4B2E db 'OK.' 384 00000143 0D0A00 db 0Dh, 0Ah, 0 385 386 ;----------------------------------------------------------------- 387 ; bss - uninitialized data 388 ;----------------------------------------------------------------- 389 390 align 2 391 392 bss_start: 393 394 ABSOLUTE bss_start 395 396 00000146 stbuf: resb 34 ; for Retro UNIX 386 v1.1 (34 byte sysstat data) 397 ;stbuf: resb 66 ; for Retro UNIX 386 v1.2 (66 byte sysstat data) 398 399 ; 17/05/2022 400 ;----------------------------------------------------------------- 401 ; Original UNIX v2 - ln (utility) pdp-11 asm source code (ln.s) 402 ;----------------------------------------------------------------- 403 ;/* UNIX V2 source code: see www.tuhs.org for details. */; 404 ; 405 ;/* 406 ; * ln target [ new name ] 407 ; */ 408 ; ---------------------------------------------------------------- 409 ;/ link command 410 ; 411 ;ln: 412 ; mov sp,r5 413 ; cmp (r5)+,$2 414 ; bhis 1f 415 ; sys exit 416 ;1: 417 ; beq 1f 418 ; tst (r5)+ 419 ; mov (r5)+,0f 420 ; mov (r5),0f+2 421 ; br 2f 422 ;1: 423 ; tst (r5)+ 424 ; mov (r5),0f 425 ; mov (r5),r4 426 ;1: 427 ; tstb (r4)+ 428 ; bne 1b 429 ;1: 430 ; cmpb -(r4),$'/ 431 ; beq 1f 432 ; cmp (r5),r4 433 ; bne 1b 434 ; br err 435 ;1: 436 ; inc r4 437 ; mov r4,0f+2 438 ;2: 439 ; mov 0f,2f 440 ; sys stat; 2:..; stbuf 441 ; bes err 442 ; bit $40000,stbuf+2 443 ; bne err 444 ; sys link; 0:..; .. 445 ; bes err 446 ; sys exit 447 ; 448 ;err: 449 ; mov $1,r0 450 ; sys write; quest; 2 451 ; sys exit 452 ; 453 ;quest: 454 ; 455 ; 456 ;.bss 457 ;stbuf: .=.+40. 458 459 ;----------------------------------------------------------------- 460 ; Original UNIX v5 - ln (utility) c source code (ln.c) 461 ;----------------------------------------------------------------- 462 ;/* UNIX V5 source code: see www.tuhs.org for details. */; 463 ; 464 ;/* 465 ; * ln target [ new name ] 466 ; */ 467 ; 468 ;struct ibuf { 469 ; int inum; 470 ; int iflags; 471 ; char inl; 472 ; char iuid; 473 ; int isize; 474 ; int iaddr[8]; 475 ; char *ictime[2]; 476 ; char *imtime[2]; 477 ; int fill; 478 ;}; 479 ; 480 ;#define DIR 040000 481 ;#define FMT 060000 482 ; 483 ;main(argc, argv) 484 ;char **argv; 485 ;{ 486 ; static struct ibuf statb; 487 ; register char *np; 488 ; 489 ; if (argc<2) { 490 ; write(1, "Usage: ln target [ newname ]\n", 29); 491 ; exit(1); 492 ; } 493 ; if (argc==2) { 494 ; np = argv[1]; 495 ; while(*np++); 496 ; while (*--np!='/' && np>argv[1]); 497 ; np++; 498 ; argv[2] = np; 499 ; } 500 ; stat(argv[1], &statb); 501 ; if ((statb.iflags&FMT) == DIR) { 502 ; write(1, "No directory link\n", 18); 503 ; exit(1); 504 ; } 505 ; if (link(argv[1], argv[2])<0) { 506 ; write(1, "Can't link\n", 11); 507 ; exit(1); 508 ; } 509 ; exit(0); 510 ;} 511 512 ;----------------------------------------------------------------- 513 ; Original UNIX v7 - ln (utility) c source code (ln.c) 514 ;----------------------------------------------------------------- 515 ;/* UNIX V7 source code: see www.tuhs.org for details. */; 516 ; 517 ;/* 518 ; * ln [ -f ] target [ new name ] 519 ; */ 520 ; 521 ;#include 522 ;#include 523 ;#include "stdio.h" 524 ;char *rindex(); 525 ; 526 ;main(argc, argv) 527 ;char **argv; 528 ;{ 529 ; struct stat statb; 530 ; register char *np; 531 ; int fflag = 0; 532 ; char nb[100], *name=nb, *arg2; 533 ; int statres; 534 ; 535 ; if (argc >1 && strcmp(argv[1], "-f")==0) { 536 ; argc--; 537 ; argv++; 538 ; fflag++; 539 ; } 540 ; if (argc<2 || argc>3) { 541 ; printf("Usage: ln target [ newname ]\n"); 542 ; exit(1); 543 ; } 544 ; np = rindex(argv[1], '/'); 545 ; if (np==0) 546 ; np = argv[1]; 547 ; else 548 ; np++; 549 ; if (argc==2) 550 ; arg2 = np; 551 ; else 552 ; arg2 = argv[2]; 553 ; statres = stat(argv[1], &statb); 554 ; if (statres<0) { 555 ; printf ("ln: %s does not exist\n", argv[1]); 556 ; exit(1); 557 ; } 558 ; if (fflag==0 && (statb.st_mode&S_IFMT) == S_IFDIR) { 559 ; printf("ln: %s is a directory\n", argv[1]); 560 ; exit(1); 561 ; } 562 ; statres = stat(arg2, &statb); 563 ; if (statres>=0 && (statb.st_mode&S_IFMT) == S_IFDIR) 564 ; sprintf(name, "%s/%s", arg2, np); 565 ; else 566 ; name = arg2; 567 ; if (link(argv[1], name)<0) { 568 ; perror("ln"); 569 ; exit(1); 570 ; } 571 ; exit(0); 572 ;}