]> git.proxmox.com Git - mirror_edk2.git/blobdiff - StdLib/LibC/Uefi/SysCalls.c
StdLib: Fix issue with Canonical output expansion of NL to CR NL and similar expansions.
[mirror_edk2.git] / StdLib / LibC / Uefi / SysCalls.c
index ebae38f3fbfa5b184bb27926cfd8d2e1e5ab584b..a2b627bd121ac9ccfb47d1a996b1eb84814d638f 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   EFI versions of NetBSD system calls.\r
 \r
-  Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials are licensed and made available under\r
   the terms and conditions of the BSD License that accompanies this distribution.\r
   The full text of the license may be found at\r
@@ -36,6 +36,7 @@
 #include  <unistd.h>\r
 #include  <kfile.h>\r
 #include  <Device/Device.h>\r
+#include  <Device/IIO.h>\r
 #include  <MainData.h>\r
 #include  <extern.h>\r
 \r
@@ -114,12 +115,14 @@ DeleteOnClose(int fd)
   return retval;\r
 }\r
 \r
-/** The isatty() function tests whether fildes, an open file descriptor,\r
+/** The isatty() function tests whether fd, an open file descriptor,\r
     is associated with a terminal device.\r
 \r
-    @retval   1   fildes is associated with a terminal.\r
-    @retval   0   fildes is not associated with a terminal.  errno is set to\r
-                  EBADF if fildes is not a valid open FD.\r
+    @param[in]  fd  File Descriptor for the file to be examined.\r
+\r
+    @retval   1   fd is associated with a terminal.\r
+    @retval   0   fd is not associated with a terminal.  errno is set to\r
+                  EBADF if fd is not a valid open FD.\r
 **/\r
 int\r
 isatty  (int fd)\r
@@ -129,7 +132,7 @@ isatty  (int fd)
 \r
   if(ValidateFD( fd, VALID_OPEN)) {\r
     Fp = &gMD->fdarray[fd];\r
-    retval =  Fp->f_iflags & _S_ITTY;\r
+    retval =  (Fp->f_iflags & _S_ITTY) ? 1 : 0;\r
   }\r
   else {\r
     errno = EBADF;\r
@@ -169,13 +172,14 @@ IsDupFd( int fd)
   return Ret;\r
 }\r
 \r
-/** Close a file and set its fd to the specified state.\r
+/** Worker function to Close a file and set its fd to the specified state.\r
 \r
     @param[in]    fd          The file descriptor to close.\r
     @param[in]    NewState    State to set the fd to after the file is closed.\r
 \r
     @retval    0    The operation completed successfully.\r
     @retval   -1    The operation failed.  Further information is in errno.\r
+                      * EBADF   fd is not a valid or open file descriptor.\r
 **/\r
 static int\r
 _closeX  (int fd, int NewState)\r
@@ -221,6 +225,8 @@ _closeX  (int fd, int NewState)
     descriptors. All outstanding record locks owned by the process on the file\r
     associated with the file descriptor are removed (that is, unlocked).\r
 \r
+    @param[in]    fd          Descriptor for the File to close.\r
+\r
     @retval   0     Successful completion.\r
     @retval   -1    An error occurred and errno is set to identify the error.\r
 **/\r
@@ -230,7 +236,14 @@ close  (int fd)
   return _closeX(fd, 0);\r
 }\r
 \r
-/**\r
+/** Delete the file specified by path.\r
+\r
+    @param[in]    path  The MBCS path of the file to delete.\r
+\r
+    @retval   -1  Unable to open the file specified by path.\r
+    @retval   -1  If (errno == EPERM), unlink is not permited for this file.\r
+    @retval   -1  Low-level delete filed.  Reason is in errno.\r
+    @retval   0   The file was successfully deleted.\r
 **/\r
 int\r
 unlink (const char *path)\r
@@ -315,6 +328,10 @@ unlink (const char *path)
                   descriptors greater than or equal to arg are available.\r
     [EOVERFLOW]   One of the values to be returned cannot be represented correctly.\r
 \r
