1 /** @file 2 EFI versions of NetBSD system calls. 3 4 Copyright (c) 2016, Daryl McDaniel. All rights reserved.<BR> 5 Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR> 6 This program and the accompanying materials are licensed and made available under 7 the terms and conditions of the BSD License that accompanies this distribution. 8 The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license. 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 #include <Uefi.h> 16 #include <Library/UefiLib.h> 17 #include <Library/UefiBootServicesTableLib.h> 18 #include <Library/BaseLib.h> 19 #include <Library/MemoryAllocationLib.h> 20 #include <Library/ShellLib.h> 21 22 #include <LibConfig.h> 23 #include <sys/EfiCdefs.h> 24 25 #include <sys/ansi.h> 26 #include <errno.h> 27 #include <stdarg.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <wchar.h> 31 #include <sys/poll.h> 32 #include <sys/fcntl.h> 33 #include <sys/stat.h> 34 #include <sys/syslimits.h> 35 #include <sys/filio.h> 36 #include <Efi/SysEfi.h> 37 #include <unistd.h> 38 #include <kfile.h> 39 #include <Device/Device.h> 40 #include <Device/IIO.h> 41 #include <MainData.h> 42 #include <extern.h> 43 44 /* EFI versions of BSD system calls used in stdio */ 45 46 /* Validate that fd refers to a valid file descriptor. 47 IsOpen is interpreted as follows: 48 - Positive fd must be OPEN 49 - Zero fd must be CLOSED 50 - Negative fd may be OPEN or CLOSED 51 52 @retval TRUE fd is VALID 53 @retval FALSE fd is INVALID 54 */ 55 BOOLEAN 56 ValidateFD( int fd, int IsOpen) 57 { 58 struct __filedes *filp; 59 BOOLEAN retval = FALSE; 60 61 if((fd >= 0) && (fd < OPEN_MAX)) { 62 filp = &gMD->fdarray[fd]; 63 retval = TRUE; 64 if(IsOpen >= 0) { 65 retval = (BOOLEAN)((filp->f_iflags != 0) && // TRUE if OPEN 66 FILE_IS_USABLE(filp)); // and Usable (not Larval or Closing) 67 if(IsOpen == VALID_CLOSED) { 68 retval = (BOOLEAN)!retval; // We want TRUE if CLOSED 69 } 70 } 71 } 72 return retval; 73 } 74 75 /* Find and reserve a free File Descriptor. 76 77 Returns the first free File Descriptor greater than or equal to the, 78 already validated, fd specified by Minfd. 79 80 @return Returns -1 if there are no free FDs. Otherwise returns the 81 found fd. 82 */ 83 int 84 FindFreeFD( int MinFd ) 85 { 86 struct __filedes *Mfd; 87 int i; 88 int fd = -1; 89 90 Mfd = gMD->fdarray; 91 92 // Get an available fd 93 for(i=MinFd; i < OPEN_MAX; ++i) { 94 if(Mfd[i].f_iflags == 0) { 95 Mfd[i].f_iflags = FIF_LARVAL; // Temporarily mark this fd as reserved 96 fd = i; 97 break; 98 } 99 } 100 return fd; 101 } 102 103 /* Mark that an open file is to be deleted when closed. */ 104 int 105 DeleteOnClose(int fd) 106 { 107 int retval = 0; 108 109 if(ValidateFD( fd, VALID_OPEN)) { 110 gMD->fdarray[fd].f_iflags |= FIF_DELCLOSE; 111 } 112 else { 113 errno = EBADF; 114 retval = -1; 115 } 116 return retval; 117 } 118 119 /** The isatty() function tests whether fd, an open file descriptor, 120 is associated with a terminal device. 121 122 @param[in] fd File Descriptor for the file to be examined. 123 124 @retval 1 fd is associated with a terminal. 125 @retval 0 fd is not associated with a terminal. errno is set to 126 EBADF if fd is not a valid open FD. 127 **/ 128 int 129 isatty (int fd) 130 { 131 int retval = 0; 132 struct __filedes *Fp; 133 134 if(ValidateFD( fd, VALID_OPEN)) { 135 Fp = &gMD->fdarray[fd]; 136 retval = (Fp->f_iflags & _S_ITTY) ? 1 : 0; 137 } 138 else { 139 errno = EBADF; 140 } 141 return retval; 142 } 143 144 /** Determine if file descriptor fd is a duplicate of some other fd. 145 146 @param[in] fd The file descriptor to check. 147 148 @retval TRUE fd is a duplicate of another fd. 149 @retval FALSE fd is unique. 150 **/ 151 static BOOLEAN 152 IsDupFd( int fd) 153 { 154 void * DevData; 155 const struct fileops *FileOps; 156 int i; 157 BOOLEAN Ret = FALSE; 158 159 if(ValidateFD( fd, VALID_OPEN )) { 160 FileOps = gMD->fdarray[fd].f_ops; 161 DevData = gMD->fdarray[fd].devdata; 162 for(i=0; i < OPEN_MAX; ++i) { 163 if(i == fd) continue; 164 if(ValidateFD( i, VALID_OPEN )) { // TRUE if fd is valid and OPEN 165 if((gMD->fdarray[i].f_ops == FileOps) 166 &&(gMD->fdarray[i].devdata == DevData )) { 167 Ret = TRUE; 168 break; 169 } 170 } 171 } 172 } 173 return Ret; 174 } 175 176 /** Worker function to Close a file and set its fd to the specified state. 177 178 @param[in] fd The file descriptor to close. 179 @param[in] NewState State to set the fd to after the file is closed. 180 181 @retval 0 The operation completed successfully. 182 @retval -1 The operation failed. Further information is in errno. 183 * EBADF fd is not a valid or open file descriptor. 184 **/ 185 static int 186 _closeX (int fd, int NewState) 187 { 188 struct __filedes *Fp; 189 int retval = 0; 190 191 // Verify my pointers and get my FD. 192 if(ValidateFD( fd, VALID_OPEN )) { 193 Fp = &gMD->fdarray[fd]; 194 // Check if there are other users of this FileHandle 195 if(Fp->RefCount == 1) { // There should be no other users 196 if(! IsDupFd(fd)) { 197 // Only do the close if no one else is using the FileHandle 198 if(Fp->f_iflags & FIF_DELCLOSE) { 199 /* Handle files marked "Delete on Close". */ 200 if(Fp->f_ops->fo_delete != NULL) { 201 retval = Fp->f_ops->fo_delete(Fp); 202 } 203 } 204 else { 205 retval = Fp->f_ops->fo_close( Fp); 206 } 207 } 208 Fp->f_iflags = NewState; // Close this FD or reserve it 209 Fp->RefCount = 0; // No one using this FD 210 } 211 else { 212 --Fp->RefCount; /* One less user of this FD */ 213 } 214 } 215 else { 216 // Bad FD 217 retval = -1; 218 errno = EBADF; 219 } 220 return retval; 221 } 222 223 /** The close() function deallocates the file descriptor indicated by fd. 224 To deallocate means to make the file descriptor available for return by 225 subsequent calls to open() or other functions that allocate file 226 descriptors. All outstanding record locks owned by the process on the file 227 associated with the file descriptor are removed (that is, unlocked). 228 229 @param[in] fd Descriptor for the File to close. 230 231 @retval 0 Successful completion. 232 @retval -1 An error occurred and errno is set to identify the error. 233 **/ 234 int 235 close (int fd) 236 { 237 return _closeX(fd, 0); 238 } 239 240 /** Delete the file specified by path. 241 242 @param[in] path The MBCS path of the file to delete. 243 244 @retval -1 Unable to open the file specified by path. 245 @retval -1 If (errno == EPERM), unlink is not permited for this file. 246 @retval -1 Low-level delete filed. Reason is in errno. 247 @retval 0 The file was successfully deleted. 248 **/ 249 int 250 unlink (const char *path) 251 { 252 struct __filedes *Fp; 253 int fd; 254 int retval = -1; 255 256 EFIerrno = RETURN_SUCCESS; 257 258 fd = open(path, O_WRONLY, 0); 259 if(fd >= 0) { 260 Fp = &gMD->fdarray[fd]; 261 262 if(Fp->f_ops->fo_delete != NULL) { 263 retval = Fp->f_ops->fo_delete(Fp); 264 } 265 Fp->f_iflags = 0; // Close this FD 266 Fp->RefCount = 0; // No one using this FD 267 } 268 return retval; 269 } 270 271 /** The fcntl() function shall perform the operations described below on open 272 files. The fildes argument is a file descriptor. 273 274 The available values for cmd are defined in <fcntl.h> and are as follows: 275 - F_DUPFD - Return a new file descriptor which shall be the lowest 276 numbered available (that is, not already open) file 277 descriptor greater than or equal to the third argument, arg, 278 taken as an integer of type int. The new file descriptor 279 shall refer to the same open file description as the original 280 file descriptor, and shall share any locks. The FD_CLOEXEC 281 flag associated with the new file descriptor shall be cleared 282 to keep the file open across calls to one of the exec functions. 283 - F_GETFD - Get the file descriptor flags defined in <fcntl.h> that are 284 associated with the file descriptor fildes. File descriptor 285 flags are associated with a single file descriptor and do not 286 affect other file descriptors that refer to the same file. 287 - F_SETFD - Set the file descriptor flags defined in <fcntl.h>, that are 288 associated with fildes, to the third argument, arg, taken 289 as type int. If the FD_CLOEXEC flag in the third argument 290 is 0, the file shall remain open across the exec 291 functions; otherwise, the file shall be closed upon 292 successful execution of one of the exec functions. 293 - F_GETFL - Get the file status flags and file access modes, defined in 294 <fcntl.h>, for the file description associated with fildes. 295 The file access modes can be extracted from the return 296 value using the mask O_ACCMODE, which is defined in 297 <fcntl.h>. File status flags and file access modes are 298 associated with the file description and do not affect 299 other file descriptors that refer to the same file with 300 different open file descriptions. 301 - F_SETFL - Set the file status flags, defined in <fcntl.h>, for the file 302 description associated with fildes from the corresponding 303 bits in the third argument, arg, taken as type int. Bits 304 corresponding to the file access mode and the file creation 305 flags, as defined in <fcntl.h>, that are set in arg shall 306 be ignored. If any bits in arg other than those mentioned 307 here are changed by the application, the result is unspecified. 308 - F_GETOWN - If fildes refers to a socket, get the process or process group 309 ID specified to receive SIGURG signals when out-of-band 310 data is available. Positive values indicate a process ID; 311 negative values, other than -1, indicate a process group 312 ID. If fildes does not refer to a socket, the results are 313 unspecified. 314 - F_SETOWN - If fildes refers to a socket, set the process or process 315 group ID specified to receive SIGURG signals when 316 out-of-band data is available, using the value of the third 317 argument, arg, taken as type int. Positive values indicate 318 a process ID; negative values, other than -1, indicate a 319 process group ID. If fildes does not refer to a socket, the 320 results are unspecified. 321 322 The fcntl() function shall fail if: 323 324 [EBADF] The fildes argument is not a valid open file descriptor. 325 [EINVAL] The cmd argument is invalid, or the cmd argument is F_DUPFD 326 and arg is negative or greater than or equal to {OPEN_MAX}. 327 [EMFILE] The argument cmd is F_DUPFD and {OPEN_MAX} file descriptors 328 are currently open in the calling process, or no file 329 descriptors greater than or equal to arg are available. 330 [EOVERFLOW] One of the values to be returned cannot be represented correctly. 331 332 @param[in] fildes Descriptor for the file to be controlled. 333 @param[in] cmd Command to be acted upon. 334 @param[in,out] ... Optional additional parameters as required by cmd. 335 336 @return Upon successful completion, the value returned shall depend on 337 cmd as follows: 338 - F_DUPFD - A new file descriptor. 339 - F_GETFD - Value of flags defined in <fcntl.h>. The return value 340 shall not be negative. 341 - F_SETFD - Value other than -1. 342 - F_GETFL - Value of file status flags and access modes. The return 343 value is not negative. 344 - F_SETFL - Value other than -1. 345 - F_GETOWN - Value of the socket owner process or process group; 346 this will not be -1. 347 - F_SETOWN - Value other than -1. 348 Otherwise, -1 shall be returned and errno set to indicate the error. 349 350 **/ 351 int 352 fcntl (int fildes, int cmd, ...) 353 { 354 va_list p3; 355 struct __filedes *MyFd; 356 int retval = -1; 357 int temp; 358 359 //Print(L"%a( %d, %d, ...)\n", __func__, fildes, cmd); 360 va_start(p3, cmd); 361 362 if(ValidateFD( fildes, VALID_OPEN )) { 363 MyFd = &gMD->fdarray[fildes]; 364 365 switch(cmd) { 366 case F_DUPFD: 367 temp = va_arg(p3, int); 368 if(ValidateFD( temp, VALID_DONT_CARE )) { 369 temp = FindFreeFD( temp ); 370 if(temp < 0) { 371 errno = EMFILE; 372 break; 373 } 374 /* temp is now a valid fd reserved for further use 375 so copy fd into temp. 376 */ 377 (void)memcpy(&gMD->fdarray[temp], MyFd, sizeof(struct __filedes)); 378 retval = temp; 379 } 380 else { 381 errno = EINVAL; 382 } 383 break; 384 385 case F_SETFL: 386 retval = MyFd->Oflags; // Get original value 387 temp = va_arg(p3, int); 388 temp &= O_SETMASK; // Only certain bits can be set 389 temp |= retval & O_SETMASK; 390 MyFd->Oflags = temp; // Set new value 391 break; 392 393 case F_SETFD: 394 retval = MyFd->f_iflags; 395 break; 396 //case F_SETOWN: 397 // retval = MyFd->SocProc; 398 // MyFd->SocProc = va_arg(p3, int); 399 // break; 400 case F_GETFD: 401 retval = MyFd->f_iflags; 402 break; 403 case F_GETFL: 404 retval = MyFd->Oflags; 405 break; 406 //case F_GETOWN: 407 // retval = MyFd->SocProc; 408 // break; 409 default: 410 errno = EINVAL; 411 break; 412 } 413 } 414 else { 415 // Bad FD 416 errno = EBADF; 417 } 418 va_end(p3); 419 return retval;; 420 } 421 422 /** The dup() function provides an alternative interface to the 423 service provided by fcntl() using the F_DUPFD command. The call: 424 - fid = dup(fildes); 425 shall be equivalent to: 426 - fid = fcntl(fildes, F_DUPFD, 0); 427 428 @param[in] fildes Descriptor for the file to be examined. 429 430 @return Upon successful completion a non-negative integer, namely the 431 file descriptor, shall be returned; otherwise, -1 shall be 432 returned and errno set to indicate the error. 433 **/ 434 int 435 dup (int fildes) 436 { 437 return fcntl(fildes, F_DUPFD, 0); 438 } 439 440 /** Make fildes2 refer to a duplicate of fildes. 441 442 The dup2() function provides an alternative interface to the 443 service provided by fcntl() using the F_DUPFD command. The call: 444 - fid = dup2(fildes, fildes2); 445 shall be equivalent to: 446 - close(fildes2); 447 - fid = fcntl(fildes, F_DUPFD, fildes2); 448 except for the following: 449 - If fildes2 is less than 0 or greater than or equal to {OPEN_MAX}, 450 dup2() shall return -1 with errno set to [EBADF]. 451 - If fildes is a valid file descriptor and is equal to fildes2, dup2() 452 shall return fildes2 without closing it. 453 - If fildes is not a valid file descriptor, dup2() shall return -1 and 454 shall not close fildes2. 455 - The value returned shall be equal to the value of fildes2 upon 456 successful completion, or -1 upon failure. 457 458 @param[in] fildes File Descriptor to be duplicated. 459 @param[in] fildes2 File Descriptor to be made a duplicate of fildes. 460 461 @return Upon successful completion a non-negative integer, namely 462 fildes2, shall be returned; otherwise, -1 shall be 463 returned and errno set to EBADF indicate the error. 464 **/ 465 int 466 dup2 (int fildes, int fildes2) 467 { 468 int retval = -1; 469 470 if(ValidateFD( fildes, VALID_OPEN)) { 471 retval = fildes2; 472 if( fildes != fildes2) { 473 if(ValidateFD( fildes2, VALID_DONT_CARE)) { 474 gMD->fdarray[fildes2].f_iflags = FIF_LARVAL; // Mark the file closed, but reserved 475 (void)memcpy(&gMD->fdarray[fildes2], // Duplicate fildes into fildes2 476 &gMD->fdarray[fildes], sizeof(struct __filedes)); 477 gMD->fdarray[fildes2].MyFD = (UINT16)fildes2; 478 } 479 else { 480 errno = EBADF; 481 retval = -1; 482 } 483 } 484 } 485 else { 486 errno = EBADF; 487 } 488 return retval; 489 } 490 491 /** Reposition a file's read/write offset. 492 493 The lseek() function repositions the offset of the file descriptor fildes 494 to the argument offset according to the directive how. The argument 495 fildes must be an open file descriptor. lseek() repositions the file 496 pointer fildes as follows: 497 498 - If how is SEEK_SET, the offset is set to offset bytes. 499 500 - If how is SEEK_CUR, the offset is set to its current location 501 plus offset bytes. 502 503 - If how is SEEK_END, the offset is set to the size of the file 504 plus offset bytes. 505 506 The lseek() function allows the file offset to be set beyond the end of 507 the existing end-of-file of the file. If data is later written at this 508 point, subsequent reads of the data in the gap return bytes of zeros 509 (until data is actually written into the gap). 510 511 Some devices are incapable of seeking. The value of the pointer associ- 512 ated with such a device is undefined. 513 514 @param[in] fd Descriptor for the File to be affected. 515 @param[in] offset Value to adjust the file position by. 516 @param[in] how How the file position is to be adjusted. 517 518 @return Upon successful completion, lseek() returns the resulting offset 519 location as measured in bytes from the beginning of the file. 520 Otherwise, a value of -1 is returned and errno is set to 521 indicate the error. 522 **/ 523 __off_t 524 lseek (int fd, __off_t offset, int how) 525 { 526 __off_t CurPos = -1; 527 // RETURN_STATUS Status = RETURN_SUCCESS; 528 struct __filedes *filp; 529 530 EFIerrno = RETURN_SUCCESS; // In case of error without an EFI call 531 532 if( how == SEEK_SET || how == SEEK_CUR || how == SEEK_END) { 533 if(ValidateFD( fd, VALID_OPEN)) { 534 filp = &gMD->fdarray[fd]; 535 // Both of our parameters have been verified as valid 536 CurPos = filp->f_ops->fo_lseek( filp, offset, how); 537 if(CurPos >= 0) { 538 filp->f_offset = CurPos; 539 } 540 } 541 else { 542 errno = EBADF; // Bad File Descriptor 543 } 544 } 545 else { 546 errno = EINVAL; // Invalid how argument 547 } 548 return CurPos; 549 } 550 551 /** The directory path is created with the access permissions specified by 552 perms. 553 554 The directory is closed after it is created. 555 556 @param[in] path The path to a directory to create. 557 @param[in] perms Permissions as defined in <sys/stat.h> 558 559 @retval 0 The directory was created successfully. 560 @retval -1 An error occurred and error codes are stored in errno and EFIerrno. 561 **/ 562 int 563 mkdir (const char *path, __mode_t perms) 564 { 565 wchar_t *NewPath; 566 DeviceNode *Node; 567 char *GenI; 568 RETURN_STATUS Status; 569 int Instance = 0; 570 int retval = 0; 571 572 Status = ParsePath(path, &NewPath, &Node, &Instance, NULL); 573 if(Status == RETURN_SUCCESS) { 574 GenI = Node->InstanceList; 575 if(GenI == NULL) { 576 errno = EPERM; 577 retval = -1; 578 } 579 else { 580 //GenI += (Instance * Node->InstanceSize); 581 retval = ((GenericInstance *)GenI)->Abstraction.fo_mkdir( path, perms); 582 } 583 free(NewPath); 584 } 585 else { 586 retval = -1; 587 } 588 return retval; 589 } 590 591 /** Open a file. 592 The open() function establishes the connection between a file and a file 593 descriptor. It creates an open file description that refers to a file 594 and a file descriptor that refers to that open file description. The file 595 descriptor is used by other I/O functions to refer to that file. 596 597 The open() function returns a file descriptor for the named file that is 598 the lowest file descriptor not currently open for that process. The open 599 file description is new, and therefore the file descriptor shall not 600 share it with any other process in the system. 601 602 The file offset used to mark the current position within the file is set 603 to the beginning of the file. 604 605 The EFI ShellOpenFileByName() function is used to perform the low-level 606 file open operation. The primary task of open() is to translate from the 607 flags used in the <stdio.h> environment to those used by the EFI function. 608 609 The file status flags and file access modes of the open file description 610 are set according to the value of oflags. 611 612 Values for oflags are constructed by a bitwise-inclusive OR of flags from 613 the following list, defined in <fcntl.h>. Applications shall specify 614 exactly one of { O_RDONLY, O_RDWR, O_WRONLY } in the value of oflags. 615 Any combination of { O_NONBLOCK, O_APPEND, O_CREAT, O_TRUNC, O_EXCL } may 616 also be specified in oflags. 617 618 The only valid flag combinations for ShellOpenFileByName() are: 619 - Read 620 - Read/Write 621 - Create/Read/Write 622 623 Values for mode specify the access permissions for newly created files. 624 The mode value is saved in the FD to indicate permissions for further operations. 625 626 O_RDONLY -- flags = EFI_FILE_MODE_READ -- this is always done 627 O_WRONLY -- flags |= EFI_FILE_MODE_WRITE 628 O_RDWR -- flags |= EFI_FILE_MODE_WRITE -- READ is already set 629 630 O_NONBLOCK -- ignored 631 O_APPEND -- Seek to EOF before every write 632 O_CREAT -- flags |= EFI_FILE_MODE_CREATE 633 O_TRUNC -- delete first then create new 634 O_EXCL -- if O_CREAT is also set, open will fail if the file already exists. 635 636 @param[in] Path The path argument points to a pathname naming the 637 object to be opened. 638 @param[in] oflags File status flags and file access modes of the 639 open file description. 640 @param[in] mode File access permission bits as defined in 641 <sys/stat.h>. Only used if a file is created 642 as a result of the open. 643 644 @return Upon successful completion, open() opens the file and returns 645 a non-negative integer representing the lowest numbered 646 unused file descriptor. Otherwise, open returns -1 and sets 647 errno to indicate the error. If a negative value is 648 returned, no files are created or modified. 649 - EMFILE - No file descriptors available -- Max number already open. 650 - EINVAL - Bad value specified for oflags or mode. 651 - ENOMEM - Failure allocating memory for internal buffers. 652 - EEXIST - File exists and open attempted with (O_EXCL | O_CREAT) set. 653 - EIO - UEFI failure. Check value in EFIerrno. 654 **/ 655 int 656 open( 657 const char *path, 658 int oflags, 659 int mode 660 ) 661 { 662 wchar_t *NewPath; 663 wchar_t *MPath; 664 DeviceNode *Node; 665 struct __filedes *filp; 666 struct termios *Termio; 667 int Instance = 0; 668 RETURN_STATUS Status; 669 UINT32 OpenMode; 670 int fd = -1; 671 int doresult; 672 673 Status = ParsePath(path, &NewPath, &Node, &Instance, &MPath); 674 if(Status == RETURN_SUCCESS) { 675 if ((Node == NULL) || 676 (Node->InstanceList == NULL)) 677 { 678 errno = EPERM; 679 } 680 else { 681 // Could add a test to see if the file name begins with a period. 682 // If it does, then add the HIDDEN flag to Attributes. 683 684 // Get an available fd 685 fd = FindFreeFD( VALID_CLOSED ); 686 687 if( fd < 0 ) { 688 // All available FDs are in use 689 errno = EMFILE; 690 } 691 else { 692 filp = &gMD->fdarray[fd]; 693 // Save the flags and mode in the File Descriptor 694 filp->Oflags = oflags; 695 filp->Omode = mode; 696 697 doresult = Node->OpenFunc(Node, filp, Instance, NewPath, MPath); 698 if(doresult < 0) { 699 filp->f_iflags = 0; // Release this FD 700 fd = -1; // Indicate an error 701 } 702 else { 703 // Build our final f_iflags value 704 OpenMode = ( mode & S_ACC_READ ) ? S_ACC_READ : 0; 705 OpenMode |= ( mode & S_ACC_WRITE ) ? S_ACC_WRITE : 0; 706 707 filp->f_iflags |= OpenMode; 708 709 if((oflags & O_TTY_INIT) && (filp->f_iflags & _S_ITTY) && (filp->devdata != NULL)) { 710 // Initialize the device's termios flags to a "sane" value 711 Termio = &((cIIO *)filp->devdata)->Termio; 712 Termio->c_iflag = ICRNL | IGNSPEC; 713 Termio->c_oflag = OPOST | ONLCR | OXTABS | ONOEOT | ONOCR | ONLRET | OCTRL; 714 Termio->c_lflag = ECHO | ECHOE | ECHONL | ICANON; 715 Termio->c_cc[VERASE] = 0x08; // ^H Backspace 716 Termio->c_cc[VKILL] = 0x15; // ^U 717 Termio->c_cc[VINTR] = 0x03; // ^C Interrupt character 718 } 719 ++filp->RefCount; 720 FILE_SET_MATURE(filp); 721 } 722 } 723 } 724 free(NewPath); 725 } 726 free(MPath); // We don't need this any more. 727 728 // return the fd of our now open file 729 return fd; 730 } 731 732 733 /** 734 Poll a list of file descriptors. 735 736 The ::poll routine waits for up to timeout milliseconds for an event 737 to occur on one or more of the file descriptors listed. The event 738 types of interested are specified for each file descriptor in the events 739 field. The actual event detected is returned in the revents field of 740 the array. The 741 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html">POSIX</a> 742 documentation is available online. 743 744 @param[in] pfd Address of an array of pollfd structures. 745 746 @param[in] nfds Number of elements in the array of pollfd structures. 747 748 @param[in] timeout Length of time in milliseconds to wait for the event 749 750 @return The number of file descriptors with detected events. Zero 751 indicates that the call timed out and -1 indicates an error. 752 753 **/ 754 int 755 poll ( 756 struct pollfd * pfd, 757 nfds_t nfds, 758 int timeout 759 ) 760 { 761 struct __filedes * pDescriptor; 762 struct pollfd * pEnd; 763 struct pollfd * pPollFD; 764 int SelectedFDs; 765 EFI_STATUS Status; 766 EFI_EVENT Timer; 767 UINT64 TimerTicks; 768 769 // 770 // Create the timer for the timeout 771 // 772 Timer = NULL; 773 Status = EFI_SUCCESS; 774 if ( INFTIM != timeout ) { 775 Status = gBS->CreateEvent ( EVT_TIMER, 776 TPL_NOTIFY, 777 NULL, 778 NULL, 779 &Timer ); 780 if ( !EFI_ERROR ( Status )) { 781 // 782 // Start the timeout timer 783 // 784 TimerTicks = timeout; 785 TimerTicks *= 1000 * 10; 786 Status = gBS->SetTimer ( Timer, 787 TimerRelative, 788 TimerTicks ); 789 } 790 else { 791 SelectedFDs = -1; 792 errno = ENOMEM; 793 } 794 } 795 if ( !EFI_ERROR ( Status )) { 796 // 797 // Poll until an event is detected or the timer fires 798 // 799 SelectedFDs = 0; 800 errno = 0; 801 do { 802 // 803 // Poll the list of file descriptors 804 // 805 pPollFD = pfd; 806 pEnd = &pPollFD [ nfds ]; 807 while ( pEnd > pPollFD ) { 808 // 809 // Validate the file descriptor 810 // 811 if ( !ValidateFD ( pPollFD->fd, VALID_OPEN )) { 812 errno = EINVAL; 813 return -1; 814 } 815 816 // 817 // Poll the device or file 818 // 819 pDescriptor = &gMD->fdarray [ pPollFD->fd ]; 820 pPollFD->revents = pDescriptor->f_ops->fo_poll ( pDescriptor, 821 pPollFD->events ); 822 823 // 824 // Determine if this file descriptor detected an event 825 // 826 if ( 0 != pPollFD->revents ) { 827 // 828 // Select this descriptor 829 // 830 SelectedFDs += 1; 831 } 832 833 // 834 // Set the next file descriptor 835 // 836 pPollFD += 1; 837 } 838 839 // 840 // Check for timeout 841 // 842 if ( NULL != Timer ) { 843 Status = gBS->CheckEvent ( Timer ); 844 if ( EFI_SUCCESS == Status ) { 845 // 846 // Timeout 847 // 848 break; 849 } 850 else if ( EFI_NOT_READY == Status ) { 851 Status = EFI_SUCCESS; 852 } 853 } 854 } while (( 0 == SelectedFDs ) 855 && ( EFI_SUCCESS == Status )); 856 857 // 858 // Stop the timer 859 // 860 if ( NULL != Timer ) { 861 gBS->SetTimer ( Timer, 862 TimerCancel, 863 0 ); 864 } 865 } 866 else { 867 SelectedFDs = -1; 868 errno = EAGAIN; 869 } 870 871 // 872 // Release the timer 873 // 874 if ( NULL != Timer ) { 875 gBS->CloseEvent ( Timer ); 876 } 877 878 // 879 // Return the number of selected file system descriptors 880 // 881 return SelectedFDs; 882 } 883 884 885 /** The rename() function changes the name of a file. 886 The From argument points to the pathname of the file to be renamed. The To 887 argument points to the new pathname of the file. 888 889 If the From argument points to the pathname of a file that is not a 890 directory, the To argument shall not point to the pathname of a 891 directory. If the file named by the To argument exists, it shall be 892 removed and From renamed to To. Write access permission is required for 893 both the directory containing old and the directory containing To. 894 895 If the From argument points to the pathname of a directory, the To 896 argument shall not point to the pathname of a file that is not a 897 directory. If the directory named by the To argument exists, it shall be 898 removed and From renamed to To. 899 900 The To pathname shall not contain a path prefix that names From. Write 901 access permission is required for the directory containing From and the 902 directory containing To. If the From argument points to the pathname of a 903 directory, write access permission may be required for the directory named 904 by From, and, if it exists, the directory named by To. 905 906 If the rename() function fails for any reason other than [EIO], any file 907 named by To shall be unaffected. 908 909 @param[in] From Path to the file to be renamed. 910 @param[in] To The new name of From. 911 912 @retval 0 Successful completion. 913 @retval -1 An error has occured and errno has been set to further specify the error. 914 Neither the file named by From nor the file named by To are 915 changed or created. 916 - ENXIO: Path specified is not supported by any loaded driver. 917 - ENOMEM: Insufficient memory to calloc a MapName buffer. 918 - EINVAL: The path parameter is not valid. 919 **/ 920 int 921 rename( 922 const char *From, 923 const char *To 924 ) 925 { 926 wchar_t *FromPath; 927 DeviceNode *FromNode; 928 char *GenI; 929 int Instance = 0; 930 RETURN_STATUS Status; 931 int retval = -1; 932 933 Status = ParsePath(From, &FromPath, &FromNode, &Instance, NULL); 934 if(Status == RETURN_SUCCESS) { 935 GenI = FromNode->InstanceList; 936 if(GenI == NULL) { 937 errno = EPERM; 938 retval = -1; 939 } 940 else { 941 //GenI += (Instance * FromNode->InstanceSize); 942 retval = ((GenericInstance *)GenI)->Abstraction.fo_rename( From, To); 943 } 944 free(FromPath); 945 } 946 return retval; 947 } 948 949 /** Delete a specified directory. 950 951 @param[in] path Path to the directory to delete. 952 953 @retval -1 The directory couldn't be opened (doesn't exist). 954 @retval -1 The directory wasn't empty or an IO error occured. 955 **/ 956 int 957 rmdir( 958 const char *path 959 ) 960 { 961 struct __filedes *filp; 962 int fd; 963 int retval = -1; 964 965 fd = open(path, O_RDWR, 0); 966 if(fd >= 0) { 967 filp = &gMD->fdarray[fd]; 968 969 retval = filp->f_ops->fo_rmdir(filp); 970 filp->f_iflags = 0; // Close this FD 971 filp->RefCount = 0; // No one using this FD 972 } 973 return retval; 974 } 975 976 /** The fstat() function obtains information about an open file associated 977 with the file descriptor fd, and writes it to the area pointed to 978 by statbuf. 979 980 The statbuf argument is a pointer to a stat structure, as defined 981 in <sys/stat.h>, into which information is placed concerning the file. 982 983 The structure members st_mode, st_ino, st_dev, st_uid, st_gid, st_atime, 984 st_ctime, and st_mtime shall have meaningful values. The value of the 985 member st_nlink shall be set to the number of links to the file. 986 987 The fstat() function shall update any time-related fields before writing 988 into the stat structure. 989 990 The fstat() function is implemented using the ShellGetFileInfo() 991 function. 992 993 The stat structure members which don't have direct analogs to EFI file 994 information are filled in as follows: 995 - st_mode Populated with information from fd 996 - st_ino Set to zero. (inode) 997 - st_dev Set to zero. 998 - st_uid Set to zero. 999 - st_gid Set to zero. 1000 - st_nlink Set to one. 1001 1002 @param[in] fd File descriptor as returned from open(). 1003 @param[out] statbuf Buffer in which the file status is put. 1004 1005 @retval 0 Successful Completion. 1006 @retval -1 An error has occurred and errno has been set to 1007 identify the error. 1008 **/ 1009 int 1010 fstat (int fd, struct stat *statbuf) 1011 { 1012 int retval = -1; 1013 struct __filedes *filp; 1014 1015 if(ValidateFD( fd, VALID_OPEN)) { 1016 filp = &gMD->fdarray[fd]; 1017 retval = filp->f_ops->fo_stat(filp, statbuf, NULL); 1018 } 1019 else { 1020 errno = EBADF; 1021 } 1022 return retval; 1023 } 1024 1025 /** Obtains information about the file pointed to by path. 1026 1027 Opens the file pointed to by path, calls _EFI_FileInfo with the file's handle, 1028 then closes the file. 1029 1030 @param[in] path Path to the file to obtain information about. 1031 @param[out] statbuf Buffer in which the file status is put. 1032 1033 @retval 0 Successful Completion. 1034 @retval -1 An error has occurred and errno has been set to 1035 identify the error. 1036 **/ 1037 int 1038 stat (const char *path, struct stat *statbuf) 1039 { 1040 int fd; 1041 int retval = -1; 1042 struct __filedes *filp; 1043 1044 fd = open(path, O_RDONLY, 0); 1045 if(fd >= 0) { 1046 filp = &gMD->fdarray[fd]; 1047 retval = filp->f_ops->fo_stat( filp, statbuf, NULL); 1048 close(fd); 1049 } 1050 return retval; 1051 } 1052 1053 /** Same as stat since EFI doesn't have symbolic links. 1054 1055 @param[in] path Path to the file to obtain information about. 1056 @param[out] statbuf Buffer in which the file status is put. 1057 1058 @retval 0 Successful Completion. 1059 @retval -1 An error has occurred and errno has been set to 1060 identify the error. 1061 **/ 1062 int 1063 lstat (const char *path, struct stat *statbuf) 1064 { 1065 return stat(path, statbuf); 1066 } 1067 1068 /** Control a device. 1069 1070 @param[in] fd Descriptor for the file to be acted upon. 1071 @param[in] request Specifies the operation to perform. 1072 @param[in,out] ... Zero or more parameters as required for request. 1073 1074 @retval >=0 The operation completed successfully. 1075 @retval -1 An error occured. More information is in errno. 1076 **/ 1077 int 1078 ioctl( 1079 int fd, 1080 unsigned long request, 1081 ... 1082 ) 1083 { 1084 int retval = -1; 1085 struct __filedes *filp; 1086 va_list argp; 1087 1088 va_start(argp, request); 1089 1090 if(ValidateFD( fd, VALID_OPEN)) { 1091 filp = &gMD->fdarray[fd]; 1092 1093 if(request == FIODLEX) { 1094 /* set Delete-on-Close */ 1095 filp->f_iflags |= FIF_DELCLOSE; 1096 retval = 0; 1097 } 1098 else if(request == FIONDLEX) { 1099 /* clear Delete-on-Close */ 1100 filp->f_iflags &= ~FIF_DELCLOSE; 1101 retval = 0; 1102 } 1103 else { 1104 /* All other requests. */ 1105 retval = filp->f_ops->fo_ioctl(filp, request, argp); 1106 } 1107 } 1108 else { 1109 errno = EBADF; 1110 } 1111 va_end(argp); 1112 1113 return retval; 1114 } 1115 1116 /** Read from a file. 1117 1118 The read() function shall attempt to read nbyte bytes from the file 1119 associated with the open file descriptor, fildes, into the buffer pointed 1120 to by buf. 1121 1122 Before any action described below is taken, and if nbyte is zero, the 1123 read() function may detect and return errors as described below. In the 1124 absence of errors, or if error detection is not performed, the read() 1125 function shall return zero and have no other results. 1126 1127 On files that support seeking (for example, a regular file), the read() 1128 shall start at a position in the file given by the file offset associated 1129 with fildes. The file offset shall be incremented by the number of bytes 1130 actually read. 1131 1132 Files that do not support seeking - for example, terminals - always read 1133 from the current position. The value of a file offset associated with 1134 such a file is undefined. 1135 1136 No data transfer shall occur past the current end-of-file. If the 1137 starting position is at or after the end-of-file, 0 shall be returned. 1138 1139 The read() function reads data previously written to a file. If any 1140 portion of a regular file prior to the end-of-file has not been written, 1141 read() shall return bytes with value 0. For example, lseek() allows the 1142 file offset to be set beyond the end of existing data in the file. If data 1143 is later written at this point, subsequent reads in the gap between the 1144 previous end of data and the newly written data shall return bytes with 1145 value 0 until data is written into the gap. 1146 1147 Upon successful completion, where nbyte is greater than 0, read() shall 1148 mark for update the st_atime field of the file, and shall return the 1149 number of bytes read. This number shall never be greater than nbyte. The 1150 value returned may be less than nbyte if the number of bytes left in the 1151 file is less than nbyte, if the read() request was interrupted by a 1152 signal, or if the file is a pipe or FIFO or special file and has fewer 1153 than nbyte bytes immediately available for reading. For example, a read() 1154 from a file associated with a terminal may return one typed line of data. 1155 1156 If fildes does not refer to a directory, the function reads the requested 1157 number of bytes from the file at the file's current position and returns 1158 them in buf. If the read goes beyond the end of the file, the read 1159 length is truncated to the end of the file. The file's current position is 1160 increased by the number of bytes returned. 1161 1162 If fildes refers to a directory, the function reads the directory entry at 1163 the file's current position and returns the entry in buf. If buf 1164 is not large enough to hold the current directory entry, then 1165 errno is set to EBUFSIZE, EFIerrno is set to EFI_BUFFER_TOO_SMALL, and the 1166 current file position is not updated. The size of the buffer needed to read 1167 the entry will be returned as a negative number. On success, the current 1168 position is updated to the next directory entry. If there are no more 1169 directory entries, the read returns a zero-length buffer. 1170 EFI_FILE_INFO is the structure returned as the directory entry. 1171 1172 @param[in] fildes Descriptor of the file to be read. 1173 @param[out] buf Pointer to location in which to store the read data. 1174 @param[in] nbyte Maximum number of bytes to be read. 1175 1176 @return Upon successful completion, read() returns a non-negative integer 1177 indicating the number of bytes actually read. Otherwise, the 1178 functions return a negative value and sets errno to indicate the 1179 error. If errno is EBUFSIZE, the absolute value of the 1180 return value indicates the size of the buffer needed to read 1181 the directory entry. 1182 **/ 1183 ssize_t 1184 read (int fildes, void *buf, size_t nbyte) 1185 { 1186 struct __filedes *filp; 1187 cIIO *IIO; 1188 ssize_t BufSize; 1189 1190 BufSize = (ssize_t)nbyte; 1191 if(BufSize > 0) { 1192 if(ValidateFD( fildes, VALID_OPEN)) { 1193 filp = &gMD->fdarray[fildes]; 1194 1195 IIO = filp->devdata; 1196 if(isatty(fildes) && (IIO != NULL)) { 1197 BufSize = IIO->Read(filp, nbyte, buf); 1198 } 1199 else { 1200 BufSize = filp->f_ops->fo_read(filp, &filp->f_offset, nbyte, buf); 1201 } 1202 } 1203 else { 1204 errno = EBADF; 1205 BufSize = -1; 1206 } 1207 } 1208 return BufSize; 1209 } 1210 1211 /** Write data to a file. 1212 1213 This function writes the specified number of bytes to the file at the current 1214 file position. The current file position is advanced the actual number of bytes 1215 written. Partial writes only occur when there has been a data error during 1216 the write attempt (such as "volume space full"). The file is automatically 1217 grown to hold the data if required. 1218 1219 Direct writes to opened directories are not supported. 1220 1221 If fildes refers to a terminal device, isatty() returns TRUE, a partial write 1222 will occur if a NULL or EOF character is encountered before n characters have 1223 been written. Characters inserted due to line-end translations or TAB 1224 expansion will not be counted. Unconvertable characters are translated into 1225 the UEFI character BLOCKELEMENT_LIGHT_SHADE. 1226 1227 Since the UEFI console device works on wide characters, the buffer is assumed 1228 to contain a byte-oriented multi-byte character stream which is then 1229 translated to wide characters using the mbtowc() functions. The resulting 1230 wide character stream is what is actually sent to the UEFI console. 1231 1232 Although both text and binary wide-oriented streams are conceptually 1233 sequences of wide characters, the external file associated with a 1234 wide-oriented stream is a sequence of multibyte characters, 1235 generalized as follows: 1236 - Multibyte encodings within files may contain embedded null bytes 1237 (unlike multibyte encodings valid for use internal to the program). 1238 - A file need not begin nor end in the initial shift state. 1239 1240 @param[in] fd Descriptor of file to be written to. 1241 @param[in] buf Pointer to data to write to the file. 1242 @param[in] nbyte Number of bytes to be written to the file. 1243 1244 @retval >=0 Number of bytes actually written to the file. 1245 @retval <0 An error occurred. More data is provided by errno. 1246 **/ 1247 ssize_t 1248 write (int fd, const void *buf, size_t nbyte) 1249 { 1250 struct __filedes *filp; 1251 cIIO *IIO; 1252 ssize_t BufSize; 1253 1254 BufSize = (ssize_t)nbyte; 1255 1256 if(ValidateFD( fd, VALID_OPEN)) { 1257 filp = &gMD->fdarray[fd]; 1258 if ((filp->Oflags & O_ACCMODE) != 0) { 1259 // File is open for writing 1260 IIO = filp->devdata; 1261 if(isatty(fd) && (IIO != NULL)) { 1262 // Output to an Interactive I/O device 1263 // (Terminal device or the slave side of a pseudo-tty) 1264 BufSize = IIO->Write(filp, buf, nbyte); 1265 } 1266 else { 1267 // Output to a regular file, socket, pipe, etc. 1268 BufSize = filp->f_ops->fo_write(filp, &filp->f_offset, nbyte, buf); 1269 } 1270 } 1271 else { 1272 // File is NOT open for writing 1273 errno = EINVAL; 1274 BufSize = -1; 1275 } 1276 } 1277 else { 1278 // fd is not for a valid open file 1279 errno = EBADF; 1280 BufSize = -1; 1281 } 1282 return BufSize; 1283 } 1284 1285 /** Gets the current working directory. 1286 1287 The getcwd() function shall place an absolute pathname of the current 1288 working directory in the array pointed to by buf, and return buf.The 1289 size argument is the size in bytes of the character array pointed to 1290 by the buf argument. 1291 1292 @param[in,out] buf The buffer to fill. 1293 @param[in] size The number of bytes in buffer. 1294 1295 @retval NULL The function failed. The value in errno provides 1296 further information about the cause of the failure. 1297 Values for errno are: 1298 - EINVAL: buf is NULL or size is zero. 1299 - ENOENT: directory does not exist. 1300 - ERANGE: buf size is too small to hold CWD 1301 1302 @retval buf The function completed successfully. 1303 **/ 1304 char 1305 *getcwd (char *buf, size_t size) 1306 { 1307 CONST CHAR16 *Cwd; 1308 1309 if (size == 0 || buf == NULL) { 1310 errno = EINVAL; 1311 return NULL; 1312 } 1313 1314 Cwd = ShellGetCurrentDir(NULL); 1315 if (Cwd == NULL) { 1316 errno = ENOENT; 1317 return NULL; 1318 } 1319 if (size < ((StrLen (Cwd) + 1) * sizeof (CHAR8))) { 1320 errno = ERANGE; 1321 return (NULL); 1322 } 1323 return (UnicodeStrToAsciiStr(Cwd, buf)); 1324 } 1325 1326 /** Change the current working directory. 1327 1328 The chdir() function shall cause the directory named by the pathname 1329 pointed to by the path argument to become the current working directory; 1330 that is, the starting point for path searches for pathnames not beginning 1331 with '/'. 1332 1333 @param[in] path The new path to set. 1334 1335 @retval 0 Operation completed successfully. 1336 @retval -1 Function failed. The value in errno provides more 1337 information on the cause of failure: 1338 - EPERM: Operation not supported with this Shell version. 1339 - ENOMEM: Unable to allocate memory. 1340 - ENOENT: Target directory does not exist. 1341 1342 @todo Add non-NEW-shell CWD changing. 1343 **/ 1344 int 1345 chdir (const char *path) 1346 { 1347 CONST CHAR16 *Cwd; 1348 EFI_STATUS Status; 1349 CHAR16 *UnicodePath; 1350 1351 /* Old Shell does not support Set Current Dir. */ 1352 if(gEfiShellProtocol != NULL) { 1353 Cwd = ShellGetCurrentDir(NULL); 1354 if (Cwd != NULL) { 1355 /* We have shell support */ 1356 UnicodePath = AllocatePool(((AsciiStrLen (path) + 1) * sizeof (CHAR16))); 1357 if (UnicodePath == NULL) { 1358 errno = ENOMEM; 1359 return -1; 1360 } 1361 AsciiStrToUnicodeStr(path, UnicodePath); 1362 Status = gEfiShellProtocol->SetCurDir(NULL, UnicodePath); 1363 FreePool(UnicodePath); 1364 if (EFI_ERROR(Status)) { 1365 errno = ENOENT; 1366 return -1; 1367 } else { 1368 return 0; 1369 } 1370 } 1371 } 1372 /* Add here for non-shell */ 1373 errno = EPERM; 1374 return -1; 1375 } 1376 1377 /** Get the foreground process group ID associated with a terminal. 1378 1379 Just returns the Image Handle for the requestor since UEFI does not have 1380 a concept of processes or groups. 1381 1382 @param[in] x Ignored. 1383 1384 @return Returns the Image Handle of the application or driver which 1385 called this function. 1386 **/ 1387 pid_t tcgetpgrp (int x) 1388 { 1389 return ((pid_t)(UINTN)(gImageHandle)); 1390 } 1391 1392 /** Get the process group ID of the calling process. 1393 1394 Just returns the Image Handle for the requestor since UEFI does not have 1395 a concept of processes or groups. 1396 1397 @return Returns the Image Handle of the application or driver which 1398 called this function. 1399 **/ 1400 pid_t getpgrp(void) 1401 { 1402 return ((pid_t)(UINTN)(gImageHandle)); 1403 } 1404 1405 /* Internal worker function for utimes. 1406 This works around an error produced by GCC when the va_* macros 1407 are used within a function with a fixed number of arguments. 1408 */ 1409 static 1410 int 1411 EFIAPI 1412 va_Utimes( 1413 const char *path, 1414 ... 1415 ) 1416 { 1417 struct __filedes *filp; 1418 va_list ap; 1419 int fd; 1420 int retval = -1; 1421 1422 va_start(ap, path); 1423 fd = open(path, O_RDWR, 0); 1424 if(fd >= 0) { 1425 filp = &gMD->fdarray[fd]; 1426 retval = filp->f_ops->fo_ioctl( filp, FIOSETIME, ap); 1427 close(fd); 1428 } 1429 va_end(ap); 1430 return retval; 1431 } 1432 1433 /** Set file access and modification times. 1434 1435 @param[in] path Path to the file to be modified. 1436 @param[in] times Pointer to an array of two timeval structures 1437 1438 @retval 0 File times successfully set. 1439 @retval -1 An error occured. Error type in errno. 1440 **/ 1441 int 1442 utimes( 1443 const char *path, 1444 const struct timeval *times 1445 ) 1446 { 1447 return va_Utimes(path, times); 1448 } 1449