1 ; **************************************************************************** 2 ; ln386.s (ln1.s) - by Erdogan Tan - 18/05/2022 3 ; ---------------------------------------------------------------------------- 4 ; Retro UNIX 386 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 ln1.s -l ln1.txt -o ln1 -Z error.txt)) 16 17 ; ln1.s - 18/05/2022 - Retro UNIX 386 v1 & v1.1 & v1.2 18 ; ln0.s - 21/05/2022 - Retro UNIX 8086 v1 (16 bit 'ln1.s') 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 ; Retro UNIX 386 v1 system call format: 90 ; sys systemcall (eax) , , 91 92 ; 11/03/2022 93 ; Note: Above 'sys' macro has limitation about register positions; 94 ; ebx, ecx, edx registers must not be used after their 95 ; positions in sys macro. 96 ; for example: 97 ; 'sys _write, 1, msg, ecx' is defective, because 98 ; ecx will be used/assigned before edx in 'sys' macro. 99 ; correct order may be: 100 ; 'sys _write, 1, msg, eax ; (eax = byte count) 101 102 struc stat 103 ; Note: This is for Retro UNIX v1.2 'sysstat' output !!! 104 ; (66 bytes) 105 00000000 ???? .inode: resw 1 106 00000002 ???? .mode: resw 1 107 00000004 ???? .nlinks: resw 1 108 00000006 ???? .uid: resw 1 109 00000008 ?? .gid: resb 1 110 00000009 ?? .size_h: resb 1 111 0000000A ???????? .size: resd 1 112 0000000E .dskptr: resd 10 113 00000036 ???????? .atime: resd 1 114 0000003A ???????? .mtime: resd 1 115 0000003E ???????? .ctime: resd 1 116 .strucsize: 117 endstruc 118 119 ;struc stat 120 ; ; Note: Retro UNIX v2 'sysstat' output DRAFT !!! 121 ; ; (72 bytes) 122 ; .idev: resb 1 123 ; .rsvd: resb 3 124 ; .inum: resd 1 125 ; .mode: resw 1 126 ; .nlinks: resw 1 127 ; .uid: resw 1 128 ; .gid: resb 1 129 ; .size_h: resb 1 130 ; .size: resd 1 131 ; .dskptr: resd 10 132 ; .atime: resd 1 133 ; .mtime: resd 1 134 ; .ctime: resd 1 135 ; .strucsize: 136 ;endstruc 137 138 ;S_IFMT equ 0F000h ; /* type of file */ 139 ;S_IFDIR equ 04000h ; /* directory */ 140 ;S_IFCHR equ 02000h ; /* character special */ 141 ;S_IFBLK equ 06000h ; /* block special */ 142 ;S_IFREG equ 08000h ; /* regular */ 143 ;S_ISUID equ 00800h ; /* set user id on execution */ 144 ;S_ISGID equ 00400h ; /* set group id on execution */ 145 ;S_IREAD equ 00100h ; /* read permission, owner */ 146 ;S_IWRITE equ 00080h ; /* write permission, owner */ 147 ;S_IEXEC equ 00040h ; /* execute/search permission, owner */ 148 149 S_IFMT equ 0F0h ; /* type of file */ 150 S_IFDIR equ 040h ; /* directory */ 151 S_IFCHR equ 020h ; /* character special */ 152 S_IFBLK equ 060h ; /* block special */ 153 S_IFREG equ 080h ; /* regular */ 154 S_ISUID equ 008h ; /* set user id on execution */ 155 S_ISGID equ 004h ; /* set group id on execution */ 156 S_IREAD equ 001h ; /* read permission, owner */ 157 S_IWRITE equ 080h ; /* write permission, owner */ 158 S_IEXEC equ 040h ; /* execute/search permission, owner */ 159 160 ;; UNIX v1 inode 161 ;; byte 1 162 ;S_ALLOC equ 080h ; Allocated flag 163 ;S_IFDIR equ 040h ; Directory flag 164 ;S_IFMDF equ 020h ; File modified flag (always on) 165 ;S_IFLRG equ 010h ; Large File flag 166 ;; byte 0 167 ;S_ISUID equ 020h ; Set User ID On Execution flag 168 ;S_IEXEC equ 010h ; Executable File flag 169 ;S_IREAD equ 008h ; Owner's Read Permission flag 170 ;S_IWRITE equ 004h ; Owner's Write Permission flag 171 172 ;----------------------------------------------------------------- 173 ; text - code 174 ;----------------------------------------------------------------- 175 176 [BITS 32] ; 32-bit intructions (for 80386 protected mode) 177 178 [ORG 0] 179 180 START_CODE: 181 ; 21/05/2022 182 ; 18/05/2022 183 ; 17/05/2022 184 00000000 89E6 mov esi, esp 185 00000002 58 pop eax ; number of arguments 186 00000003 5A pop edx ; argv[0] 187 ;;mov [argc], eax 188 ;mov [argc], al 189 190 ;cmp eax, 2 191 00000004 3C02 cmp al, 2 192 00000006 7321 jnb short ln_0 193 00000008 FEC8 dec al 194 0000000A 7516 jnz short ln_usage 195 sys _msg, program_msg, 255, 0Fh 72 <1> 73 <1> 74 <1> 75 <1> %if %0 >= 2 76 0000000C BB[D3000000] <1> mov ebx, %2 77 <1> %if %0 >= 3 78 00000011 B9FF000000 <1> mov ecx, %3 79 <1> 80 <1> %if %0 >= 4 81 00000016 BA0F000000 <1> mov edx, %4 82 <1> %endif 83 <1> %endif 84 <1> %endif 85 0000001B B823000000 <1> mov eax, %1 86 00000020 CD30 <1> int 30h 196 ln_usage: 197 ;sys _msg, usage_msg, 255, 07h 198 00000022 B8[0A010000] mov eax, usage_msg 199 ;call print_msg 200 00000027 EB6D jmp short ln_5 201 ;ln_exit: 202 ; sys _exit ; sys exit 203 ;;hlt: 204 ;; nop 205 ;; nop 206 ;; jmp short hlt 207 208 ln_0: 209 ; 21/05/2022 210 00000029 5F pop edi ; argv[1] 211 0000002A 7719 ja short ln_3 ; al > 2 212 213 ; same file name (different directories) 214 ; (new file is in current directory) 215 0000002C 89FE mov esi, edi 216 0000002E 89F2 mov edx, esi 217 ln_1: 218 00000030 AC lodsb 219 00000031 08C0 or al, al 220 00000033 7408 jz short ln_2 221 00000035 3C2F cmp al, '/' 222 00000037 75F7 jne short ln_1 223 00000039 89F2 mov edx, esi ; last '/' + 1 224 0000003B EBF3 jmp short ln_1 225 ln_2: 226 0000003D 4A dec edx ; last '/' 227 0000003E 39FA cmp edx, edi 228 00000040 763A jna short err 229 00000042 42 inc edx ; last '/' + 1 ; = argv[2] 230 00000043 EB01 jmp short ln_4 231 ln_3: 232 ; different file name 233 00000045 5A pop edx ; argv[2] 234 ln_4: 235 sys _stat, edi, stbuf 72 <1> 73 <1> 74 <1> 75 <1> %if %0 >= 2 76 00000046 89FB <1> mov ebx, %2 77 <1> %if %0 >= 3 78 00000048 B9[7C010000] <1> mov ecx, %3 79 <1> 80 <1> %if %0 >= 4 81 <1> mov edx, %4 82 <1> %endif 83 <1> %endif 84 <1> %endif 85 0000004D B812000000 <1> mov eax, %1 86 00000052 CD30 <1> int 30h 236 00000054 7253 jc short ln_not_exists 237 238 ; check retro unix v2 inode flags 239 ; (a bit different than unix v7 inode flags) 240 ; if it is a directory.. 241 ; regular file flag and dir flag must be 1 242 00000056 A0[7F010000] mov al, [stbuf+stat.mode+1] 243 0000005B 24C0 and al, S_IFDIR|S_IFREG ; S_IFREG = S_ALLOC 244 0000005D 3CC0 cmp al, S_IFDIR|S_IFREG ; directory ? 245 0000005F 744F je short ln_is_dir ; yes 246 247 sys _link, edi, edx 72 <1> 73 <1> 74 <1> 75 <1> %if %0 >= 2 76 00000061 89FB <1> mov ebx, %2 77 <1> %if %0 >= 3 78 00000063 89D1 <1> mov ecx, %3 79 <1> 80 <1> %if %0 >= 4 81 <1> mov edx, %4 82 <1> %endif 83 <1> %endif 84 <1> %endif 85 00000065 B809000000 <1> mov eax, %1 86 0000006A CD30 <1> int 30h 248 0000006C 7334 jnc short ln_6 249 250 ; 21/05/2022 251 0000006E B8[58010000] mov eax, cant_link_msg 252 00000073 E83F000000 call print_msg 253 00000078 89F8 mov eax, edi 254 0000007A EB1A jmp short ln_5 255 256 err: 257 0000007C B8[68010000] mov eax, err_msg 258 00000081 EB13 jmp short ln_5 259 260 ln_p_error: 261 00000083 B8[2B010000] mov eax, ln_header 262 00000088 E82A000000 call print_msg 263 0000008D 89F8 mov eax, edi 264 0000008F E823000000 call print_msg 265 00000094 89E8 mov eax, ebp 266 ln_5: 267 00000096 E81C000000 call print_msg 268 ln_exit: 269 sys _exit ; sys exit 72 <1> 73 <1> 74 <1> 75 <1> %if %0 >= 2 76 <1> mov ebx, %2 77 <1> %if %0 >= 3 78 <1> mov ecx, %3 79 <1> 80 <1> %if %0 >= 4 81 <1> mov edx, %4 82 <1> %endif 83 <1> %endif 84 <1> %endif 85 0000009B B801000000 <1> mov eax, %1 86 000000A0 CD30 <1> int 30h 270 ;hlt: 271 ; nop 272 ; nop 273 ; jmp short hlt 274 275 ln_6: 276 000000A2 B8[74010000] mov eax, ok_msg 277 000000A7 EBED jmp short ln_5 278 279 ln_not_exists: 280 000000A9 BD[32010000] mov ebp, not_exists_msg 281 000000AE EBD3 jmp short ln_p_error 282 283 ln_is_dir: 284 000000B0 BD[45010000] mov ebp, is_dir_msg 285 000000B5 EBCC jmp short ln_p_error 286 287 ;----------------------------------------------------------------- 288 289 print_msg: 290 ; eax = asciiz string address 291 000000B7 89C6 mov esi, eax 292 000000B9 4E dec esi 293 nextchr: 294 000000BA 46 inc esi 295 000000BB 803E00 cmp byte [esi], 0 296 000000BE 77FA ja short nextchr 297 ;cmp [esi], 0Dh 298 ;ja short nextchr 299 000000C0 29C6 sub esi, eax 300 ; esi = asciiz string length 301 ; 302 sys _write, 1, eax, esi 72 <1> 73 <1> 74 <1> 75 <1> %if %0 >= 2 76 000000C2 BB01000000 <1> mov ebx, %2 77 <1> %if %0 >= 3 78 000000C7 89C1 <1> mov ecx, %3 79 <1> 80 <1> %if %0 >= 4 81 000000C9 89F2 <1> mov edx, %4 82 <1> %endif 83 <1> %endif 84 <1> %endif 85 000000CB B804000000 <1> mov eax, %1 86 000000D0 CD30 <1> int 30h 303 ; 304 000000D2 C3 retn 305 306 ;----------------------------------------------------------------- 307 ; data - initialized data 308 ;----------------------------------------------------------------- 309 310 ;;argc: dd 0 311 ;argc: db 0 312 313 ; ---------------------------------------------------------------- 314 315 program_msg: 316 000000D3 0D0A db 0Dh, 0Ah 317 000000D5 526574726F20554E49- db 'Retro UNIX 386 v1 LINK by Erdogan TAN - 21/05/2022' 317 000000DE 582033383620763120- 317 000000E7 4C494E4B2062792045- 317 000000F0 72646F67616E205441- 317 000000F9 4E202D2032312F3035- 317 00000102 2F32303232 318 00000107 0D0A00 db 0Dh, 0Ah, 0 319 320 usage_msg: 321 0000010A 0D0A db 0Dh, 0Ah 322 0000010C 55736167653A206C6E- db 'Usage: ln target [ newname ]' 322 00000115 20746172676574205B- 322 0000011E 206E65776E616D6520- 322 00000127 5D 323 nextline: 324 00000128 0D0A00 db 0Dh, 0Ah, 0 325 ln_header: 326 0000012B 0D0A db 0Dh, 0Ah 327 0000012D 6C6E3A20 db 'ln: ' 328 00000131 00 db 0 329 not_exists_msg: 330 ;db 0Dh, 0Ah 331 00000132 20646F6573206E6F74- db ' does not exist ' 331 0000013B 20657869737420 332 00000142 0D0A00 db 0Dh, 0Ah, 0 333 334 is_dir_msg: 335 00000145 206973206120646972- db ' is a directory ' 335 0000014E 6563746F727920 336 00000155 0D0A00 db 0Dh, 0Ah, 0 337 338 cant_link_msg: 339 00000158 0D0A db 0Dh, 0Ah 340 0000015A 43616E206E6F74206C- db 'Can not link ' 340 00000163 696E6B20 341 ;db 0Dh, 0Ah, 0 342 00000167 00 db 0 ; 21/05/2022 343 344 err_msg: 345 00000168 0D0A db 0Dh, 0Ah 346 0000016A 4572726F722120 db 'Error! ' 347 00000171 0D0A00 db 0Dh, 0Ah, 0 348 349 ok_msg: 350 00000174 0D0A db 0Dh, 0Ah 351 00000176 4F4B2E db 'OK.' 352 00000179 0D0A00 db 0Dh, 0Ah, 0 353 354 ;----------------------------------------------------------------- 355 ; bss - uninitialized data 356 ;----------------------------------------------------------------- 357 358 align 2 359 360 bss_start: 361 362 ABSOLUTE bss_start 363 364 ;stbuf: resb 34 ; for Retro UNIX 386 v1.1 (34 byte sysstat data) 365 0000017C stbuf: resb 66 ; for Retro UNIX 386 v1.2 (66 byte sysstat data) 366 367 ; 17/05/2022 368 ;----------------------------------------------------------------- 369 ; Original UNIX v2 - ln (utility) pdp-11 asm source code (ln.s) 370 ;----------------------------------------------------------------- 371 ;/* UNIX V2 source code: see www.tuhs.org for details. */; 372 ; 373 ;/* 374 ; * ln target [ new name ] 375 ; */ 376 ; ---------------------------------------------------------------- 377 ;/ link command 378 ; 379 ;ln: 380 ; mov sp,r5 381 ; cmp (r5)+,$2 382 ; bhis 1f 383 ; sys exit 384 ;1: 385 ; beq 1f 386 ; tst (r5)+ 387 ; mov (r5)+,0f 388 ; mov (r5),0f+2 389 ; br 2f 390 ;1: 391 ; tst (r5)+ 392 ; mov (r5),0f 393 ; mov (r5),r4 394 ;1: 395 ; tstb (r4)+ 396 ; bne 1b 397 ;1: 398 ; cmpb -(r4),$'/ 399 ; beq 1f 400 ; cmp (r5),r4 401 ; bne 1b 402 ; br err 403 ;1: 404 ; inc r4 405 ; mov r4,0f+2 406 ;2: 407 ; mov 0f,2f 408 ; sys stat; 2:..; stbuf 409 ; bes err 410 ; bit $40000,stbuf+2 411 ; bne err 412 ; sys link; 0:..; .. 413 ; bes err 414 ; sys exit 415 ; 416 ;err: 417 ; mov $1,r0 418 ; sys write; quest; 2 419 ; sys exit 420 ; 421 ;quest: 422 ; 423 ; 424 ;.bss 425 ;stbuf: .=.+40. 426 427 ;----------------------------------------------------------------- 428 ; Original UNIX v5 - ln (utility) c source code (ln.c) 429 ;----------------------------------------------------------------- 430 ;/* UNIX V5 source code: see www.tuhs.org for details. */; 431 ; 432 ;/* 433 ; * ln target [ new name ] 434 ; */ 435 ; 436 ;struct ibuf { 437 ; int inum; 438 ; int iflags; 439 ; char inl; 440 ; char iuid; 441 ; int isize; 442 ; int iaddr[8]; 443 ; char *ictime[2]; 444 ; char *imtime[2]; 445 ; int fill; 446 ;}; 447 ; 448 ;#define DIR 040000 449 ;#define FMT 060000 450 ; 451 ;main(argc, argv) 452 ;char **argv; 453 ;{ 454 ; static struct ibuf statb; 455 ; register char *np; 456 ; 457 ; if (argc<2) { 458 ; write(1, "Usage: ln target [ newname ]\n", 29); 459 ; exit(1); 460 ; } 461 ; if (argc==2) { 462 ; np = argv[1]; 463 ; while(*np++); 464 ; while (*--np!='/' && np>argv[1]); 465 ; np++; 466 ; argv[2] = np; 467 ; } 468 ; stat(argv[1], &statb); 469 ; if ((statb.iflags&FMT) == DIR) { 470 ; write(1, "No directory link\n", 18); 471 ; exit(1); 472 ; } 473 ; if (link(argv[1], argv[2])<0) { 474 ; write(1, "Can't link\n", 11); 475 ; exit(1); 476 ; } 477 ; exit(0); 478 ;} 479 480 ;----------------------------------------------------------------- 481 ; Original UNIX v7 - ln (utility) c source code (ln.c) 482 ;----------------------------------------------------------------- 483 ;/* UNIX V7 source code: see www.tuhs.org for details. */; 484 ; 485 ;/* 486 ; * ln [ -f ] target [ new name ] 487 ; */ 488 ; 489 ;#include 490 ;#include 491 ;#include "stdio.h" 492 ;char *rindex(); 493 ; 494 ;main(argc, argv) 495 ;char **argv; 496 ;{ 497 ; struct stat statb; 498 ; register char *np; 499 ; int fflag = 0; 500 ; char nb[100], *name=nb, *arg2; 501 ; int statres; 502 ; 503 ; if (argc >1 && strcmp(argv[1], "-f")==0) { 504 ; argc--; 505 ; argv++; 506 ; fflag++; 507 ; } 508 ; if (argc<2 || argc>3) { 509 ; printf("Usage: ln target [ newname ]\n"); 510 ; exit(1); 511 ; } 512 ; np = rindex(argv[1], '/'); 513 ; if (np==0) 514 ; np = argv[1]; 515 ; else 516 ; np++; 517 ; if (argc==2) 518 ; arg2 = np; 519 ; else 520 ; arg2 = argv[2]; 521 ; statres = stat(argv[1], &statb); 522 ; if (statres<0) { 523 ; printf ("ln: %s does not exist\n", argv[1]); 524 ; exit(1); 525 ; } 526 ; if (fflag==0 && (statb.st_mode&S_IFMT) == S_IFDIR) { 527 ; printf("ln: %s is a directory\n", argv[1]); 528 ; exit(1); 529 ; } 530 ; statres = stat(arg2, &statb); 531 ; if (statres>=0 && (statb.st_mode&S_IFMT) == S_IFDIR) 532 ; sprintf(name, "%s/%s", arg2, np); 533 ; else 534 ; name = arg2; 535 ; if (link(argv[1], name)<0) { 536 ; perror("ln"); 537 ; exit(1); 538 ; } 539 ; exit(0); 540 ;}