+    @param[in]      fildes    Descriptor for the file to be controlled.\r
+    @param[in]      cmd       Command to be acted upon.\r
+    @param[in,out]  ...       Optional additional parameters as required by cmd.\r
+\r
     @return   Upon successful completion, the value returned shall depend on\r
               cmd as follows:\r
                 - F_DUPFD - A new file descriptor.\r
@@ -407,6 +424,8 @@ fcntl     (int fildes, int cmd, ...)
     shall be equivalent to:\r
       - fid = fcntl(fildes, F_DUPFD, 0);\r
 \r
+    @param[in]    fildes    Descriptor for the file to be examined.\r
+\r
     @return   Upon successful completion a non-negative integer, namely the\r
               file descriptor, shall be returned; otherwise, -1 shall be\r
               returned and errno set to indicate the error.\r
@@ -417,7 +436,9 @@ dup   (int fildes)
   return fcntl(fildes, F_DUPFD, 0);\r
 }\r
 \r
-/** The dup2() function provides an alternative interface to the\r
+/** Make fildes2 refer to a duplicate of fildes.\r
+\r
+    The dup2() function provides an alternative interface to the\r
     service provided by fcntl() using the F_DUPFD command. The call:\r
       - fid = dup2(fildes, fildes2);\r
     shall be equivalent to:\r
@@ -433,6 +454,9 @@ dup   (int fildes)
       - The value returned shall be equal to the value of fildes2 upon\r
         successful completion, or -1 upon failure.\r
 \r
+    @param[in]  fildes    File Descriptor to be duplicated.\r
+    @param[in]  fildes2   File Descriptor to be made a duplicate of fildes.\r
+\r
     @return   Upon successful completion a non-negative integer, namely\r
               fildes2, shall be returned; otherwise, -1 shall be\r
               returned and errno set to EBADF indicate the error.\r
@@ -470,13 +494,13 @@ dup2    (int fildes, int fildes2)
     fildes must be an open file descriptor.  lseek() repositions the file\r
     pointer fildes as follows:\r
 \r
-         If how is SEEK_SET, the offset is set to offset bytes.\r
+      - If how is SEEK_SET, the offset is set to offset bytes.\r
 \r
-         If how is SEEK_CUR, the offset is set to its current location\r
-         plus offset bytes.\r
+      - If how is SEEK_CUR, the offset is set to its current location\r
+        plus offset bytes.\r
 \r
-         If how is SEEK_END, the offset is set to the size of the file\r
-         plus offset bytes.\r
+      - If how is SEEK_END, the offset is set to the size of the file\r
+        plus offset bytes.\r
 \r
     The lseek() function allows the file offset to be set beyond the end of\r
     the existing end-of-file of the file.  If data is later written at this\r
@@ -486,6 +510,10 @@ dup2    (int fildes, int fildes2)
     Some devices are incapable of seeking.  The value of the pointer associ-\r
     ated with such a device is undefined.\r
 \r
+    @param[in]  fd        Descriptor for the File to be affected.\r
+    @param[in]  offset    Value to adjust the file position by.\r
+    @param[in]  how       How the file position is to be adjusted.\r
+\r
     @return   Upon successful completion, lseek() returns the resulting offset\r
               location as measured in bytes from the beginning of the file.\r
               Otherwise, a value of -1 is returned and errno is set to\r
@@ -524,6 +552,9 @@ lseek (int fd, __off_t offset, int how)
 \r
     The directory is closed after it is created.\r
 \r
+    @param[in]  path    The path to a directory to create.\r
+    @param[in]  perms   Permissions as defined in <sys/stat.h>\r
+\r
     @retval   0   The directory was created successfully.\r
     @retval  -1   An error occurred and error codes are stored in errno and EFIerrno.\r
 **/\r
