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