StdLib: Add terminal type line editing (Interactive IO) for console devices.

Adds a subset of the terminal I/O capabilities described in the Single Unix Specification, V4.
Supports:
    Erase previous character.  Default is Backspace or ^H
    Erase line.  Default is ^U
TAB characters are supported and, by default, are rendered as 8 spaces.  They will still be read as a single TAB character.
Both Canonical and Non-Canonical modes are supported.
If a terminal device is opened with O_TTY_INIT in the mode, the device will be initialized to "sane" values for interactive use.  It will be in Canonical mode, Enter will be translated to NewLine and on output, a NewLine is translated to CRLF.  Echoing will be on, control characters are output as ^X, and TABs are expanded.
See the new <sys/termios.h> file for more information.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by:  daryl.mcdaniel@intel.com
Reviewed-by:    erik.c.bjorge@intel.com
Reviewed-by:    leroy.p.leahy@intel.com
Reviewed-by:    lee.g.rosenbaum@intel.com
Reviewed-by:    jaben.carsey@intel.com





git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13989 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
darylm503
2012-12-11 21:19:14 +00:00
parent e575c101d8
commit 6c6c850ad6
23 changed files with 3404 additions and 218 deletions

View File

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