@@ -557,16 +588,38 @@ mkdir (const char *path, __mode_t perms)
 }\r
 \r
 /** Open a file.\r
+    The open() function establishes the connection between a file and a file\r
+    descriptor.  It creates an open file description that refers to a file\r
+    and a file descriptor that refers to that open file description. The file\r
+    descriptor is used by other I/O functions to refer to that file.\r
+\r
+    The open() function returns a file descriptor for the named file that is\r
+    the lowest file descriptor not currently open for that process. The open\r
+    file description is new, and therefore the file descriptor shall not\r
+    share it with any other process in the system.\r
+\r
+    The file offset used to mark the current position within the file is set\r
+    to the beginning of the file.\r
 \r
     The EFI ShellOpenFileByName() function is used to perform the low-level\r
     file open operation.  The primary task of open() is to translate from the\r
     flags used in the <stdio.h> environment to those used by the EFI function.\r
 \r
+    The file status flags and file access modes of the open file description\r
+    are set according to the value of oflags.\r
+\r
+    Values for oflags are constructed by a bitwise-inclusive OR of flags from\r
+    the following list, defined in <fcntl.h>. Applications shall specify\r
+    exactly one of { O_RDONLY, O_RDWR, O_WRONLY } in the value of oflags.\r
+    Any combination of { O_NONBLOCK, O_APPEND, O_CREAT, O_TRUNC, O_EXCL } may\r
+    also be specified in oflags.\r
+\r
     The only valid flag combinations for ShellOpenFileByName() are:\r
       - Read\r
       - Read/Write\r
       - Create/Read/Write\r
 \r
+    Values for mode specify the access permissions for newly created files.\r
     The mode value is saved in the FD to indicate permissions for further operations.\r
 \r
     O_RDONLY      -- flags = EFI_FILE_MODE_READ -- this is always done\r
@@ -578,6 +631,25 @@ mkdir (const char *path, __mode_t perms)
     O_CREAT       -- flags |= EFI_FILE_MODE_CREATE\r
     O_TRUNC       -- delete first then create new\r
     O_EXCL        -- if O_CREAT is also set, open will fail if the file already exists.\r
+\r
+    @param[in]    Path      The path argument points to a pathname naming the\r
+                            object to be opened.\r
+    @param[in]    oflags    File status flags and file access modes of the\r
+                            open file description.\r
+    @param[in]    mode      File access permission bits as defined in\r
+                            <sys/stat.h>.  Only used if a file is created\r
+                            as a result of the open.\r
+\r
+    @return     Upon successful completion, open() opens the file and returns\r
+                a non-negative integer representing the lowest numbered\r
+                unused file descriptor. Otherwise, open returns -1 and sets\r
+                errno to indicate the error. If a negative value is\r
+                returned, no files are created or modified.\r
+                  - EMFILE - No file descriptors available -- Max number already open.\r
+                  - EINVAL - Bad value specified for oflags or mode.\r
+                  - ENOMEM - Failure allocating memory for internal buffers.\r
+                  - EEXIST - File exists and open attempted with (O_EXCL | O_CREAT) set.\r
+                  - EIO - UEFI failure.  Check value in EFIerrno.\r
 **/\r
 int\r
 open(\r
@@ -590,18 +662,20 @@ open(
   wchar_t              *MPath;\r
   DeviceNode           *Node;\r
   struct __filedes     *filp;\r
+  struct termios       *Termio;\r
   int                   Instance  = 0;\r
   RETURN_STATUS         Status;\r
-  UINT64                OpenMode;\r
+  UINT32                OpenMode;\r
   int                   fd = -1;\r
   int                   doresult;\r
 \r
   Status = ParsePath(path, &NewPath, &Node, &Instance, &MPath);\r
   if(Status == RETURN_SUCCESS) {\r
     if((Node == NULL)               ||\r
-       (Node->InstanceList == NULL)) {\r
+       (Node->InstanceList == NULL))\r
+    {\r
       errno   = EPERM;\r
-  }\r
+    }\r
     else {\r
   // Could add a test to see if the file name begins with a period.\r
   // If it does, then add the HIDDEN flag to Attributes.\r
@@ -625,23 +699,31 @@ open(
         fd = -1;              // Indicate an error\r
       }\r
       else {\r
-        // Re-use OpenMode in order to build our final f_iflags value\r
+        // Build our final f_iflags value\r
         OpenMode  = ( mode & S_ACC_READ )  ? S_ACC_READ : 0;\r
         OpenMode |= ( mode & S_ACC_WRITE ) ? S_ACC_WRITE : 0;\r
 \r
-        filp->f_iflags |= (UINT32)OpenMode;\r
+        filp->f_iflags |= OpenMode;\r
+\r
+        if((oflags & O_TTY_INIT) && (filp->f_iflags & _S_ITTY) && (filp->devdata != NULL)) {\r
+          // Initialize the device's termios flags to a "sane" value\r
+          Termio = &((cIIO *)filp->devdata)->Termio;\r
+          Termio->c_iflag = ICRNL | IGNSPEC;\r
+          Termio->c_oflag = OPOST | ONLCR | OXTABS | ONOEOT | ONOCR | ONLRET | OCTRL;\r
+          Termio->c_lflag = ECHO | ECHOE | ECHONL | ICANON;\r
+          Termio->c_cc[VERASE]  = 0x08;   // ^H Backspace\r
+          Termio->c_cc[VKILL]   = 0x15;   // ^U\r
+          Termio->c_cc[VINTR]   = 0x03;   // ^C Interrupt character\r
+        }\r
         ++filp->RefCount;\r
         FILE_SET_MATURE(filp);\r
       }\r
           }\r
     }\r
-    if(NewPath != NULL) {\r
     free(NewPath);\r
         }\r
-  }\r
-  if(MPath != NULL) {\r
     free(MPath);    // We don't need this any more.\r
-  }\r
+\r
   // return the fd of our now open file\r
   return fd;\r
 }\r
