• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
ValidateFD(int fd,int IsOpen)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
FindFreeFD(int MinFd)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
DeleteOnClose(int fd)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
isatty(int fd)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
IsDupFd(int fd)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
_closeX(int fd,int NewState)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
close(int fd)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
unlink(const char * path)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
fcntl(int fildes,int cmd,...)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
dup(int fildes)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
dup2(int fildes,int fildes2)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
lseek(int fd,__off_t offset,int how)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
mkdir(const char * path,__mode_t perms)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
open(const char * path,int oflags,int mode)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
poll(struct pollfd * pfd,nfds_t nfds,int timeout)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
rename(const char * From,const char * To)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
rmdir(const char * path)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
fstat(int fd,struct stat * statbuf)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
stat(const char * path,struct stat * statbuf)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
lstat(const char * path,struct stat * statbuf)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
ioctl(int fd,unsigned long request,...)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
read(int fildes,void * buf,size_t nbyte)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
write(int fd,const void * buf,size_t nbyte)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
getcwd(char * buf,size_t size)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
chdir(const char * path)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 **/
tcgetpgrp(int x)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 **/
getpgrp(void)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
va_Utimes(const char * path,...)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
utimes(const char * path,const struct timeval * times)1442 utimes(
1443   const char *path,
1444   const struct timeval *times
1445   )
1446 {
1447   return va_Utimes(path, times);
1448 }
1449