@@ -658,11 +740,11 @@ open(
   <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html">POSIX</a>\r
   documentation is available online.\r
 \r
-  @param [in] pfd       Address of an array of pollfd structures.\r
+  @param[in]  pfd       Address of an array of pollfd structures.\r
 \r
-  @param [in] nfds      Number of elements in the array of pollfd structures.\r
+  @param[in]  nfds      Number of elements in the array of pollfd structures.\r
 \r
-  @param [in] timeout   Length of time in milliseconds to wait for the event\r
+  @param[in]  timeout   Length of time in milliseconds to wait for the event\r
 \r
   @return     The number of file descriptors with detected events.  Zero\r
               indicates that the call timed out and -1 indicates an error.\r
@@ -800,38 +882,44 @@ poll (
 \r
 \r
 /** The rename() function changes the name of a file.\r
-    The old argument points to the pathname of the file to be renamed. The new\r
+    The From argument points to the pathname of the file to be renamed. The To\r
     argument points to the new pathname of the file.\r
 \r
-    If the old argument points to the pathname of a file that is not a\r
-    directory, the new argument shall not point to the pathname of a\r
-    directory. If the file named by the new argument exists, it shall be\r
-    removed and old renamed to new. Write access permission is required for\r
-    both the directory containing old and the directory containing new.\r
+    If the From argument points to the pathname of a file that is not a\r
+    directory, the To argument shall not point to the pathname of a\r
+    directory. If the file named by the To argument exists, it shall be\r
+    removed and From renamed to To. Write access permission is required for\r
+    both the directory containing old and the directory containing To.\r
 \r
-    If the old argument points to the pathname of a directory, the new\r
+    If the From argument points to the pathname of a directory, the To\r
     argument shall not point to the pathname of a file that is not a\r
-    directory. If the directory named by the new argument exists, it shall be\r
-    removed and old renamed to new.\r
+    directory. If the directory named by the To argument exists, it shall be\r
+    removed and From renamed to To.\r
 \r
-    The new pathname shall not contain a path prefix that names old. Write\r
-    access permission is required for the directory containing old and the\r
-    directory containing new. If the old argument points to the pathname of a\r
+    The To pathname shall not contain a path prefix that names From. Write\r
+    access permission is required for the directory containing From and the\r
+    directory containing To. If the From argument points to the pathname of a\r
     directory, write access permission may be required for the directory named\r
-    by old, and, if it exists, the directory named by new.\r
+    by From, and, if it exists, the directory named by To.\r
 \r
     If the rename() function fails for any reason other than [EIO], any file\r
-    named by new shall be unaffected.\r
+    named by To shall be unaffected.\r
+\r
+    @param[in]  From    Path to the file to be renamed.\r
+    @param[in]  To      The new name of From.\r
 \r
-    @return   Upon successful completion, rename() shall return 0; otherwise,\r
-              -1 shall be returned, errno shall be set to indicate the error,\r
-              and neither the file named by old nor the file named by new\r
-              shall be changed or created.\r
+    @retval   0     Successful completion.\r
+    @retval   -1    An error has occured and errno has been set to further specify the error.\r
+                    Neither the file named by From nor the file named by To are\r
+                    changed or created.\r
+                      - ENXIO: Path specified is not supported by any loaded driver.\r
+                      - ENOMEM: Insufficient memory to calloc a MapName buffer.\r
+                      - EINVAL: The path parameter is not valid.\r
 **/\r
 int\r
 rename(\r
-  const char *from,\r
-  const char *to\r
+  const char *From,\r
+  const char *To\r
   )\r
 {\r
   wchar_t            *FromPath;\r
@@ -841,7 +929,7 @@ rename(
   RETURN_STATUS       Status;\r
   int                 retval      = -1;\r
 \r
-  Status = ParsePath(from, &FromPath, &FromNode, &Instance, NULL);\r
+  Status = ParsePath(From, &FromPath, &FromNode, &Instance, NULL);\r
   if(Status == RETURN_SUCCESS) {\r
     GenI = FromNode->InstanceList;\r
     if(GenI == NULL) {\r
@@ -850,14 +938,19 @@ rename(
       }\r
       else {\r
       //GenI += (Instance * FromNode->InstanceSize);\r
-      retval = ((GenericInstance *)GenI)->Abstraction.fo_rename( from, to);\r
+      retval = ((GenericInstance *)GenI)->Abstraction.fo_rename( From, To);\r
               }\r
     free(FromPath);\r
             }\r
   return retval;\r
 }\r
 \r
-/**\r
+/** Delete a specified directory.\r
+\r
+    @param[in]  path    Path to the directory to delete.\r
+\r
+    @retval   -1    The directory couldn't be opened (doesn't exist).\r
+    @retval   -1    The directory wasn't empty or an IO error occured.\r
 **/\r
 int\r
 rmdir(\r
@@ -880,10 +973,10 @@ rmdir(
 }\r
 \r
 /** The fstat() function obtains information about an open file associated\r
-    with the file descriptor fildes, and shall write it to the area pointed to\r
-    by buf.\r
+    with the file descriptor fd, and writes it to the area pointed to\r
+    by statbuf.\r
 \r
-    The buf argument is a pointer to a stat structure, as defined\r
+    The statbuf argument is a pointer to a stat structure, as defined\r
     in <sys/stat.h>, into which information is placed concerning the file.\r
 \r
     The structure members st_mode, st_ino, st_dev, st_uid, st_gid, st_atime,\r
@@ -898,7 +991,7 @@ rmdir(
 \r
     The stat structure members which don't have direct analogs to EFI file\r
     information are filled in as follows:\r
-      - st_mode     Populated with information from fildes\r
+      - st_mode     Populated with information from fd\r
       - st_ino      Set to zero.  (inode)\r
       - st_dev      Set to zero.\r
       - st_uid      Set to zero.\r
@@ -933,6 +1026,9 @@ fstat (int fd, struct stat *statbuf)
     Opens the file pointed to by path, calls _EFI_FileInfo with the file's handle,\r
     then closes the file.\r
 \r
+    @param[in]    path      Path to the file to obtain information about.\r
+    @param[out]   statbuf   Buffer in which the file status is put.\r
+\r
     @retval    0  Successful Completion.\r
     @retval   -1  An error has occurred and errno has been set to\r
                   identify the error.\r
@@ -953,7 +1049,15 @@ stat   (const char *path, struct stat *statbuf)
   return retval;\r
 }\r
 \r
-/**  Same as stat since EFI doesn't have symbolic links.  **/\r
+/**  Same as stat since EFI doesn't have symbolic links.\r
+\r
+    @param[in]    path      Path to the file to obtain information about.\r
+    @param[out]   statbuf   Buffer in which the file status is put.\r
+\r
+    @retval    0  Successful Completion.\r
+    @retval   -1  An error has occurred and errno has been set to\r
+                  identify the error.\r
+**/\r
 int\r
 lstat (const char *path, struct stat *statbuf)\r
 {\r
@@ -961,6 +1065,13 @@ lstat (const char *path, struct stat *statbuf)
 }\r
 \r
 /** Control a device.\r
+\r
+    @param[in]        fd        Descriptor for the file to be acted upon.\r
+    @param[in]        request   Specifies the operation to perform.\r
+    @param[in,out]    ...       Zero or more parameters as required for request.\r
+\r
+    @retval   >=0   The operation completed successfully.\r
+    @retval   -1    An error occured.  More information is in errno.\r
 **/\r
 int\r
 ioctl(\r
@@ -1057,6 +1168,10 @@ ioctl(
     directory entries, the read returns a zero-length buffer.\r
     EFI_FILE_INFO is the structure returned as the directory entry.\r
 \r
+    @param[in]    fildes  Descriptor of the file to be read.\r
+    @param[out]   buf     Pointer to location in which to store the read data.\r
+    @param[in]    nbyte   Maximum number of bytes to be read.\r
+\r
     @return   Upon successful completion, read() returns a non-negative integer\r
               indicating the number of bytes actually read. Otherwise, the\r
               functions return a negative value and sets errno to indicate the\r
@@ -1068,62 +1183,91 @@ ssize_t
 read   (int fildes, void *buf, size_t nbyte)\r
 {\r
   struct __filedes *filp;\r
+  cIIO             *IIO;\r
   ssize_t           BufSize;\r
 \r
   BufSize = (ssize_t)nbyte;\r
-  if(ValidateFD( fildes, VALID_OPEN)) {\r
-    filp = &gMD->fdarray[fildes];\r
+  if(BufSize > 0) {\r
+    if(ValidateFD( fildes, VALID_OPEN)) {\r
+      filp = &gMD->fdarray[fildes];\r
 \r
-    BufSize = filp->f_ops->fo_read(filp, &filp->f_offset, nbyte, buf);\r
-  }\r
-  else {\r
-    errno = EBADF;\r
-    BufSize = -EBADF;\r
+      IIO = filp->devdata;\r
+      if(isatty(fildes) && (IIO != NULL)) {\r
+        BufSize = IIO->Read(filp, nbyte, buf);\r
+      }\r
+      else {\r
+        BufSize = filp->f_ops->fo_read(filp, &filp->f_offset, nbyte, buf);\r
+      }\r
+    }\r
+    else {\r
+      errno = EBADF;\r
+      BufSize = -1;\r
+    }\r
   }\r
   return BufSize;\r
 }\r
 \r
 /** Write data to a file.\r
 \r
-  This function writes the specified number of bytes to the file at the current\r
-  file position. The current file position is advanced the actual number of bytes\r
-  written, which is returned in BufferSize. Partial writes only occur when there\r
-  has been a data error during the write attempt (such as "volume space full").\r
-  The file is automatically grown to hold the data if required. Direct writes to\r
-  opened directories are not supported.\r
-\r
-  If fildes refers to a terminal device, isatty() returns TRUE, a partial write\r
-  will occur if a NULL or EOF character is encountered before n characters have\r
-  been written.  Characters inserted due to line-end translations will not be\r
-  counted.  Unconvertable characters are translated into the UEFI character\r
-  BLOCKELEMENT_LIGHT_SHADE.\r
-\r
-  Since the UEFI console device works on wide characters, the buffer is assumed\r
-  to contain a single-byte character stream which is then translated to wide\r
-  characters using the btowc() functions.  The resulting wide character stream\r
-  is what is actually sent to the UEFI console.\r
-\r
-  QUESTION:  Should writes to stdout or stderr always succeed?\r
+    This function writes the specified number of bytes to the file at the current\r
+    file position. The current file position is advanced the actual number of bytes\r
+    written, which is returned in BufferSize. Partial writes only occur when there\r
+    has been a data error during the write attempt (such as "volume space full").\r
+    The file is automatically grown to hold the data if required. Direct writes to\r
+    opened directories are not supported.\r
+\r
+    If fildes refers to a terminal device, isatty() returns TRUE, a partial write\r
+    will occur if a NULL or EOF character is encountered before n characters have\r
+    been written.  Characters inserted due to line-end translations will not be\r
+    counted.  Unconvertable characters are translated into the UEFI character\r
+    BLOCKELEMENT_LIGHT_SHADE.\r
+\r
+    Since the UEFI console device works on wide characters, the buffer is assumed\r
+    to contain a single-byte character stream which is then translated to wide\r
+    characters using the mbtowc() functions.  The resulting wide character stream\r
+    is what is actually sent to the UEFI console.\r
+\r
+    @param[in]  fd      Descriptor of file to be written to.\r
+    @param[in]  buf     Pointer to data to write to the file.\r
+    @param[in]  nbyte   Number of bytes to be written to the file.\r
+\r
+    @retval   >=0   Number of bytes actually written to the file.\r
+    @retval   <0    An error occurred.  More data is provided by errno.\r
 **/\r
 ssize_t\r
 write  (int fd, const void *buf, size_t nbyte)\r
 {\r
   struct __filedes *filp;\r
+  cIIO             *IIO;\r
   ssize_t           BufSize;\r
-//  EFI_FILE_HANDLE   FileHandle;\r
-//  RETURN_STATUS     Status = RETURN_SUCCESS;\r
 \r
   BufSize = (ssize_t)nbyte;\r
 \r
   if(ValidateFD( fd, VALID_OPEN)) {\r
     filp = &gMD->fdarray[fd];\r
-\r
-    BufSize = filp->f_ops->fo_write(filp, &filp->f_offset, nbyte, buf);\r
+    if ((filp->Oflags & O_ACCMODE) != 0) {\r
+      // File is open for writing\r
+      IIO = filp->devdata;\r
+      if(isatty(fd) && (IIO != NULL)) {\r
+        // Output to an Interactive I/O device\r
+        BufSize = IIO->Write(filp, buf, nbyte);\r
+      }\r
+      else {\r
+        // Output to a file, socket, pipe, etc.\r
+        BufSize = filp->f_ops->fo_write(filp, &filp->f_offset, nbyte, buf);\r
+      }\r
     }\r
     else {\r
+      // File is NOT open for writing\r
+      errno = EINVAL;\r
+      BufSize = -1;\r
+    }\r
+  }\r
+  else {\r
+    // fd is not for a valid open file\r
     errno = EBADF;\r
-    BufSize = -EBADF;\r
-      }\r
+    BufSize = -1;\r
+  }\r
   return BufSize;\r
 }\r
 \r
@@ -1219,11 +1363,29 @@ chdir (const char *path)
   return -1;\r
 }\r
 \r
+/** Get the foreground process group ID associated with a terminal.\r
+\r
+    Just returns the Image Handle for the requestor since UEFI does not have\r
+    a concept of processes or groups.\r
+\r
+    @param[in]    x   Ignored.\r
+\r
+    @return   Returns the Image Handle of the application or driver which\r
+              called this function.\r
+**/\r
 pid_t tcgetpgrp (int x)\r
 {\r
   return ((pid_t)(UINTN)(gImageHandle));\r
 }\r
 \r
+/** Get the process group ID of the calling process.\r
+\r
+    Just returns the Image Handle for the requestor since UEFI does not have\r
+    a concept of processes or groups.\r
+\r
+    @return   Returns the Image Handle of the application or driver which\r
+              called this function.\r
+**/\r
 pid_t getpgrp(void)\r
 {\r
   return ((pid_t)(UINTN)(gImageHandle));\r
@@ -1259,10 +1421,11 @@ va_Utimes(
 \r
 /** Set file access and modification times.\r
 \r
-    @param[in]  path\r
-    @param[in]  times\r
+    @param[in]  path    Path to the file to be modified.\r
+    @param[in]  times   Pointer to an array of two timeval structures\r
 \r
-    @return\r
+    @retval   0     File times successfully set.\r
+    @retval   -1    An error occured.  Error type in errno.\r
 **/\r
 int\r
 utimes(\r
@@ -1272,4 +1435,3 @@ utimes(
 {\r
   return va_Utimes(path, times);\r
 }\r
-\r