The Pedigree Project  0.1
file-syscalls.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "modules/system/console/Console.h"
22 #include "modules/system/users/Group.h"
23 #include "modules/system/users/User.h"
24 #include "modules/system/users/UserManager.h"
25 #include "modules/system/vfs/Directory.h"
26 #include "modules/system/vfs/File.h"
27 #include "modules/system/vfs/LockedFile.h"
29 #include "modules/system/vfs/Pipe.h"
30 #include "modules/system/vfs/Symlink.h"
31 #include "modules/system/vfs/VFS.h"
32 #include "pedigree/kernel/compiler.h"
33 #include "pedigree/kernel/machine/Disk.h"
34 #include "pedigree/kernel/machine/Keyboard.h"
35 #include "pedigree/kernel/machine/KeymapManager.h"
36 #include "pedigree/kernel/machine/Machine.h"
37 #include "pedigree/kernel/process/Process.h"
38 #include "pedigree/kernel/processor/MemoryRegion.h"
39 #include "pedigree/kernel/processor/PhysicalMemoryManager.h"
40 #include "pedigree/kernel/processor/Processor.h"
41 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
42 #include "pedigree/kernel/processor/types.h"
43 #include "pedigree/kernel/syscallError.h"
44 #include "pedigree/kernel/utilities/PointerGuard.h"
45 #include "pedigree/kernel/utilities/Tree.h"
46 #include "pedigree/kernel/utilities/utility.h"
47 
48 #include "modules/subsys/posix/IoEvent.h"
49 #include "pedigree/kernel/Subsystem.h"
50 #include <FileDescriptor.h>
51 #include <PosixProcess.h>
52 #include <PosixSubsystem.h>
53 
54 #include "console-syscalls.h"
55 #include "file-syscalls.h"
56 #include "net-syscalls.h"
57 #include "pipe-syscalls.h"
58 
59 #include <dirent.h>
60 #include <fcntl.h>
61 #include <limits.h>
62 #include <stddef.h>
63 #include <sys/ioctl.h>
64 #include <sys/mman.h>
65 #include <sys/stat.h>
66 #include <sys/statfs.h>
67 #include <sys/statvfs.h>
68 #include <termios.h>
69 #include <utime.h>
70 
71 // Emits a lot of logs in normalisePath to help debug remaps.
72 #define ENABLE_VERBOSE_NORMALISATION 0
73 
74 extern int posix_getpid();
75 
76 // For getdents() (getdents64 uses a compatible struct dirent).
78 {
79  long d_ino;
80  off_t d_off;
81  unsigned short d_reclen;
82  char d_name[1];
83 };
84 
85 extern DevFs *g_pDevFs;
86 
87 //
88 // Syscalls pertaining to files.
89 //
90 
91 #define CHECK_FLAG(a, b) (((a) & (b)) == (b))
92 
93 #define GET_CWD() \
94  (Processor::information().getCurrentThread()->getParent()->getCwd())
95 
96 static PosixProcess *getPosixProcess()
97 {
98  Process *pStockProcess =
99  Processor::information().getCurrentThread()->getParent();
100  if (pStockProcess->getType() != Process::Posix)
101  {
102  return 0;
103  }
104 
105  PosixProcess *pProcess = static_cast<PosixProcess *>(pStockProcess);
106  return pProcess;
107 }
108 
109 File *findFileWithAbiFallbacks(const String &name, File *cwd)
110 {
111  Process *pProcess =
112  Processor::information().getCurrentThread()->getParent();
113  PosixSubsystem *pSubsystem =
114  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
115  return pSubsystem->findFile(name, cwd);
116 }
117 
118 static File *traverseSymlink(File *file)
119 {
121  if (!file)
122  {
123  SYSCALL_ERROR(DoesNotExist);
124  return 0;
125  }
126 
127  Tree<File *, File *> loopDetect;
128  while (file->isSymlink())
129  {
130  file = Symlink::fromFile(file)->followLink();
131  if (!file)
132  {
133  SYSCALL_ERROR(DoesNotExist);
134  return 0;
135  }
136 
137  if (loopDetect.lookup(file))
138  {
139  SYSCALL_ERROR(LoopExists);
140  return 0;
141  }
142  else
143  loopDetect.insert(file, file);
144  }
145 
146  return file;
147 }
148 
149 static bool doChdir(File *dir)
150 {
151  File *target = 0;
152  if (dir->isSymlink())
153  {
154  target = traverseSymlink(dir);
155  if (!target)
156  {
157  F_NOTICE("Symlink traversal failed.");
158  SYSCALL_ERROR(DoesNotExist);
159  return false;
160  }
161  }
162 
163  if (dir &&
164  (dir->isDirectory() || (dir->isSymlink() && target->isDirectory())))
165  {
166  File *pRealFile = dir;
167  if (dir->isSymlink())
168  {
169  pRealFile = target;
170  }
171 
172  // Only need execute permissions to enter a directory.
173  if (!VFS::checkAccess(pRealFile, false, false, true))
174  {
175  return false;
176  }
177 
178  Processor::information().getCurrentThread()->getParent()->setCwd(dir);
179  }
180  else if (dir && !dir->isDirectory())
181  {
182  SYSCALL_ERROR(NotADirectory);
183  return false;
184  }
185  else
186  {
187  SYSCALL_ERROR(DoesNotExist);
188  return false;
189  }
190 
191  return true;
192 }
193 
194 static bool
195 doStat(const char *name, File *pFile, struct stat *st, bool traverse = true)
196 {
197  if (traverse)
198  {
199  pFile = traverseSymlink(pFile);
200  if (!pFile)
201  {
202  F_NOTICE(" -> Symlink traversal failed");
203  return -1;
204  }
205  }
206 
207  int mode = 0;
209  if (ConsoleManager::instance().isConsole(pFile) ||
210  (name && !StringCompare(name, "/dev/null")) ||
211  (pFile && pFile->getName() == "null"))
212  {
213  F_NOTICE(" -> S_IFCHR");
214  mode = S_IFCHR;
215  }
216  else if (pFile->isDirectory())
217  {
218  F_NOTICE(" -> S_IFDIR");
219  mode = S_IFDIR;
220  }
221  else if (pFile->isSymlink() || pFile->isPipe())
222  {
223  F_NOTICE(" -> S_IFLNK");
224  mode = S_IFLNK;
225  }
226  else if (pFile->isFifo())
227  {
228  F_NOTICE(" -> S_FIFO");
229  mode = S_IFIFO;
230  }
231  else if (pFile->isSocket())
232  {
233  F_NOTICE(" -> S_SOCK");
234  mode = S_IFSOCK;
235  }
236  else
237  {
238  F_NOTICE(" -> S_IFREG");
239  mode = S_IFREG;
240  }
241 
242  // Clear any cruft in the stat structure before we fill it.
243  ByteSet(st, 0, sizeof(*st));
244 
245  uint32_t permissions = pFile->getPermissions();
246  if (permissions & FILE_UR)
247  mode |= S_IRUSR;
248  if (permissions & FILE_UW)
249  mode |= S_IWUSR;
250  if (permissions & FILE_UX)
251  mode |= S_IXUSR;
252  if (permissions & FILE_GR)
253  mode |= S_IRGRP;
254  if (permissions & FILE_GW)
255  mode |= S_IWGRP;
256  if (permissions & FILE_GX)
257  mode |= S_IXGRP;
258  if (permissions & FILE_OR)
259  mode |= S_IROTH;
260  if (permissions & FILE_OW)
261  mode |= S_IWOTH;
262  if (permissions & FILE_OX)
263  mode |= S_IXOTH;
264  if (permissions & FILE_STICKY)
265  mode |= S_ISVTX;
266  F_NOTICE(" -> " << Oct << mode);
267 
268  Filesystem *pFs = pFile->getFilesystem();
269 
271  st->st_dev =
272  static_cast<short>(reinterpret_cast<uintptr_t>(pFile->getFilesystem()));
273  F_NOTICE(" -> " << st->st_dev);
274  st->st_ino = static_cast<short>(pFile->getInode());
275  F_NOTICE(" -> " << st->st_ino);
276  st->st_mode = mode;
277  st->st_nlink = 1;
278  st->st_uid = pFile->getUid();
279  st->st_gid = pFile->getGid();
280  F_NOTICE(" -> uid=" << Dec << st->st_uid);
281  F_NOTICE(" -> gid=" << Dec << st->st_gid);
282  st->st_rdev = 0;
283  st->st_size = static_cast<int>(pFile->getSize());
284  F_NOTICE(" -> " << st->st_size);
285  st->st_atime = pFile->getAccessedTime();
286  st->st_mtime = pFile->getModifiedTime();
287  st->st_ctime = pFile->getCreationTime();
288  st->st_blksize = static_cast<int>(pFile->getBlockSize());
289  st->st_blocks = (st->st_size / st->st_blksize) +
290  ((st->st_size % st->st_blksize) ? 1 : 0);
291 
292  // Special fixups
293  if (pFs == g_pDevFs)
294  {
295  if ((name && !StringCompare(name, "/dev/null")) ||
296  (pFile->getName() == "null"))
297  {
298  F_NOTICE("/dev/null, fixing st_rdev");
299  // major/minor device numbers
300  st->st_rdev = 0x0103;
301  }
302  else if (ConsoleManager::instance().isConsole(pFile))
303  {
305  ConsoleFile *pConsole = static_cast<ConsoleFile *>(pFile);
306  st->st_rdev = 0x8800 | pConsole->getConsoleNumber();
307  }
308  }
309 
310  return true;
311 }
312 
313 static bool doChmod(File *pFile, mode_t mode)
314 {
315  // Are we the owner of the file?
316  User *pCurrentUser =
317  Processor::information().getCurrentThread()->getParent()->getUser();
318 
319  size_t uid = pCurrentUser->getId();
320  if (!(uid == pFile->getUid() || uid == 0))
321  {
322  F_NOTICE(" -> EPERM");
323  // Not allowed - EPERM.
324  // User must own the file or be superuser.
325  SYSCALL_ERROR(NotEnoughPermissions);
326  return false;
327  }
328 
330  uint32_t permissions = 0;
331  if (mode & S_IRUSR)
332  permissions |= FILE_UR;
333  if (mode & S_IWUSR)
334  permissions |= FILE_UW;
335  if (mode & S_IXUSR)
336  permissions |= FILE_UX;
337  if (mode & S_IRGRP)
338  permissions |= FILE_GR;
339  if (mode & S_IWGRP)
340  permissions |= FILE_GW;
341  if (mode & S_IXGRP)
342  permissions |= FILE_GX;
343  if (mode & S_IROTH)
344  permissions |= FILE_OR;
345  if (mode & S_IWOTH)
346  permissions |= FILE_OW;
347  if (mode & S_IXOTH)
348  permissions |= FILE_OX;
349  if (mode & S_ISVTX)
350  permissions |= FILE_STICKY;
351  pFile->setPermissions(permissions);
352 
353  return true;
354 }
355 
356 static bool doChown(File *pFile, uid_t owner, gid_t group)
357 {
358  // If we're root, changing is fine.
359  size_t newOwner = pFile->getUid();
360  size_t newGroup = pFile->getGid();
361  if (owner != static_cast<uid_t>(-1))
362  {
363  newOwner = owner;
364  }
365  if (group != static_cast<gid_t>(-1))
366  {
367  newGroup = group;
368  }
369 
370  // We can only chown the user if we're root.
371  if (pFile->getUid() != newOwner)
372  {
373  User *pCurrentUser =
374  Processor::information().getCurrentThread()->getParent()->getUser();
375  if (pCurrentUser->getId())
376  {
377  SYSCALL_ERROR(NotEnoughPermissions);
378  return false;
379  }
380  }
381 
382  // We can change the group to anything if we're root, but otherwise only
383  // to a group we're a member of.
384  if (pFile->getGid() != newGroup)
385  {
386  User *pCurrentUser =
387  Processor::information().getCurrentThread()->getParent()->getUser();
388  if (pCurrentUser->getId())
389  {
390  Group *pTargetGroup = UserManager::instance().getGroup(newGroup);
391  if (!pTargetGroup->isMember(pCurrentUser))
392  {
393  SYSCALL_ERROR(NotEnoughPermissions);
394  return false;
395  }
396  }
397  }
398 
399  // Update the file's uid/gid now that we've checked we're allowed to.
400  if (pFile->getUid() != newOwner)
401  {
402  pFile->setUid(newOwner);
403  }
404 
405  if (pFile->getGid() != newGroup)
406  {
407  pFile->setGid(newGroup);
408  }
409 
410  return true;
411 }
412 
413 // NON-special-case remappings.
414 static struct Remapping
415 {
416  // from must match either completely, or be followed by a "/"
417  const char *from;
418  const char *to;
419  const char *fsname; // certain remaps are to be reported as custom FS's to
420  // some ABIs
421  bool all_abis; // certain ABIs shouldn't normalise certain paths
422  bool on_devfs; // certain callers care about the result being on devfs
423 } g_Remappings[] = {
424  {"/dev", "dev»", nullptr, true, true},
425  {"/proc", "proc»", "proc", true, false},
426  {"/bin", "/applications", nullptr, false, false},
427  {"/usr/bin", "/applications", nullptr, false, false},
428  {"/lib", "/libraries", nullptr, false, false},
429  {"/etc", "/config", nullptr, false, false},
430  {"/tmp", "scratch»", "tmpfs", true, false},
431  {"/var/run", "posix-runtime»", "tmpfs", true, false},
432  {nullptr, nullptr, nullptr, false, false},
433 };
434 
435 bool normalisePath(String &nameToOpen, const char *name, bool *onDevFs)
436 {
437  Process *pProcess =
438  Processor::information().getCurrentThread()->getParent();
439  PosixSubsystem *pSubsystem =
440  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
441  bool fixFilesystemPaths = pSubsystem->getAbi() != PosixSubsystem::LinuxAbi;
442 
443  // Rebase /dev onto the devfs. /dev/tty is special.
444  // Note: in all these we may need to accept the raw directory but nothing
445  // more (e.g. /libfoo should not become /libraries, but /lib DOES become
446  // /libraries because it has no further characters)
447  if (!StringCompare(name, "/dev/tty"))
448  {
449  // Get controlling console, unless we have none.
450  if (!pProcess->getCtty())
451  {
452  if (onDevFs)
453  *onDevFs = true;
454  }
455 
456  nameToOpen = name;
457  return true;
458  }
459  else if (!StringCompareN(name, "/@/", StringLength("/@/")))
460  {
461  // Absolute UNIX paths for POSIX stupidity.
462  // /@/path/to/foo = /path/to/foo
463  // /@/root»/applications = root»/applications
464  const char *newName = name + StringLength("/@/");
465  if (*newName == '/')
466  ++newName;
467  nameToOpen = newName;
468  return true;
469  }
470  else
471  {
472  // try the remappings
473  struct Remapping *remap = g_Remappings;
474 #if ENABLE_VERBOSE_NORMALISATION
475  F_NOTICE("performing remap for '" << name << "'...");
476 #endif
477  bool ok = false;
478  while (remap->from != nullptr)
479  {
480  if (!(fixFilesystemPaths || remap->all_abis))
481  {
482 #if ENABLE_VERBOSE_NORMALISATION
483  F_NOTICE(
484  " -> ignoring " << remap->from
485  << " as it is not for the current ABI");
486 #endif
487  ++remap;
488  continue;
489  }
490 
491 #if ENABLE_VERBOSE_NORMALISATION
492  F_NOTICE(" -> check against " << remap->from);
493 #endif
494  if (!StringCompare(name, remap->from))
495  {
496 #if ENABLE_VERBOSE_NORMALISATION
497  F_NOTICE(" -> direct remap to " << remap->to);
498 #endif
499  nameToOpen = remap->to;
500  ok = true;
501  break;
502  }
503 
504  // does not match directly, so we need to check for a partial match
505  if (!StringCompareN(name, remap->from, StringLength(remap->from)))
506  {
507 #if ENABLE_VERBOSE_NORMALISATION
508  F_NOTICE(" -> possibly partial remap");
509 #endif
510 
511  // we have a partial match, but this only OK if the following
512  // character is '/' to avoid incorrectly rewriting paths
513  if (*(name + StringLength(remap->from)) == '/')
514  {
515  // good
516  nameToOpen = remap->to;
517  nameToOpen += (name + StringLength(remap->from));
518 #if ENABLE_VERBOSE_NORMALISATION
519  F_NOTICE(
520  " -> indirect remap to create path '" << nameToOpen
521  << "'...");
522 #endif
523  ok = true;
524  break;
525  }
526 
527 // no good
528 #if ENABLE_VERBOSE_NORMALISATION
529  NOTICE(" -> cannot use this remap as it is not actually "
530  "matching a path segment");
531 #endif
532  }
533 
534  ++remap;
535  }
536 
537  if (onDevFs && remap)
538  {
539  *onDevFs = remap->on_devfs;
540  }
541 
542  if (!ok)
543  {
544  nameToOpen = name;
545  return false;
546  }
547 
548  return true;
549  }
550 }
551 
552 int posix_close(int fd)
553 {
554 #ifdef VERBOSE_KERNEL
555  F_NOTICE("close(" << fd << ")");
556 #endif
557  Process *pProcess =
558  Processor::information().getCurrentThread()->getParent();
559  PosixSubsystem *pSubsystem =
560  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
561  if (!pSubsystem)
562  {
563  ERROR("No subsystem for this process!");
564  return -1;
565  }
566 
567  FileDescriptor *pFd = pSubsystem->getFileDescriptor(fd);
568  if (!pFd)
569  {
570  // Error - no such file descriptor.
571  SYSCALL_ERROR(BadFileDescriptor);
572  return -1;
573  }
574 
575 #ifndef VERBOSE_KERNEL
576  F_NOTICE("close(" << fd << ")");
577 #endif
578 
579  // If this was a master psuedoterminal, we should unlock it now.
580  if (ConsoleManager::instance().isConsole(pFd->file))
581  {
582  if (ConsoleManager::instance().isMasterConsole(pFd->file))
583  {
584  ConsoleManager::instance().unlockConsole(pFd->file);
585  }
586  }
587 
588  pSubsystem->freeFd(fd);
589  return 0;
590 }
591 
592 int posix_open(const char *name, int flags, int mode)
593 {
594  return posix_openat(AT_FDCWD, name, flags, mode);
595 }
596 
597 int posix_read(int fd, char *ptr, int len)
598 {
599  F_NOTICE(
600  "read(" << Dec << fd << Hex << ", " << reinterpret_cast<uintptr_t>(ptr)
601  << ", " << len << ")");
603  reinterpret_cast<uintptr_t>(ptr), len, PosixSubsystem::SafeWrite))
604  {
605  F_NOTICE(" -> invalid address");
606  SYSCALL_ERROR(InvalidArgument);
607  return -1;
608  }
609 
610  // Lookup this process.
611  Thread *pThread = Processor::information().getCurrentThread();
612  Process *pProcess = pThread->getParent();
613  PosixSubsystem *pSubsystem =
614  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
615  if (!pSubsystem)
616  {
617  ERROR("No subsystem for this process!");
618  return -1;
619  }
620 
621  FileDescriptor *pFd = pSubsystem->getFileDescriptor(fd);
622  if (!pFd)
623  {
624  // Error - no such file descriptor.
625  SYSCALL_ERROR(BadFileDescriptor);
626  return -1;
627  }
628 
629  if (pFd->networkImpl)
630  {
631  // Need to redirect to socket implementation.
632  return posix_recv(fd, ptr, len, 0);
633  }
634 
635  if (pFd->file->isDirectory())
636  {
637  SYSCALL_ERROR(IsADirectory);
638  return -1;
639  }
640 
641  // Are we allowed to block?
642  bool canBlock = !((pFd->flflags & O_NONBLOCK) == O_NONBLOCK);
643 
644  // Handle async descriptor that is not ready for reading.
645  // File::read has no mechanism for presenting such an error, other than
646  // returning 0. However, a read() returning 0 is an EOF condition.
647  if (!canBlock)
648  {
649  if (!pFd->file->select(false, 0))
650  {
651  SYSCALL_ERROR(NoMoreProcesses);
652  F_NOTICE(" -> async and nothing available to read");
653  return -1;
654  }
655  }
656 
657  // Prepare to handle EINTR.
658  uint64_t nRead = 0;
659  if (ptr && len)
660  {
661  pThread->setInterrupted(false);
662  Thread::WakeReason wakeReason = Thread::NotWoken;
663  pThread->addWakeupWatcher(&wakeReason);
664  nRead = pFd->file->read(
665  pFd->offset, len, reinterpret_cast<uintptr_t>(ptr), canBlock);
666  pThread->removeWakeupWatcher(&wakeReason);
670  if ((!nRead) && pThread->wasInterrupted())
671  {
672  SYSCALL_ERROR(Interrupted);
673  F_NOTICE(" -> interrupted");
674  return -1;
675  }
676  pFd->offset += nRead;
677  }
678 
679  if (ptr && nRead)
680  {
681  // Need to use unsafe for String::assign so StringLength doesn't get
682  // called, as this does not always end up zero-terminated.
683  String debug;
684  debug.assign(ptr, nRead, true);
685  F_NOTICE(" -> read: '" << debug << "'");
686  }
687 
688  F_NOTICE(" -> " << Dec << nRead << Hex);
689 
690  return static_cast<int>(nRead);
691 }
692 
693 int posix_write(int fd, char *ptr, int len, bool nocheck)
694 {
695  F_NOTICE(
696  "write(" << fd << ", " << reinterpret_cast<uintptr_t>(ptr) << ", "
697  << len << ")");
698  if (!nocheck &&
700  reinterpret_cast<uintptr_t>(ptr), len, PosixSubsystem::SafeRead))
701  {
702  F_NOTICE(" -> invalid address");
703  SYSCALL_ERROR(InvalidArgument);
704  return -1;
705  }
706 
707  if (ptr && len > 0)
708  {
709  // Need to use unsafe for String::assign so StringLength doesn't get
710  // called, as this does not always end up zero-terminated.
711  String debug;
712  debug.assign(ptr, len - 1, true);
713  F_NOTICE("write(" << fd << ", " << debug << ", " << len << ")");
714  }
715 
716  // Lookup this process.
717  Thread *pThread = Processor::information().getCurrentThread();
718  Process *pProcess = pThread->getParent();
719  PosixSubsystem *pSubsystem =
720  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
721  if (!pSubsystem)
722  {
723  ERROR("No subsystem for this process!");
724  return -1;
725  }
726 
727  FileDescriptor *pFd = pSubsystem->getFileDescriptor(fd);
728  if (!pFd)
729  {
730  // Error - no such file descriptor.
731  SYSCALL_ERROR(BadFileDescriptor);
732  return -1;
733  }
734 
735  if (pFd->networkImpl)
736  {
737  // Need to redirect to socket implementation.
738  return posix_send(fd, ptr, len, 0);
739  }
740 
741  // Copy to kernel.
742  uint64_t nWritten = 0;
743  if (ptr && len)
744  {
745  nWritten = pFd->file->write(
746  pFd->offset, len, reinterpret_cast<uintptr_t>(ptr));
747  pFd->offset += nWritten;
748  }
749 
750  F_NOTICE(" -> write returns " << nWritten);
751 
752  // Handle broken pipe (write of zero bytes to a pipe).
753  // Note: don't send SIGPIPE if we actually tried a zero-length write.
754  if (pFd->file->isPipe() && (nWritten == 0 && len > 0))
755  {
756  F_NOTICE(" -> write to a broken pipe");
757  SYSCALL_ERROR(BrokenPipe);
758  pSubsystem->threadException(pThread, Subsystem::Pipe);
759  return -1;
760  }
761 
762  return static_cast<int>(nWritten);
763 }
764 
765 int posix_writev(int fd, const struct iovec *iov, int iovcnt)
766 {
767  F_NOTICE("writev(" << fd << ", <iov>, " << iovcnt << ")");
768 
770 
771  if (iovcnt <= 0)
772  {
773  SYSCALL_ERROR(InvalidArgument);
774  return -1;
775  }
776 
777  int totalWritten = 0;
778  for (int i = 0; i < iovcnt; ++i)
779  {
780  F_NOTICE(
781  "writev: iov[" << i << "] is @ " << iov[i].iov_base << ", "
782  << iov[i].iov_len << " bytes.");
783 
784  if (!iov[i].iov_len)
785  continue;
786 
787  int r = posix_write(
788  fd, reinterpret_cast<char *>(iov[i].iov_base), iov[i].iov_len,
789  false);
790  if (r < 0)
791  {
794  return r;
795  }
796 
797  totalWritten += r;
798  }
799 
800  return totalWritten;
801 }
802 
803 int posix_readv(int fd, const struct iovec *iov, int iovcnt)
804 {
805  F_NOTICE("readv(" << fd << ", <iov>, " << iovcnt << ")");
806 
808 
809  if (iovcnt <= 0)
810  {
811  SYSCALL_ERROR(InvalidArgument);
812  return -1;
813  }
814 
815  int totalRead = 0;
816  for (int i = 0; i < iovcnt; ++i)
817  {
818  F_NOTICE(
819  "readv: iov[" << i << "] is @ " << iov[i].iov_base << ", "
820  << iov[i].iov_len << " bytes.");
821 
822  if (!iov[i].iov_len)
823  continue;
824 
825  int r = posix_read(
826  fd, reinterpret_cast<char *>(iov[i].iov_base), iov[i].iov_len);
827  if (r < 0)
828  {
831  return r;
832  }
833 
834  totalRead += r;
835  }
836 
837  return totalRead;
838 }
839 
840 off_t posix_lseek(int file, off_t ptr, int dir)
841 {
842  F_NOTICE("lseek(" << file << ", " << ptr << ", " << dir << ")");
843 
844  // Lookup this process.
845  Process *pProcess =
846  Processor::information().getCurrentThread()->getParent();
847  PosixSubsystem *pSubsystem =
848  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
849  if (!pSubsystem)
850  {
851  ERROR("No subsystem for this process!");
852  return -1;
853  }
854 
855  FileDescriptor *pFd = pSubsystem->getFileDescriptor(file);
856  if (!pFd)
857  {
858  // Error - no such file descriptor.
859  SYSCALL_ERROR(BadFileDescriptor);
860  return -1;
861  }
862 
863  size_t fileSize = pFd->file->getSize();
864  switch (dir)
865  {
866  case SEEK_SET:
867  pFd->offset = ptr;
868  break;
869  case SEEK_CUR:
870  pFd->offset += ptr;
871  break;
872  case SEEK_END:
873  pFd->offset = fileSize + ptr;
874  break;
875  }
876 
877  return static_cast<int>(pFd->offset);
878 }
879 
880 int posix_link(char *target, char *link)
881 {
882  return posix_linkat(AT_FDCWD, target, AT_FDCWD, link, AT_SYMLINK_FOLLOW);
883 }
884 
885 int posix_readlink(const char *path, char *buf, unsigned int bufsize)
886 {
887  return posix_readlinkat(AT_FDCWD, path, buf, bufsize);
888 }
889 
890 int posix_realpath(const char *path, char *buf, size_t bufsize)
891 {
892  F_NOTICE("realpath");
893 
895  reinterpret_cast<uintptr_t>(path), PATH_MAX,
896  PosixSubsystem::SafeRead) &&
898  reinterpret_cast<uintptr_t>(buf), bufsize,
899  PosixSubsystem::SafeWrite)))
900  {
901  F_NOTICE("realpath -> invalid address");
902  SYSCALL_ERROR(InvalidArgument);
903  return -1;
904  }
905 
906  String realPath;
907  normalisePath(realPath, path);
908  F_NOTICE(" -> traversing " << realPath);
909  File *f = findFileWithAbiFallbacks(realPath, GET_CWD());
910  if (!f)
911  {
912  SYSCALL_ERROR(DoesNotExist);
913  return -1;
914  }
915 
916  f = traverseSymlink(f);
917  if (!f)
918  {
919  SYSCALL_ERROR(DoesNotExist);
920  return -1;
921  }
922 
923  if (!f->isDirectory())
924  {
925  SYSCALL_ERROR(NotADirectory);
926  return -1;
927  }
928 
929  String actualPath("/@/");
930  actualPath += f->getFullPath(true);
931  if (actualPath.length() > (bufsize - 1))
932  {
933  SYSCALL_ERROR(NameTooLong);
934  return -1;
935  }
936 
937  // File is good, copy it now.
938  F_NOTICE(" -> returning " << actualPath);
939  StringCopyN(buf, static_cast<const char *>(actualPath), bufsize);
940 
941  return 0;
942 }
943 
944 int posix_unlink(char *name)
945 {
946  return posix_unlinkat(AT_FDCWD, name, 0);
947 }
948 
949 int posix_symlink(char *target, char *link)
950 {
951  return posix_symlinkat(target, AT_FDCWD, link);
952 }
953 
954 int posix_rename(const char *source, const char *dst)
955 {
956  return posix_renameat(AT_FDCWD, source, AT_FDCWD, dst);
957 }
958 
959 int posix_getcwd(char *buf, size_t maxlen)
960 {
962  reinterpret_cast<uintptr_t>(buf), maxlen,
963  PosixSubsystem::SafeWrite))
964  {
965  F_NOTICE("getcwd -> invalid address");
966  SYSCALL_ERROR(InvalidArgument);
967  return -1;
968  }
969 
970  F_NOTICE("getcwd(" << maxlen << ")");
971 
972  File *curr = GET_CWD();
973 
974  // Absolute path syntax.
975  String str("/@/");
976  str += curr->getFullPath(true);
977 
978  size_t maxLength = str.length();
979  if (maxLength > maxlen)
980  {
981  // Too long.
982  SYSCALL_ERROR(BadRange);
983  return -1;
984  }
985  StringCopyN(buf, static_cast<const char *>(str), maxLength);
986 
987  F_NOTICE(" -> " << str);
988 
989  return maxLength + 1; // include null terminator
990 }
991 
992 int posix_stat(const char *name, struct stat *st)
993 {
994  F_NOTICE("stat(" << name << ") => fstatat");
995  return posix_fstatat(AT_FDCWD, name, st, 0);
996 }
997 
998 int posix_fstat(int fd, struct stat *st)
999 {
1000  F_NOTICE("fstat(" << fd << ") => fstatat");
1001  return posix_fstatat(fd, 0, st, AT_EMPTY_PATH);
1002 }
1003 
1004 int posix_lstat(char *name, struct stat *st)
1005 {
1006  F_NOTICE("lstat(" << name << ") => fstatat");
1007  return posix_fstatat(AT_FDCWD, name, st, AT_SYMLINK_NOFOLLOW);
1008 }
1009 
1010 static int getdents_common(
1011  int fd, size_t (*set_dent)(File *, void *, size_t, size_t), void *buffer,
1012  int count)
1013 {
1014  // Lookup this process.
1015  Process *pProcess =
1016  Processor::information().getCurrentThread()->getParent();
1017  PosixSubsystem *pSubsystem =
1018  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
1019  if (!pSubsystem)
1020  {
1021  ERROR("No subsystem for this process!");
1022  return -1;
1023  }
1024 
1025  FileDescriptor *pFd = pSubsystem->getFileDescriptor(fd);
1026  if (!pFd || !pFd->file)
1027  {
1028  // Error - no such file descriptor.
1029  F_NOTICE(" -> bad file");
1030  SYSCALL_ERROR(BadFileDescriptor);
1031  return -1;
1032  }
1033 
1034  if (!pFd->file->isDirectory())
1035  {
1036  F_NOTICE(" -> not a directory");
1037  SYSCALL_ERROR(NotADirectory);
1038  return -1;
1039  }
1040 
1041  if (!count)
1042  {
1043  F_NOTICE(" -> count is zero");
1044  return 0;
1045  }
1046 
1047  // Navigate the directory tree.
1048  Directory *pDirectory = Directory::fromFile(pFd->file);
1049  size_t truePosition = pFd->offset;
1050  int offset = 0;
1051  for (; truePosition < pDirectory->getNumChildren() && offset < count;
1052  ++truePosition)
1053  {
1054  File *pFile = pDirectory->getChild(truePosition);
1055  if (!pFile)
1056  break;
1057 
1058  F_NOTICE(" -> " << pFile->getName());
1059  size_t reclen =
1060  set_dent(pFile, buffer, count - offset, truePosition + 1);
1061  if (reclen == 0)
1062  {
1063  // no more room
1064  break;
1065  }
1066 
1067  buffer = adjust_pointer(buffer, reclen);
1068  offset += reclen;
1069  }
1070 
1071  size_t totalCount = truePosition - pFd->offset;
1072  pFd->offset = truePosition;
1073 
1074  F_NOTICE(" -> " << offset);
1075  return offset;
1076 }
1077 
1078 static size_t
1079 getdents_helper(File *file, void *buffer, size_t avail, size_t next_pos)
1080 {
1081  struct linux_dirent *entry =
1082  reinterpret_cast<struct linux_dirent *>(buffer);
1083  char *char_buffer = reinterpret_cast<char *>(buffer);
1084 
1085  size_t filenameLength = file->getName().length();
1086  // dirent struct, filename, null terminator, and d_type
1087  size_t reclen = sizeof(struct linux_dirent) + filenameLength + 2;
1088  // do we have room for this record?
1089  if (avail < reclen)
1090  {
1091  // need to call again with more space available
1092  return 0;
1093  }
1094 
1095  entry->d_reclen = reclen;
1096  entry->d_off = next_pos;
1097 
1098  entry->d_ino = file->getInode();
1099  if (!entry->d_ino)
1100  {
1101  entry->d_ino = ~0U;
1102  }
1103 
1104  StringCopy(entry->d_name, static_cast<const char *>(file->getName()));
1105  char_buffer[reclen - 2] = 0;
1106 
1107  char d_type = DT_UNKNOWN;
1108  if (file->isSymlink() || file->isPipe())
1109  {
1110  d_type = DT_LNK;
1111  }
1112  else if (file->isDirectory())
1113  {
1114  d_type = DT_DIR;
1115  }
1116  else
1117  {
1119  d_type = DT_REG;
1120  }
1121  char_buffer[reclen - 1] = d_type;
1122 
1123  return reclen;
1124 }
1125 
1126 static size_t
1127 getdents64_helper(File *file, void *buffer, size_t avail, size_t next_pos)
1128 {
1129  struct dirent *entry = reinterpret_cast<struct dirent *>(buffer);
1130 
1131  size_t filenameLength = file->getName().length();
1132  size_t reclen = offsetof(struct dirent, d_name) + filenameLength +
1133  1; // needs null terminator
1134  // do we have room for this record?
1135  if (avail < reclen)
1136  {
1137  // need to call again with more space available
1138  return 0;
1139  }
1140 
1141  entry->d_reclen = reclen;
1142  entry->d_off = next_pos;
1143 
1144  entry->d_ino = file->getInode();
1145  if (!entry->d_ino)
1146  {
1147  entry->d_ino = ~0U;
1148  }
1149 
1150  StringCopy(entry->d_name, static_cast<const char *>(file->getName()));
1151  entry->d_name[filenameLength] = 0;
1152 
1153  if (file->isSymlink() || file->isPipe())
1154  {
1155  entry->d_type = DT_LNK;
1156  }
1157  else if (file->isDirectory())
1158  {
1159  entry->d_type = DT_DIR;
1160  }
1161  else
1162  {
1164  entry->d_type = DT_REG;
1165  }
1166 
1167  return reclen;
1168 }
1169 
1170 int posix_getdents(int fd, struct linux_dirent *ents, int count)
1171 {
1172  F_NOTICE("getdents(" << fd << ")");
1174  reinterpret_cast<uintptr_t>(ents), count,
1175  PosixSubsystem::SafeWrite))
1176  {
1177  F_NOTICE("getdents -> invalid address");
1178  SYSCALL_ERROR(InvalidArgument);
1179  return -1;
1180  }
1181 
1182  return getdents_common(fd, getdents_helper, ents, count);
1183 }
1184 
1185 int posix_getdents64(int fd, struct dirent *ents, int count)
1186 {
1187  F_NOTICE("getdents64(" << fd << ")");
1189  reinterpret_cast<uintptr_t>(ents), count,
1190  PosixSubsystem::SafeWrite))
1191  {
1192  F_NOTICE("getdents64 -> invalid address");
1193  SYSCALL_ERROR(InvalidArgument);
1194  return -1;
1195  }
1196 
1197  return getdents_common(fd, getdents64_helper, ents, count);
1198 }
1199 
1200 int posix_ioctl(int fd, size_t command, void *buf)
1201 {
1202  F_NOTICE(
1203  "ioctl(" << Dec << fd << ", " << Hex << command << ", "
1204  << reinterpret_cast<uintptr_t>(buf) << ")");
1205 
1206  Process *pProcess =
1207  Processor::information().getCurrentThread()->getParent();
1208  PosixSubsystem *pSubsystem =
1209  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
1210  if (!pSubsystem)
1211  {
1212  ERROR("No subsystem for this process!");
1213  return -1;
1214  }
1215 
1216  FileDescriptor *f = pSubsystem->getFileDescriptor(fd);
1217  if (!f)
1218  {
1219  // Error - no such FD.
1220  F_NOTICE(" -> ioctl for a file that doesn't exist");
1221  SYSCALL_ERROR(BadFileDescriptor);
1222  return -1;
1223  }
1224 
1225  if (!f->file)
1226  {
1227  F_NOTICE(" -> fd " << fd << " is not supposed to be ioctl'd");
1228  SYSCALL_ERROR(InvalidArgument);
1229  return -1;
1230  }
1231 
1233 
1234  if (f->file->supports(command))
1235  {
1236  return f->file->command(command, buf);
1237  }
1238 
1239  switch (command)
1240  {
1241  // KDGETLED
1242  case 0x4B31:
1243  {
1244  F_NOTICE(" -> KDGETLED, arg=" << buf);
1245  char *cbuf = reinterpret_cast<char *>(buf);
1246  *cbuf = Machine::instance().getKeyboard()->getLedState();
1247  }
1248  return 0;
1249 
1250  // KDSETLED
1251  case 0x4B32:
1252  {
1253  F_NOTICE(" -> KDSETLED, arg=" << buf);
1254  uintptr_t leds = reinterpret_cast<uintptr_t>(buf);
1255  Machine::instance().getKeyboard()->setLedState(leds);
1256  }
1257  return 0;
1258 
1259  case 0x4B33: // KDGKBTYPE
1260  {
1261  F_NOTICE(" -> KDGKBTYPE");
1262  if (ConsoleManager::instance().isConsole(f->file))
1263  {
1264  // US 101
1265  *reinterpret_cast<int *>(buf) = 0x02;
1266  return 0;
1267  }
1268  else
1269  {
1270  SYSCALL_ERROR(NotAConsole);
1271  return -1;
1272  }
1273  }
1274 
1275  // KDSETMODE
1276  case 0x4b3a:
1278  F_NOTICE(" -> KDSETMODE (stubbed), arg=" << buf);
1279  if (buf == reinterpret_cast<void *>(1))
1280  {
1281  g_pDevFs->getTerminalManager().setSystemMode(
1282  VirtualTerminalManager::Graphics);
1283  }
1284  else
1285  {
1286  g_pDevFs->getTerminalManager().setSystemMode(
1287  VirtualTerminalManager::Text);
1288  }
1289  return 0;
1290 
1291  // KDGETMODE
1292  case 0x4b3b:
1293  {
1294  F_NOTICE(" -> KDGETMODE");
1295  switch (g_pDevFs->getTerminalManager().getSystemMode())
1296  {
1297  case VirtualTerminalManager::Graphics:
1298  *reinterpret_cast<int *>(buf) = 1;
1299  break;
1300  case VirtualTerminalManager::Text:
1301  *reinterpret_cast<int *>(buf) = 0;
1302  break;
1303  }
1304  }
1305  return 0;
1306 
1307  // KDGKBMODE
1308  case 0x4b44:
1309  F_NOTICE(" -> KDGKBMODE (stubbed), arg=" << buf);
1310  return 0;
1311 
1312  // KDSKBMODE
1313  case 0x4B45:
1314  {
1315  F_NOTICE(" -> KDSKBMODE, arg=" << buf);
1316 
1317  size_t consoleNumber = 0;
1318  if (ConsoleManager::instance().isConsole(f->file))
1319  {
1320  ConsoleFile *pConsole = static_cast<ConsoleFile *>(f->file);
1321  consoleNumber = pConsole->getPhysicalConsoleNumber();
1322  if (consoleNumber == ~0U)
1323  {
1324  ERROR("KDSKBMODE used on something that is not a VT");
1325  return -1;
1326  }
1327  }
1328  else
1329  {
1330  SYSCALL_ERROR(NotAConsole);
1331  return -1;
1332  }
1333 
1334  long mode = reinterpret_cast<long>(buf);
1335  if (mode == 0)
1336  {
1337  g_pDevFs->getTerminalManager().setInputMode(
1338  consoleNumber, TextIO::Raw);
1339  }
1340  else
1341  {
1342  g_pDevFs->getTerminalManager().setInputMode(
1343  consoleNumber, TextIO::Standard);
1344  }
1345  }
1346  return 0;
1347 
1348  // KDGKBENT
1349  case 0x4B46:
1350  {
1351  F_NOTICE(" -> KDGKBENT, arg=" << buf);
1352  POSIX_VERBOSE_LOG("io", " -> KDGKBENT, arg=" << buf);
1353 
1354  struct kbentry *kbent = reinterpret_cast<struct kbentry *>(buf);
1355  bool shift = kbent->kb_table & 0x1;
1356  bool altgr = kbent->kb_table & 0x2;
1357  bool ctrl = kbent->kb_table & 0x4;
1358  bool alt = kbent->kb_table & 0x8;
1359 
1360  // convert to HID so we can look in the keymap
1361  KeymapManager::EscapeState escape = KeymapManager::EscapeNone;
1362  uint8_t keyCode =
1364  kbent->kb_index, escape);
1367  ctrl, shift, alt, altgr, 0, keyCode);
1368  if (entry)
1369  {
1370  F_NOTICE(
1371  " -> no keymap entry for table #" << Dec << kbent->kb_table
1372  << " index #" << Hex
1373  << kbent->kb_index);
1374  kbent->kb_value =
1375  0xF000 | static_cast<uint16_t>(entry->value & 0xFFFF);
1376  }
1377  else
1378  {
1379  kbent->kb_value = 0;
1380  }
1381 
1382  POSIX_VERBOSE_LOG(
1383  "io", " -> val for table #" << Dec << kbent->kb_table << " #"
1384  << Hex << kbent->kb_index
1385  << " is now " << kbent->kb_value
1386  << "!");
1387  }
1388  return 0;
1389 
1390  // KDSKBENT
1391  case 0x4B47:
1392  F_NOTICE(" -> KDSKBENT (stubbed), arg=" << buf);
1393  POSIX_VERBOSE_LOG("io", " -> KDSKBENT (stubbed), arg=" << buf);
1394  return -1;
1395 
1396  // KDKBDREP
1397  case 0x4B52:
1398  F_NOTICE(" -> KDKBDREP (stubbed), arg=" << buf);
1399  return 0;
1400 
1401  case TCGETS:
1402  {
1403  if (ConsoleManager::instance().isConsole(f->file))
1404  {
1405  return posix_tcgetattr(
1406  fd, reinterpret_cast<struct termios *>(buf));
1407  }
1408  else
1409  {
1410  SYSCALL_ERROR(NotAConsole);
1411  return -1;
1412  }
1413  }
1414 
1415  case TCSETS:
1416  {
1417  if (ConsoleManager::instance().isConsole(f->file))
1418  {
1419  return posix_tcsetattr(
1420  fd, TCSANOW, reinterpret_cast<struct termios *>(buf));
1421  }
1422  else
1423  {
1424  SYSCALL_ERROR(NotAConsole);
1425  return -1;
1426  }
1427  }
1428 
1429  case TCSETSW:
1430  {
1431  if (ConsoleManager::instance().isConsole(f->file))
1432  {
1433  return posix_tcsetattr(
1434  fd, TCSADRAIN, reinterpret_cast<struct termios *>(buf));
1435  }
1436  else
1437  {
1438  SYSCALL_ERROR(NotAConsole);
1439  return -1;
1440  }
1441  }
1442 
1443  case TCSETSF:
1444  {
1445  if (ConsoleManager::instance().isConsole(f->file))
1446  {
1447  return posix_tcsetattr(
1448  fd, TCSAFLUSH, reinterpret_cast<struct termios *>(buf));
1449  }
1450  else
1451  {
1452  SYSCALL_ERROR(NotAConsole);
1453  return -1;
1454  }
1455  }
1456 
1457  case TIOCGPGRP:
1458  {
1459  if (ConsoleManager::instance().isConsole(f->file))
1460  {
1461  pid_t pgrp = posix_tcgetpgrp(fd);
1462  *reinterpret_cast<pid_t *>(buf) = pgrp;
1463  return 0;
1464  }
1465  else
1466  {
1467  SYSCALL_ERROR(NotAConsole);
1468  return -1;
1469  }
1470  }
1471 
1472  case TIOCSPGRP:
1473  {
1474  if (ConsoleManager::instance().isConsole(f->file))
1475  {
1476  return posix_tcsetpgrp(fd, *reinterpret_cast<pid_t *>(buf));
1477  }
1478  else
1479  {
1480  SYSCALL_ERROR(NotAConsole);
1481  return -1;
1482  }
1483  }
1484 
1485  case TCFLSH:
1486  {
1487  if (ConsoleManager::instance().isConsole(f->file))
1488  {
1489  return console_flush(f->file, 0);
1490  }
1491  else
1492  {
1493  SYSCALL_ERROR(NotAConsole);
1494  return -1;
1495  }
1496  }
1497 
1498  case TIOCGWINSZ:
1499  {
1500  if (ConsoleManager::instance().isConsole(f->file))
1501  {
1502  F_NOTICE(" -> TIOCGWINSZ");
1503  return console_getwinsize(
1504  f->file, reinterpret_cast<struct winsize *>(buf));
1505  }
1506  else
1507  {
1508  SYSCALL_ERROR(NotAConsole);
1509  return -1;
1510  }
1511  }
1512 
1513  case TIOCSWINSZ:
1514  {
1515  if (ConsoleManager::instance().isConsole(f->file))
1516  {
1517  const struct winsize *ws =
1518  reinterpret_cast<const struct winsize *>(buf);
1519  F_NOTICE(
1520  " -> TIOCSWINSZ " << Dec << ws->ws_col << "x" << ws->ws_row
1521  << Hex);
1522  return console_setwinsize(f->file, ws);
1523  }
1524  else
1525  {
1526  SYSCALL_ERROR(NotAConsole);
1527  return -1;
1528  }
1529  }
1530 
1531  case TIOCSCTTY:
1532  {
1533  if (ConsoleManager::instance().isConsole(f->file))
1534  {
1535  F_NOTICE(" -> TIOCSCTTY");
1536  return console_setctty(
1537  fd, reinterpret_cast<uintptr_t>(buf) == 1);
1538  }
1539  else
1540  {
1541  SYSCALL_ERROR(NotAConsole);
1542  return -1;
1543  }
1544  }
1545 
1546  case TIOCGPTN:
1547  {
1548  F_NOTICE(" -> TIOCGPTN");
1549  unsigned int *out = reinterpret_cast<unsigned int *>(buf);
1550  unsigned int result = console_getptn(fd);
1551  if (result < ~0U)
1552  {
1553  F_NOTICE(" -> ok, returning " << result);
1554  *out = result;
1555  return 0;
1556  }
1557  else
1558  {
1559  // console_getptn will set the syscall error
1560  F_NOTICE(" -> failed!");
1561  return -1;
1562  }
1563  }
1564 
1565  case FIONBIO:
1566  {
1567  F_NOTICE(" -> FIONBIO");
1568  // set/unset non-blocking
1569  if (buf)
1570  {
1571  int a = *reinterpret_cast<int *>(buf);
1572  if (a)
1573  {
1574  F_NOTICE(" -> set non-blocking");
1575  f->flflags |= O_NONBLOCK;
1576  }
1577  else
1578  {
1579  F_NOTICE(" -> set blocking");
1580  f->flflags &= ~O_NONBLOCK;
1581  }
1582  }
1583  else
1584  f->flflags &= ~O_NONBLOCK;
1585 
1586  return 0;
1587  }
1588 
1589  // VT_OPENQRY
1590  case 0x5600:
1591  {
1592  F_NOTICE(" -> VT_OPENQRY (stubbed)");
1593 
1594  int *ibuf = reinterpret_cast<int *>(buf);
1595 
1596  size_t newTty = g_pDevFs->getTerminalManager().openInactive();
1597  if (newTty != ~0U)
1598  {
1599  NOTICE("VT_OPENQRY => " << newTty);
1600  *ibuf = newTty + 1;
1601  }
1602  else
1603  {
1604  *ibuf = -1;
1605  }
1606 
1607  return 0;
1608  }
1609 
1610  // VT_GETMODE
1611  case 0x5601:
1612  {
1613  F_NOTICE(" -> VT_GETMODE (stubbed)");
1614 
1617  size_t currentTty =
1618  g_pDevFs->getTerminalManager().getCurrentTerminalNumber();
1619 
1620  struct vt_mode *mode = reinterpret_cast<struct vt_mode *>(buf);
1621  *mode = g_pDevFs->getTerminalManager().getTerminalMode(currentTty);
1622  }
1623  return 0;
1624 
1625  // VT_SETMODE
1626  case 0x5602:
1627  {
1628  F_NOTICE(" -> VT_SETMODE (stubbed)");
1629 
1630  const struct vt_mode *mode =
1631  reinterpret_cast<const struct vt_mode *>(buf);
1632 
1635  size_t currentTty =
1636  g_pDevFs->getTerminalManager().getCurrentTerminalNumber();
1637  g_pDevFs->getTerminalManager().setTerminalMode(currentTty, *mode);
1638  }
1639  return 0;
1640 
1641  // VT_GETSTATE
1642  case 0x5603:
1643  {
1644  F_NOTICE(" -> VT_GETSTATE (stubbed)");
1645 
1646  struct vt_stat *stat = reinterpret_cast<struct vt_stat *>(buf);
1647  *stat = g_pDevFs->getTerminalManager().getState();
1648  }
1649  return 0;
1650 
1651  // VT_RELDISP
1652  case 0x5605:
1653  {
1654  F_NOTICE(" -> VT_RELDISP (stubbed)");
1655 
1656  NOTICE("VT_RELDISP");
1657  uintptr_t ibuf = reinterpret_cast<uintptr_t>(buf);
1658  if (ibuf == 0)
1659  {
1660  NOTICE(" -> switch disallowed");
1661  g_pDevFs->getTerminalManager().reportPermission(
1662  VirtualTerminalManager::Disallowed);
1663  }
1664  else if (ibuf == 1)
1665  {
1666  NOTICE(" -> switch allowed");
1667  g_pDevFs->getTerminalManager().reportPermission(
1668  VirtualTerminalManager::Allowed);
1669  }
1670  else
1671  {
1672  NOTICE(" -> switch acknowledged");
1673  }
1674  }
1675  return 0;
1676 
1677  // VT_ACTIVATE
1678  case 0x5606:
1679  {
1680  uintptr_t ttyNum = reinterpret_cast<uintptr_t>(buf);
1681  F_NOTICE(" -> VT_ACTIVATE -> " << ttyNum);
1682  g_pDevFs->getTerminalManager().activate(ttyNum - 1);
1683  }
1684  return 0;
1685 
1686  // VT_WAITACTIVE
1687  case 0x5607:
1688  // no-op on Pedigree so far
1689  return 0;
1690  }
1691 
1692  F_NOTICE(
1693  " -> invalid combination of fd " << fd << " and ioctl " << Hex
1694  << command);
1695  SYSCALL_ERROR(InvalidArgument);
1696  return -1;
1697 }
1698 
1699 int posix_chdir(const char *path)
1700 {
1701  F_NOTICE("chdir");
1702 
1704  reinterpret_cast<uintptr_t>(path), PATH_MAX,
1705  PosixSubsystem::SafeRead))
1706  {
1707  F_NOTICE("chdir -> invalid address");
1708  SYSCALL_ERROR(InvalidArgument);
1709  return -1;
1710  }
1711 
1712  F_NOTICE("chdir(" << path << ")");
1713 
1714  String realPath;
1715  normalisePath(realPath, path);
1716 
1717  File *dir = findFileWithAbiFallbacks(realPath, GET_CWD());
1718  if (!dir)
1719  {
1720  F_NOTICE("Does not exist.");
1721  SYSCALL_ERROR(DoesNotExist);
1722  return -1;
1723  }
1724 
1725  return doChdir(dir) ? 0 : -1;
1726 }
1727 
1728 int posix_dup(int fd)
1729 {
1730  F_NOTICE("dup(" << fd << ")");
1731 
1732  // grab the file descriptor pointer for the passed descriptor
1733  Process *pProcess =
1734  Processor::information().getCurrentThread()->getParent();
1735  PosixSubsystem *pSubsystem =
1736  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
1737  if (!pSubsystem)
1738  {
1739  ERROR("No subsystem for this process!");
1740  return -1;
1741  }
1742 
1743  FileDescriptor *f = pSubsystem->getFileDescriptor(fd);
1744  if (!f)
1745  {
1746  SYSCALL_ERROR(BadFileDescriptor);
1747  return -1;
1748  }
1749 
1750  size_t newFd = pSubsystem->getFd();
1751 
1752  // Copy the descriptor
1753  FileDescriptor *f2 = new FileDescriptor(*f);
1754  pSubsystem->addFileDescriptor(newFd, f2);
1755 
1756  return static_cast<int>(newFd);
1757 }
1758 
1759 int posix_dup2(int fd1, int fd2)
1760 {
1761  F_NOTICE("dup2(" << fd1 << ", " << fd2 << ")");
1762 
1763  if (fd2 < 0)
1764  {
1765  SYSCALL_ERROR(BadFileDescriptor);
1766  return -1; // EBADF
1767  }
1768 
1769  if (fd1 == fd2)
1770  return fd2;
1771 
1772  // grab the file descriptor pointer for the passed descriptor
1773  Process *pProcess =
1774  Processor::information().getCurrentThread()->getParent();
1775  PosixSubsystem *pSubsystem =
1776  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
1777  if (!pSubsystem)
1778  {
1779  ERROR("No subsystem for this process!");
1780  return -1;
1781  }
1782 
1783  FileDescriptor *f = pSubsystem->getFileDescriptor(fd1);
1784  if (!f)
1785  {
1786  SYSCALL_ERROR(BadFileDescriptor);
1787  return -1;
1788  }
1789 
1790  // Copy the descriptor.
1791  //
1792  // This will also increase the refcount *before* we close the original, else
1793  // we might accidentally trigger an EOF condition on a pipe! (if the write
1794  // refcount drops to zero)...
1795  FileDescriptor *f2 = new FileDescriptor(*f);
1796  pSubsystem->addFileDescriptor(fd2, f2);
1797 
1798  // According to the spec, CLOEXEC is cleared on DUP.
1799  f2->fdflags &= ~FD_CLOEXEC;
1800 
1801  return fd2;
1802 }
1803 
1804 int posix_mkdir(const char *name, int mode)
1805 {
1806  return posix_mkdirat(AT_FDCWD, name, mode);
1807 }
1808 
1809 int posix_rmdir(const char *path)
1810 {
1811  return posix_unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
1812 }
1813 
1814 int posix_isatty(int fd)
1815 {
1816  // Lookup this process.
1817  Process *pProcess =
1818  Processor::information().getCurrentThread()->getParent();
1819  PosixSubsystem *pSubsystem =
1820  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
1821  if (!pSubsystem)
1822  {
1823  ERROR("No subsystem for this process!");
1824  return -1;
1825  }
1826 
1827  FileDescriptor *pFd = pSubsystem->getFileDescriptor(fd);
1828  if (!pFd)
1829  {
1830  // Error - no such file descriptor.
1831  ERROR("isatty: no such file descriptor (" << Dec << fd << Hex << ")");
1832  return 0;
1833  }
1834 
1835  int result = ConsoleManager::instance().isConsole(pFd->file) ? 1 : 0;
1836  NOTICE("isatty(" << fd << ") -> " << result);
1837  return result;
1838 }
1839 
1840 int posix_fcntl(int fd, int cmd, void *arg)
1841 {
1843  F_NOTICE("fcntl(" << fd << ", " << cmd << ", " << arg << ")");
1844 
1845  // grab the file descriptor pointer for the passed descriptor
1846  Thread *pThread = Processor::information().getCurrentThread();
1847  Process *pProcess = pThread->getParent();
1848  PosixSubsystem *pSubsystem =
1849  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
1850  if (!pSubsystem)
1851  {
1852  ERROR("No subsystem for this process!");
1853  return -1;
1854  }
1855 
1856  FileDescriptor *f = pSubsystem->getFileDescriptor(fd);
1857  if (!f)
1858  {
1859  SYSCALL_ERROR(BadFileDescriptor);
1860  return -1;
1861  }
1862 
1863  switch (cmd)
1864  {
1865  case F_DUPFD:
1866 
1867  if (arg)
1868  {
1869  size_t fd2 = reinterpret_cast<size_t>(arg);
1870 
1871  // Copy the descriptor (addFileDescriptor automatically frees
1872  // the old one, if needed)
1873  FileDescriptor *f2 = new FileDescriptor(*f);
1874  pSubsystem->addFileDescriptor(fd2, f2);
1875 
1876  // According to the spec, CLOEXEC is cleared on DUP.
1877  f2->fdflags &= ~FD_CLOEXEC;
1878 
1879  return static_cast<int>(fd2);
1880  }
1881  else
1882  {
1883  size_t fd2 = pSubsystem->getFd();
1884 
1885  // copy the descriptor
1886  FileDescriptor *f2 = new FileDescriptor(*f);
1887  pSubsystem->addFileDescriptor(fd2, f2);
1888 
1889  // According to the spec, CLOEXEC is cleared on DUP.
1890  f2->fdflags &= ~FD_CLOEXEC;
1891 
1892  return static_cast<int>(fd2);
1893  }
1894 
1895  case F_GETFD:
1896  F_NOTICE(" -> get fd flags");
1897  return f->fdflags;
1898  case F_SETFD:
1899  F_NOTICE(" -> set fd flags: " << arg);
1900  f->fdflags = reinterpret_cast<size_t>(arg);
1901  return 0;
1902  case F_GETFL:
1903  F_NOTICE(" -> get flags " << f->flflags);
1904  return f->flflags;
1905  case F_SETFL:
1906  F_NOTICE(" -> set flags " << arg);
1907  f->flflags = reinterpret_cast<size_t>(arg) &
1908  (O_APPEND | O_NONBLOCK | O_CLOEXEC);
1909  F_NOTICE(" -> new flags " << f->flflags);
1910  return 0;
1911  case F_GETLK: // Get record-locking information
1912  case F_SETLK: // Set or clear a record lock (without blocking
1913  case F_SETLKW: // Set or clear a record lock (with blocking)
1914  F_NOTICE(" -> fcntl locks (stubbed)");
1916  return 0;
1917  case F_GETOWN:
1918  F_NOTICE(" -> F_GETOWN (stubbed)");
1919  return 0;
1920  case F_SETOWN:
1922  F_NOTICE(" -> F_SETOWN");
1923 
1924  if (!f->ioevent)
1925  {
1926  if (f->file)
1927  {
1928  NOTICE("Adding ioevent to thread");
1929  f->ioevent = new IoEvent(pSubsystem, f->file);
1930  f->file->monitor(pThread, f->ioevent);
1931  }
1932  else
1933  {
1935  ERROR(
1936  "F_SETOWN on something that can't raise events [fd="
1937  << fd << " file=" << f->file
1938  << " impl=" << f->networkImpl.get() << "!");
1939  return -1;
1940  }
1941  }
1942  return 0;
1943 
1944  default:
1945  WARNING("fcntl: unknown control " << cmd << " on fd " << fd);
1946  }
1947 
1948  SYSCALL_ERROR(Unimplemented);
1949  return -1;
1950 }
1951 
1952 void *posix_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off)
1953 {
1954  F_NOTICE("mmap");
1955  F_NOTICE(
1956  " -> addr=" << addr << ", len=" << len << ", prot=" << prot
1957  << ", flags=" << flags << ", fildes=" << fd
1958  << ", off=" << off << ".");
1959 
1960  // Get the File object to map
1961  Process *pProcess =
1962  Processor::information().getCurrentThread()->getParent();
1963  PosixSubsystem *pSubsystem =
1964  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
1965  if (!pSubsystem)
1966  {
1967  ERROR("No subsystem for this process!");
1968  return MAP_FAILED;
1969  }
1970 
1971  // The return address
1972  void *finalAddress = 0;
1973 
1974  VirtualAddressSpace &va = Processor::information().getVirtualAddressSpace();
1975  size_t pageSz = PhysicalMemoryManager::getPageSize();
1976 
1977  // Sanitise input.
1978  uintptr_t sanityAddress = reinterpret_cast<uintptr_t>(addr);
1979  if (sanityAddress)
1980  {
1981  if ((sanityAddress < va.getUserStart()) ||
1982  (sanityAddress >= va.getKernelStart()))
1983  {
1984  if (flags & MAP_FIXED)
1985  {
1986  // Invalid input and MAP_FIXED, this is an error.
1987  SYSCALL_ERROR(InvalidArgument);
1988  F_NOTICE(" -> mmap given invalid fixed address");
1989  return MAP_FAILED;
1990  }
1991  else
1992  {
1993  // Invalid input - but not MAP_FIXED, so we can ignore addr.
1994  sanityAddress = 0;
1995  }
1996  }
1997  }
1998 
1999  // Verify the passed length
2000  if (!len || (sanityAddress & (pageSz - 1)))
2001  {
2002  SYSCALL_ERROR(InvalidArgument);
2003  return MAP_FAILED;
2004  }
2005 
2006  // Create permission set.
2008  if (prot & PROT_NONE)
2009  {
2010  perms = MemoryMappedObject::None;
2011  }
2012  else
2013  {
2014  // Everything implies a readable memory region.
2015  perms = MemoryMappedObject::Read;
2016  if (prot & PROT_WRITE)
2017  perms |= MemoryMappedObject::Write;
2018  if (prot & PROT_EXEC)
2019  perms |= MemoryMappedObject::Exec;
2020  }
2021 
2022  if (flags & MAP_ANON)
2023  {
2024  if (flags & MAP_SHARED)
2025  {
2026  F_NOTICE(
2027  " -> failed (MAP_SHARED cannot be used with MAP_ANONYMOUS)");
2028  SYSCALL_ERROR(InvalidArgument);
2029  return MAP_FAILED;
2030  }
2031 
2032  MemoryMappedObject *pObject =
2033  MemoryMapManager::instance().mapAnon(sanityAddress, len, perms);
2034  if (!pObject)
2035  {
2037  SYSCALL_ERROR(OutOfMemory);
2038  F_NOTICE(" -> failed (mapAnon)!");
2039  return MAP_FAILED;
2040  }
2041 
2042  F_NOTICE(" -> " << sanityAddress);
2043 
2044  finalAddress = reinterpret_cast<void *>(sanityAddress);
2045  }
2046  else
2047  {
2048  // Valid file passed?
2049  FileDescriptor *f = pSubsystem->getFileDescriptor(fd);
2050  if (!f)
2051  {
2052  SYSCALL_ERROR(BadFileDescriptor);
2053  return MAP_FAILED;
2054  }
2055 
2058 
2059  // Grab the file to map in
2060  File *fileToMap = f->file;
2061 
2062  // Check general file permissions, open file mode aside.
2063  // Note: PROT_WRITE is OK for private mappings, as the backing file
2064  // doesn't get updated for those maps.
2065  if (!VFS::checkAccess(
2066  fileToMap, prot & PROT_READ,
2067  (prot & PROT_WRITE) && (flags & MAP_SHARED), prot & PROT_EXEC))
2068  {
2069  F_NOTICE(
2070  " -> mmap on " << fileToMap->getFullPath()
2071  << " failed due to permissions.");
2072  return MAP_FAILED;
2073  }
2074 
2075  F_NOTICE("mmap: file name is " << fileToMap->getFullPath());
2076 
2077  // Grab the MemoryMappedFile for it. This will automagically handle
2078  // MAP_FIXED mappings too
2079  bool bCopyOnWrite = (flags & MAP_SHARED) == 0;
2081  fileToMap, sanityAddress, len, perms, off, bCopyOnWrite);
2082  if (!pFile)
2083  {
2085  SYSCALL_ERROR(OutOfMemory);
2086  F_NOTICE(" -> failed (mapFile)!");
2087  return MAP_FAILED;
2088  }
2089 
2090  F_NOTICE(" -> " << sanityAddress);
2091 
2092  finalAddress = reinterpret_cast<void *>(sanityAddress);
2093  }
2094 
2095  // Complete
2096  return finalAddress;
2097 }
2098 
2099 int posix_msync(void *p, size_t len, int flags)
2100 {
2101  F_NOTICE("msync");
2102  F_NOTICE(
2103  " -> addr=" << p << ", len=" << len << ", flags=" << Hex << flags);
2104 
2105  uintptr_t addr = reinterpret_cast<uintptr_t>(p);
2106  size_t pageSz = PhysicalMemoryManager::getPageSize();
2107 
2108  // Verify the passed length
2109  if (!len || (addr & (pageSz - 1)))
2110  {
2111  SYSCALL_ERROR(InvalidArgument);
2112  return -1;
2113  }
2114 
2115  if ((flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC)) != 0)
2116  {
2117  SYSCALL_ERROR(InvalidArgument);
2118  return -1;
2119  }
2120 
2121  // Make sure there's at least one object we'll touch.
2122  if (!MemoryMapManager::instance().contains(addr, len))
2123  {
2124  SYSCALL_ERROR(OutOfMemory);
2125  return -1;
2126  }
2127 
2128  if (flags & MS_INVALIDATE)
2129  {
2131  }
2132  else
2133  {
2134  MemoryMapManager::instance().sync(addr, len, flags & MS_ASYNC);
2135  }
2136 
2137  return 0;
2138 }
2139 
2140 int posix_mprotect(void *p, size_t len, int prot)
2141 {
2142  F_NOTICE("mprotect");
2143  F_NOTICE(" -> addr=" << p << ", len=" << len << ", prot=" << Hex << prot);
2144 
2145  uintptr_t addr = reinterpret_cast<uintptr_t>(p);
2146  size_t pageSz = PhysicalMemoryManager::getPageSize();
2147 
2148  // Verify the passed length
2149  if (!len || (addr & (pageSz - 1)))
2150  {
2151  SYSCALL_ERROR(InvalidArgument);
2152  return -1;
2153  }
2154 
2155  // Make sure there's at least one object we'll touch.
2156  if (!MemoryMapManager::instance().contains(addr, len))
2157  {
2158  SYSCALL_ERROR(OutOfMemory);
2159  return -1;
2160  }
2161 
2162  // Create permission set.
2164  if (prot & PROT_NONE)
2165  {
2166  perms = MemoryMappedObject::None;
2167  }
2168  else
2169  {
2170  // Everything implies a readable memory region.
2171  perms = MemoryMappedObject::Read;
2172  if (prot & PROT_WRITE)
2173  perms |= MemoryMappedObject::Write;
2174  if (prot & PROT_EXEC)
2175  perms |= MemoryMappedObject::Exec;
2176  }
2177 
2180 
2181  MemoryMapManager::instance().setPermissions(addr, len, perms);
2182 
2183  return 0;
2184 }
2185 
2186 int posix_munmap(void *addr, size_t len)
2187 {
2188  F_NOTICE(
2189  "munmap(" << reinterpret_cast<uintptr_t>(addr) << ", " << len << ")");
2190 
2191  if (!len)
2192  {
2193  SYSCALL_ERROR(InvalidArgument);
2194  return -1;
2195  }
2196 
2197  MemoryMapManager::instance().remove(reinterpret_cast<uintptr_t>(addr), len);
2198 
2199  return 0;
2200 }
2201 
2202 int posix_access(const char *name, int amode)
2203 {
2204  return posix_faccessat(AT_FDCWD, name, amode, 0);
2205 }
2206 
2207 int posix_ftruncate(int a, off_t b)
2208 {
2209  F_NOTICE("ftruncate(" << a << ", " << b << ")");
2210 
2211  // Grab the File pointer for this file
2212  Process *pProcess =
2213  Processor::information().getCurrentThread()->getParent();
2214  PosixSubsystem *pSubsystem =
2215  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
2216  if (!pSubsystem)
2217  {
2218  ERROR("No subsystem for this process!");
2219  return -1;
2220  }
2221 
2222  FileDescriptor *pFd = pSubsystem->getFileDescriptor(a);
2223  if (!pFd)
2224  {
2225  // Error - no such file descriptor.
2226  SYSCALL_ERROR(BadFileDescriptor);
2227  return -1;
2228  }
2229  File *pFile = pFd->file;
2230 
2231  // If we are to simply truncate, do so
2232  if (b == 0)
2233  {
2234  pFile->truncate();
2235  return 0;
2236  }
2237  else if (static_cast<size_t>(b) == pFile->getSize())
2238  return 0;
2239  // If we need to reduce the file size, do so
2240  else if (static_cast<size_t>(b) < pFile->getSize())
2241  {
2242  pFile->setSize(b);
2243  return 0;
2244  }
2245  // Otherwise, extend the file
2246  else
2247  {
2248  size_t currSize = pFile->getSize();
2249  size_t numExtraBytes = b - currSize;
2250  NOTICE("Extending by " << numExtraBytes << " bytes");
2251  uint8_t *nullBuffer = new uint8_t[numExtraBytes];
2252  NOTICE("Got the buffer");
2253  ByteSet(nullBuffer, 0, numExtraBytes);
2254  NOTICE("Zeroed the buffer");
2255  pFile->write(
2256  currSize, numExtraBytes, reinterpret_cast<uintptr_t>(nullBuffer));
2257  NOTICE("Deleting the buffer");
2258  delete[] nullBuffer;
2259  NOTICE("Complete");
2260  return 0;
2261  }
2262 }
2263 
2264 int posix_fsync(int fd)
2265 {
2266  F_NOTICE("fsync(" << fd << ")");
2267 
2268  // Grab the File pointer for this file
2269  Process *pProcess =
2270  Processor::information().getCurrentThread()->getParent();
2271  PosixSubsystem *pSubsystem =
2272  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
2273  if (!pSubsystem)
2274  {
2275  ERROR("No subsystem for this process!");
2276  return -1;
2277  }
2278 
2279  FileDescriptor *pFd = pSubsystem->getFileDescriptor(fd);
2280  if (!pFd)
2281  {
2282  // Error - no such file descriptor.
2283  SYSCALL_ERROR(BadFileDescriptor);
2284  return -1;
2285  }
2286  File *pFile = pFd->file;
2287  pFile->sync();
2288 
2289  return 0;
2290 }
2291 
2292 EXPORTED_PUBLIC int
2293 pedigree_get_mount(char *mount_buf, char *info_buf, size_t n)
2294 {
2296  reinterpret_cast<uintptr_t>(mount_buf), PATH_MAX,
2297  PosixSubsystem::SafeWrite) &&
2299  reinterpret_cast<uintptr_t>(info_buf), PATH_MAX,
2300  PosixSubsystem::SafeWrite)))
2301  {
2302  F_NOTICE("pedigree_get_mount -> invalid address");
2303  SYSCALL_ERROR(InvalidArgument);
2304  return -1;
2305  }
2306 
2307  NOTICE("pedigree_get_mount(" << Dec << n << Hex << ")");
2308 
2309  typedef List<String *> StringList;
2310  typedef Tree<Filesystem *, List<String *> *> VFSMountTree;
2311  VFSMountTree &mounts = VFS::instance().getMounts();
2312 
2313  size_t i = 0;
2314  for (VFSMountTree::Iterator it = mounts.begin(); it != mounts.end(); it++)
2315  {
2316  Filesystem *pFs = it.key();
2317  StringList *pList = it.value();
2318  Disk *pDisk = pFs->getDisk();
2319 
2320  for (StringList::Iterator it2 = pList->begin(); it2 != pList->end();
2321  it2++, i++)
2322  {
2323  String mount = **it2;
2324 
2325  if (i == n)
2326  {
2327  String info, s;
2328  if (pDisk)
2329  {
2330  pDisk->getName(s);
2331  pDisk->getParent()->getName(info);
2332  info += " // ";
2333  info += s;
2334  }
2335  else
2336  info = "no disk";
2337 
2338  StringCopy(mount_buf, static_cast<const char *>(mount));
2339  StringCopy(info_buf, static_cast<const char *>(info));
2340 
2341  return 0;
2342  }
2343  }
2344  }
2345 
2346  return -1;
2347 }
2348 
2349 int posix_chmod(const char *path, mode_t mode)
2350 {
2351  return posix_fchmodat(AT_FDCWD, path, mode, 0);
2352 }
2353 
2354 int posix_chown(const char *path, uid_t owner, gid_t group)
2355 {
2356  return posix_fchownat(AT_FDCWD, path, owner, group, 0);
2357 }
2358 
2359 int posix_fchmod(int fd, mode_t mode)
2360 {
2361  return posix_fchmodat(fd, nullptr, mode, AT_EMPTY_PATH);
2362 }
2363 
2364 int posix_fchown(int fd, uid_t owner, gid_t group)
2365 {
2366  return posix_fchownat(fd, nullptr, owner, group, AT_EMPTY_PATH);
2367 }
2368 
2369 int posix_fchdir(int fd)
2370 {
2371  F_NOTICE("fchdir(" << fd << ")");
2372 
2373  // Lookup this process.
2374  Process *pProcess =
2375  Processor::information().getCurrentThread()->getParent();
2376  PosixSubsystem *pSubsystem =
2377  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
2378  if (!pSubsystem)
2379  {
2380  ERROR("No subsystem for this process!");
2381  return -1;
2382  }
2383 
2384  FileDescriptor *pFd = pSubsystem->getFileDescriptor(fd);
2385  if (!pFd)
2386  {
2387  // Error - no such file descriptor.
2388  SYSCALL_ERROR(BadFileDescriptor);
2389  return -1;
2390  }
2391 
2392  File *file = pFd->file;
2393  return doChdir(file) ? 0 : -1;
2394 }
2395 
2396 static int statvfs_doer(Filesystem *pFs, struct statvfs *buf)
2397 {
2398  if (!pFs)
2399  {
2400  SYSCALL_ERROR(DoesNotExist);
2401  return -1;
2402  }
2403 
2405  buf->f_bsize = 4096;
2406  buf->f_frsize = 512;
2407  buf->f_blocks = static_cast<fsblkcnt_t>(-1);
2408  buf->f_bfree = static_cast<fsblkcnt_t>(-1);
2409  buf->f_bavail = static_cast<fsblkcnt_t>(-1);
2410  buf->f_files = 0;
2411  buf->f_ffree = static_cast<fsfilcnt_t>(-1);
2412  buf->f_favail = static_cast<fsfilcnt_t>(-1);
2413  buf->f_fsid = 0;
2414  buf->f_flag = (pFs->isReadOnly() ? ST_RDONLY : 0) |
2415  ST_NOSUID; // No suid in pedigree yet.
2416  buf->f_namemax = 0;
2417 
2418  return 0;
2419 }
2420 
2421 int posix_fstatvfs(int fd, struct statvfs *buf)
2422 {
2424  reinterpret_cast<uintptr_t>(buf), sizeof(struct statvfs),
2425  PosixSubsystem::SafeWrite))
2426  {
2427  F_NOTICE("fstatvfs -> invalid address");
2428  SYSCALL_ERROR(InvalidArgument);
2429  return -1;
2430  }
2431 
2432  F_NOTICE("fstatvfs(" << fd << ")");
2433 
2434  // Lookup this process.
2435  Process *pProcess =
2436  Processor::information().getCurrentThread()->getParent();
2437  PosixSubsystem *pSubsystem =
2438  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
2439  if (!pSubsystem)
2440  {
2441  ERROR("No subsystem for this process!");
2442  return -1;
2443  }
2444 
2445  FileDescriptor *pFd = pSubsystem->getFileDescriptor(fd);
2446  if (!pFd)
2447  {
2448  // Error - no such file descriptor.
2449  SYSCALL_ERROR(BadFileDescriptor);
2450  return -1;
2451  }
2452 
2453  File *file = pFd->file;
2454 
2455  return statvfs_doer(file->getFilesystem(), buf);
2456 }
2457 
2458 int posix_statvfs(const char *path, struct statvfs *buf)
2459 {
2461  reinterpret_cast<uintptr_t>(path), PATH_MAX,
2462  PosixSubsystem::SafeRead) &&
2464  reinterpret_cast<uintptr_t>(buf), sizeof(struct statvfs),
2465  PosixSubsystem::SafeWrite)))
2466  {
2467  F_NOTICE("statvfs -> invalid address");
2468  SYSCALL_ERROR(InvalidArgument);
2469  return -1;
2470  }
2471 
2472  F_NOTICE("statvfs(" << path << ")");
2473 
2474  String realPath;
2475  normalisePath(realPath, path);
2476 
2477  File *file = findFileWithAbiFallbacks(realPath, GET_CWD());
2478  if (!file)
2479  {
2480  SYSCALL_ERROR(DoesNotExist);
2481  return -1;
2482  }
2483 
2484  // Symlink traversal
2485  file = traverseSymlink(file);
2486  if (!file)
2487  return -1;
2488 
2489  return statvfs_doer(file->getFilesystem(), buf);
2490 }
2491 
2492 int posix_utime(const char *path, const struct utimbuf *times)
2493 {
2495  reinterpret_cast<uintptr_t>(path), PATH_MAX,
2496  PosixSubsystem::SafeRead) &&
2497  ((!times) || PosixSubsystem::checkAddress(
2498  reinterpret_cast<uintptr_t>(times),
2499  sizeof(struct utimbuf), PosixSubsystem::SafeRead))))
2500  {
2501  F_NOTICE("utimes -> invalid address");
2502  SYSCALL_ERROR(InvalidArgument);
2503  return -1;
2504  }
2505 
2506  F_NOTICE("utime(" << path << ")");
2507 
2508  String realPath;
2509  normalisePath(realPath, path);
2510 
2511  File *file = findFileWithAbiFallbacks(realPath, GET_CWD());
2512  if (!file)
2513  {
2514  SYSCALL_ERROR(DoesNotExist);
2515  return -1;
2516  }
2517 
2518  // Symlink traversal
2519  file = traverseSymlink(file);
2520  if (!file)
2521  return -1;
2522 
2523  if (!VFS::checkAccess(file, false, true, false))
2524  {
2525  // checkAccess does a SYSCALL_ERROR for us.
2526  return -1;
2527  }
2528 
2529  Time::Timestamp accessTime;
2530  Time::Timestamp modifyTime;
2531  if (times)
2532  {
2533  accessTime = times->actime * Time::Multiplier::Second;
2534  modifyTime = times->modtime * Time::Multiplier::Second;
2535  }
2536  else
2537  {
2538  accessTime = modifyTime = Time::getTime();
2539  }
2540 
2541  file->setAccessedTime(accessTime);
2542  file->setModifiedTime(modifyTime);
2543 
2544  return 0;
2545 }
2546 
2547 int posix_utimes(const char *path, const struct timeval *times)
2548 {
2549  return posix_futimesat(AT_FDCWD, path, times);
2550 }
2551 
2552 int posix_chroot(const char *path)
2553 {
2555  reinterpret_cast<uintptr_t>(path), PATH_MAX,
2556  PosixSubsystem::SafeRead))
2557  {
2558  F_NOTICE("chroot -> invalid address");
2559  SYSCALL_ERROR(InvalidArgument);
2560  return -1;
2561  }
2562 
2563  F_NOTICE("chroot(" << path << ")");
2564 
2565  String realPath;
2566  normalisePath(realPath, path);
2567 
2568  File *file = findFileWithAbiFallbacks(realPath, GET_CWD());
2569  if (!file)
2570  {
2571  SYSCALL_ERROR(DoesNotExist);
2572  return -1;
2573  }
2574 
2575  // Symlink traversal
2576  file = traverseSymlink(file);
2577  if (!file)
2578  return -1;
2579 
2580  // chroot must be a directory.
2581  if (!file->isDirectory())
2582  {
2583  SYSCALL_ERROR(NotADirectory);
2584  return -1;
2585  }
2586 
2587  Process *pProcess =
2588  Processor::information().getCurrentThread()->getParent();
2589  pProcess->setRootFile(file);
2590 
2591  return 0;
2592 }
2593 
2594 int posix_flock(int fd, int operation)
2595 {
2596  F_NOTICE("flock(" << fd << ", " << operation << ")");
2597  F_NOTICE(" -> flock is a no-op stub");
2598  return 0;
2599 }
2600 
2601 static File *check_dirfd(int dirfd, int flags = 0)
2602 {
2603  // Lookup this process.
2604  Process *pProcess =
2605  Processor::information().getCurrentThread()->getParent();
2606  PosixSubsystem *pSubsystem =
2607  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
2608  if (!pSubsystem)
2609  {
2610  F_NOTICE(" -> No subsystem for this process!");
2611  return 0;
2612  }
2613 
2614  File *cwd = GET_CWD();
2615  if (dirfd != AT_FDCWD)
2616  {
2617  FileDescriptor *pFd = pSubsystem->getFileDescriptor(dirfd);
2618  if (!pFd)
2619  {
2620  F_NOTICE(" -> dirfd is a bad fd");
2621  SYSCALL_ERROR(BadFileDescriptor);
2622  return 0;
2623  }
2624 
2625  File *file = pFd->file;
2626  if ((flags & AT_EMPTY_PATH) == 0)
2627  {
2628  if (!file->isDirectory())
2629  {
2630  F_NOTICE(" -> dirfd is not a directory");
2631  SYSCALL_ERROR(NotADirectory);
2632  return 0;
2633  }
2634  }
2635 
2636  cwd = file;
2637  }
2638 
2639  return cwd;
2640 }
2641 
2642 int posix_openat(int dirfd, const char *pathname, int flags, mode_t mode)
2643 {
2644  F_NOTICE("openat");
2645 
2646  File *cwd = check_dirfd(dirfd);
2647  if (!cwd)
2648  {
2649  return -1;
2650  }
2651 
2653  reinterpret_cast<uintptr_t>(pathname), PATH_MAX,
2654  PosixSubsystem::SafeRead))
2655  {
2656  F_NOTICE("open -> invalid address");
2657  SYSCALL_ERROR(InvalidArgument);
2658  return -1;
2659  }
2660 
2661  F_NOTICE(
2662  "openat(" << dirfd << ", " << pathname << ", " << flags << ", " << Oct
2663  << mode << ")");
2664 
2665  // Lookup this process.
2666  Process *pProcess =
2667  Processor::information().getCurrentThread()->getParent();
2668  PosixSubsystem *pSubsystem =
2669  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
2670  if (!pSubsystem)
2671  {
2672  F_NOTICE(" -> No subsystem for this process!");
2673  return -1;
2674  }
2675 
2676  // One of these three must be specified.
2677  if (!(CHECK_FLAG(flags, O_RDONLY) || CHECK_FLAG(flags, O_RDWR) ||
2678  CHECK_FLAG(flags, O_WRONLY)))
2679  {
2680  F_NOTICE("One of O_RDONLY, O_WRONLY, or O_RDWR must be passed.");
2681  SYSCALL_ERROR(InvalidArgument);
2682  return -1;
2683  }
2684 
2685  // verify the filename - don't try to open a dud file
2686  if (pathname[0] == 0)
2687  {
2688  F_NOTICE(" -> File does not exist (null path).");
2689  SYSCALL_ERROR(DoesNotExist);
2690  return -1;
2691  }
2692 
2693  PosixProcess *pPosixProcess = getPosixProcess();
2694  if (pPosixProcess)
2695  {
2696  mode &= ~pPosixProcess->getMask();
2697  }
2698 
2699  size_t fd = pSubsystem->getFd();
2700 
2701  File *file = 0;
2702 
2703  bool onDevFs = false;
2704  bool openingCtty = false;
2705  String nameToOpen;
2706  normalisePath(nameToOpen, pathname, &onDevFs);
2707  if (nameToOpen == "/dev/tty")
2708  {
2709  openingCtty = true;
2710 
2711  file = pProcess->getCtty();
2712  if (!file)
2713  {
2714  F_NOTICE(" -> returning -1, no controlling tty");
2715  return -1;
2716  }
2717  else if (ConsoleManager::instance().isMasterConsole(file))
2718  {
2719  // If we happened to somehow open a master console, get its slave.
2720  F_NOTICE(" -> controlling terminal was not a slave");
2721  file = ConsoleManager::instance().getOther(file);
2722  }
2723  }
2724 
2725  F_NOTICE(" -> actual filename to open is '" << nameToOpen << "'");
2726 
2727  if (!file)
2728  {
2729  // Find file.
2730  file = findFileWithAbiFallbacks(nameToOpen, cwd);
2731  }
2732 
2733  bool bCreated = false;
2734  if (!file)
2735  {
2736  if ((flags & O_CREAT) && !onDevFs)
2737  {
2738  F_NOTICE(" {O_CREAT}");
2739  bool worked = VFS::instance().createFile(nameToOpen, mode, cwd);
2740  if (!worked)
2741  {
2742  // createFile should set the error if it fails.
2743  F_NOTICE(" -> File does not exist (createFile failed)");
2744  pSubsystem->freeFd(fd);
2745  return -1;
2746  }
2747 
2748  file = findFileWithAbiFallbacks(nameToOpen, cwd);
2749  if (!file)
2750  {
2751  F_NOTICE(" -> File does not exist (O_CREAT failed)");
2752  SYSCALL_ERROR(DoesNotExist);
2753  pSubsystem->freeFd(fd);
2754  return -1;
2755  }
2756 
2757  bCreated = true;
2758  }
2759  else
2760  {
2761  F_NOTICE(" -> Does not exist.");
2762  // Error - not found.
2763  SYSCALL_ERROR(DoesNotExist);
2764  pSubsystem->freeFd(fd);
2765  return -1;
2766  }
2767  }
2768 
2769  if (!file)
2770  {
2771  F_NOTICE(" -> File does not exist.");
2772  SYSCALL_ERROR(DoesNotExist);
2773  pSubsystem->freeFd(fd);
2774  return -1;
2775  }
2776 
2777  file = traverseSymlink(file);
2778 
2779  if (!file)
2780  {
2781  SYSCALL_ERROR(DoesNotExist);
2782  pSubsystem->freeFd(fd);
2783  return -1;
2784  }
2785 
2786  if (file->isDirectory() && (flags & (O_WRONLY | O_RDWR)))
2787  {
2788  // Error - is directory.
2789  F_NOTICE(" -> Is a directory, and O_WRONLY or O_RDWR was specified.");
2790  SYSCALL_ERROR(IsADirectory);
2791  pSubsystem->freeFd(fd);
2792  return -1;
2793  }
2794 
2795  if ((flags & O_CREAT) && (flags & O_EXCL) && !bCreated)
2796  {
2797  // file exists with O_CREAT and O_EXCL
2798  F_NOTICE(" -> File exists");
2799  SYSCALL_ERROR(FileExists);
2800  pSubsystem->freeFd(fd);
2801  return -1;
2802  }
2803 
2804  // O_RDONLY is zero.
2805  bool checkRead = (flags == O_RDONLY) || (flags & O_RDWR);
2806 
2807  // Handle side effects.
2808  File *newFile = file->open();
2809 
2810  // Check for the desired permissions.
2811  // Note: we are permitted to create a file that we cannot open for writing
2812  // again. It will be open for the original mode requested if it was
2813  // created.
2814  if (!bCreated)
2815  {
2816  if (!VFS::checkAccess(
2817  file, checkRead, flags & (O_WRONLY | O_RDWR | O_TRUNC), false))
2818  {
2819  // checkAccess does a SYSCALL_ERROR for us.
2820  F_NOTICE(" -> file access denied.");
2821  return -1;
2822  }
2823  // Check for the desired permissions.
2824  if ((newFile != file) &&
2825  (!VFS::checkAccess(
2826  newFile, checkRead, flags & (O_WRONLY | O_RDWR | O_TRUNC),
2827  false)))
2828  {
2829  // checkAccess does a SYSCALL_ERROR for us.
2830  F_NOTICE(" -> file access denied.");
2831  return -1;
2832  }
2833  }
2834 
2835  // ensure we tweak the correct file now
2836  file = newFile;
2837 
2838  // Check for console (as we have special handling needed here)
2839  if (ConsoleManager::instance().isConsole(file))
2840  {
2841  // If a master console, attempt to lock.
2842  if (ConsoleManager::instance().isMasterConsole(file))
2843  {
2844  // Lock the master, we now own it.
2845  // Or, we don't - if someone else has it open for example.
2846  if (!ConsoleManager::instance().lockConsole(file))
2847  {
2848  F_NOTICE("Couldn't lock pseudoterminal master");
2849  SYSCALL_ERROR(DeviceBusy);
2850  pSubsystem->freeFd(fd);
2851  return -1;
2852  }
2853  }
2854  else
2855  {
2856  // Slave - set as controlling unless noctty is set.
2857  if ((flags & O_NOCTTY) == 0 && !openingCtty)
2858  {
2859  F_NOTICE(
2860  " -> setting opened terminal '" << file->getName()
2861  << "' to be controlling");
2862  console_setctty(file, false);
2863  }
2864  }
2865  }
2866 
2867  // Permissions were OK.
2868  if ((flags & O_TRUNC) &&
2869  ((flags & O_CREAT) || (flags & O_WRONLY) || (flags & O_RDWR)))
2870  {
2871  F_NOTICE(" -> {O_TRUNC}");
2872  // truncate the file
2873  file->truncate();
2874  }
2875 
2876  // Final checks.
2877  if (file->isFifo())
2878  {
2879  F_NOTICE("FIFO => checking if we have any readers");
2880 
2883  Pipe *pipe = Pipe::fromFile(file);
2884  if (!pipe->getReaderCount())
2885  {
2886  F_NOTICE("FIFO => might need to wait for a reader");
2887  if (flags & O_WRONLY)
2888  {
2889  // non-blocking open for writing with no readers -> io error
2890  if (flags & O_NONBLOCK)
2891  {
2892  // FIFO + no readers yet = ENXIO
2893  F_NOTICE(" -> ENXIO");
2894  SYSCALL_ERROR(NoSuchDevice);
2895  pSubsystem->freeFd(fd);
2896  return -1;
2897  }
2898  else
2899  {
2900  F_NOTICE("FIFO => not a non-blocking open");
2901 
2902  // need to wait for a reader
2903  if (!pipe->waitForReader())
2904  {
2905  // interrupted!
2906  F_NOTICE(" -> EINTR (fifo)");
2907  SYSCALL_ERROR(Interrupted);
2908  pSubsystem->freeFd(fd);
2909  return -1;
2910  }
2911  else
2912  {
2913  F_NOTICE("FIFO => successfully waited for a reader");
2914  }
2915  }
2916  }
2917  }
2918  else
2919  {
2920  F_NOTICE("FIFO => " << pipe->getReaderCount() << " readers.");
2921  }
2922  }
2923 
2924  FileDescriptor *f = new FileDescriptor(
2925  file, (flags & O_APPEND) ? file->getSize() : 0, fd, 0, flags);
2926  if (f)
2927  pSubsystem->addFileDescriptor(fd, f);
2928 
2929  F_NOTICE(" -> " << fd);
2930 
2931  return static_cast<int>(fd);
2932 }
2933 
2934 int posix_mkdirat(int dirfd, const char *pathname, mode_t mode)
2935 {
2936  F_NOTICE("mkdirat");
2937 
2938  File *cwd = check_dirfd(dirfd);
2939  if (!cwd)
2940  {
2941  return -1;
2942  }
2943 
2945  reinterpret_cast<uintptr_t>(pathname), PATH_MAX,
2946  PosixSubsystem::SafeRead))
2947  {
2948  F_NOTICE("mkdirat -> invalid address");
2949  SYSCALL_ERROR(InvalidArgument);
2950  return -1;
2951  }
2952 
2953  F_NOTICE("mkdirat(" << dirfd << ", " << pathname << ", " << mode << ")");
2954 
2955  String realPath;
2956  normalisePath(realPath, pathname);
2957 
2958  PosixProcess *pPosixProcess = getPosixProcess();
2959  if (pPosixProcess)
2960  {
2961  mode &= ~pPosixProcess->getMask();
2962  }
2963 
2964  bool worked = VFS::instance().createDirectory(realPath, mode, cwd);
2965  return worked ? 0 : -1;
2966 }
2967 
2968 int posix_fchownat(
2969  int dirfd, const char *pathname, uid_t owner, gid_t group, int flags)
2970 {
2971  F_NOTICE("fchownat");
2972 
2973  File *cwd = check_dirfd(dirfd, flags);
2974  if (!cwd)
2975  {
2976  return -1;
2977  }
2978 
2979  if (!pathname)
2980  {
2981  if (flags & AT_EMPTY_PATH)
2982  {
2983  // no pathname provided but it's an empty path chownat
2984  pathname = "";
2985  }
2986  else
2987  {
2988  // no pathname provided!
2989  SYSCALL_ERROR(InvalidArgument);
2990  return -1;
2991  }
2992  }
2993  else if (!PosixSubsystem::checkAddress(
2994  reinterpret_cast<uintptr_t>(pathname), PATH_MAX,
2995  PosixSubsystem::SafeRead))
2996  {
2997  F_NOTICE("chown -> invalid address");
2998  SYSCALL_ERROR(InvalidArgument);
2999  return -1;
3000  }
3001 
3002  F_NOTICE(
3003  "fchownat(" << dirfd << ", " << pathname << ", " << owner << ", "
3004  << group << ", " << flags << ")");
3005 
3006  File *file = 0;
3007 
3008  // Is there any need to change?
3009  if ((owner == group) && (owner == static_cast<uid_t>(-1)))
3010  return 0;
3011 
3012  bool onDevFs = false;
3013  String realPath;
3014  normalisePath(realPath, pathname, &onDevFs);
3015 
3016  if (onDevFs)
3017  {
3018  // Silently ignore.
3019  return 0;
3020  }
3021 
3022  // Lookup this process.
3023  Process *pProcess =
3024  Processor::information().getCurrentThread()->getParent();
3025  PosixSubsystem *pSubsystem =
3026  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
3027  if (!pSubsystem)
3028  {
3029  F_NOTICE(" -> No subsystem for this process!");
3030  return -1;
3031  }
3032 
3033  // AT_EMPTY_PATH only takes effect if the pathname is actually empty
3034  if ((flags & AT_EMPTY_PATH) && ((pathname == 0) || (*pathname == 0)))
3035  {
3036  FileDescriptor *pFd = pSubsystem->getFileDescriptor(dirfd);
3037  if (!pFd)
3038  {
3039  // Error - no such file descriptor.
3040  SYSCALL_ERROR(BadFileDescriptor);
3041  return -1;
3042  }
3043 
3044  file = pFd->file;
3045  }
3046  else
3047  {
3048  file = findFileWithAbiFallbacks(realPath, cwd);
3049  if (!file)
3050  {
3051  SYSCALL_ERROR(DoesNotExist);
3052  return -1;
3053  }
3054  }
3055 
3056  // Read-only filesystem?
3057  if (file->getFilesystem()->isReadOnly())
3058  {
3059  SYSCALL_ERROR(ReadOnlyFilesystem);
3060  return -1;
3061  }
3062 
3063  // Symlink traversal
3064  if ((flags & AT_SYMLINK_NOFOLLOW) == 0)
3065  {
3066  file = traverseSymlink(file);
3067  }
3068 
3069  if (!file)
3070  {
3071  SYSCALL_ERROR(DoesNotExist);
3072  return -1;
3073  }
3074 
3075  return doChown(file, owner, group) ? 0 : -1;
3076 }
3077 
3078 int posix_futimesat(
3079  int dirfd, const char *pathname, const struct timeval *times)
3080 {
3081  F_NOTICE("futimesat");
3082 
3083  File *cwd = check_dirfd(dirfd);
3084  if (!cwd)
3085  {
3086  return -1;
3087  }
3088 
3090  reinterpret_cast<uintptr_t>(pathname), PATH_MAX,
3091  PosixSubsystem::SafeRead) &&
3092  ((!times) ||
3094  reinterpret_cast<uintptr_t>(times), sizeof(struct timeval) * 2,
3095  PosixSubsystem::SafeRead))))
3096  {
3097  F_NOTICE("utimes -> invalid address");
3098  SYSCALL_ERROR(InvalidArgument);
3099  return -1;
3100  }
3101 
3102  F_NOTICE("futimesat(" << dirfd << ", " << pathname << ", " << times << ")");
3103 
3104  String realPath;
3105  normalisePath(realPath, pathname);
3106 
3107  File *file = findFileWithAbiFallbacks(realPath, cwd);
3108  if (!file)
3109  {
3110  SYSCALL_ERROR(DoesNotExist);
3111  return -1;
3112  }
3113 
3114  // Symlink traversal
3115  file = traverseSymlink(file);
3116  if (!file)
3117  return -1;
3118 
3119  if (!VFS::checkAccess(file, false, true, false))
3120  {
3121  // checkAccess does a SYSCALL_ERROR for us.
3122  return -1;
3123  }
3124 
3125  Time::Timestamp accessTime;
3126  Time::Timestamp modifyTime;
3127  if (times)
3128  {
3129  struct timeval access = times[0];
3130  struct timeval modify = times[1];
3131 
3132  accessTime = access.tv_sec * Time::Multiplier::Second;
3133  accessTime += access.tv_usec * Time::Multiplier::Microsecond;
3134 
3135  modifyTime = modify.tv_sec * Time::Multiplier::Second;
3136  modifyTime += modify.tv_usec * Time::Multiplier::Microsecond;
3137  }
3138  else
3139  {
3140  accessTime = modifyTime = Time::getTimeNanoseconds();
3141  }
3142 
3143  file->setAccessedTime(accessTime);
3144  file->setModifiedTime(modifyTime);
3145 
3146  return 0;
3147 }
3148 
3149 int posix_unlinkat(int dirfd, const char *pathname, int flags)
3150 {
3151  F_NOTICE("unlinkat");
3152 
3153  File *cwd = check_dirfd(dirfd);
3154  if (!cwd)
3155  {
3156  return -1;
3157  }
3158 
3160  reinterpret_cast<uintptr_t>(pathname), PATH_MAX,
3161  PosixSubsystem::SafeRead))
3162  {
3163  F_NOTICE("unlink -> invalid address");
3164  SYSCALL_ERROR(InvalidArgument);
3165  return -1;
3166  }
3167 
3168  F_NOTICE("unlinkat(" << dirfd << ", " << pathname << ", " << flags << ")");
3169 
3170  String realPath;
3171  normalisePath(realPath, pathname);
3172 
3173  File *pFile = findFileWithAbiFallbacks(realPath, cwd);
3174  if (!pFile)
3175  {
3176  SYSCALL_ERROR(DoesNotExist);
3177  return -1;
3178  }
3179  else if (pFile->isDirectory() && ((flags & AT_REMOVEDIR) == 0))
3180  {
3181  // unless AT_REMOVEDIR is specified, we won't rmdir
3182  SYSCALL_ERROR(NotEnoughPermissions);
3183  return -1;
3184  }
3185 
3186  // remove() checks permissions to ensure we can delete the file.
3187  if (VFS::instance().remove(realPath, GET_CWD()))
3188  {
3189  return 0;
3190  }
3191  else
3192  {
3193  return -1;
3194  }
3195 }
3196 
3197 int posix_renameat(
3198  int olddirfd, const char *oldpath, int newdirfd, const char *newpath)
3199 {
3200  F_NOTICE("renameat");
3201 
3202  File *oldcwd = check_dirfd(olddirfd);
3203  if (!oldcwd)
3204  {
3205  return -1;
3206  }
3207 
3208  File *newcwd = check_dirfd(newdirfd);
3209  if (!newcwd)
3210  {
3211  return -1;
3212  }
3213 
3215  reinterpret_cast<uintptr_t>(oldpath), PATH_MAX,
3216  PosixSubsystem::SafeRead) &&
3218  reinterpret_cast<uintptr_t>(newpath), PATH_MAX,
3219  PosixSubsystem::SafeRead)))
3220  {
3221  F_NOTICE("rename -> invalid address");
3222  SYSCALL_ERROR(InvalidArgument);
3223  return -1;
3224  }
3225 
3226  F_NOTICE(
3227  "renameat(" << olddirfd << ", " << oldpath << ", " << newdirfd << ", "
3228  << newpath << ")");
3229 
3230  String realSource;
3231  String realDestination;
3232  normalisePath(realSource, oldpath);
3233  normalisePath(realDestination, newpath);
3234 
3235  File *src = findFileWithAbiFallbacks(realSource, oldcwd);
3236  File *dest = findFileWithAbiFallbacks(realDestination, newcwd);
3237 
3238  if (!src)
3239  {
3240  SYSCALL_ERROR(DoesNotExist);
3241  return -1;
3242  }
3243 
3244  // traverse symlink
3245  src = traverseSymlink(src);
3246  if (!src)
3247  {
3248  SYSCALL_ERROR(DoesNotExist);
3249  return -1;
3250  }
3251 
3252  if (dest)
3253  {
3254  // traverse symlink
3255  dest = traverseSymlink(dest);
3256  if (!dest)
3257  {
3258  SYSCALL_ERROR(DoesNotExist);
3259  return -1;
3260  }
3261 
3262  if (dest->isDirectory() && !src->isDirectory())
3263  {
3264  SYSCALL_ERROR(FileExists);
3265  return -1;
3266  }
3267  else if (!dest->isDirectory() && src->isDirectory())
3268  {
3269  SYSCALL_ERROR(NotADirectory);
3270  return -1;
3271  }
3272  }
3273  else
3274  {
3275  VFS::instance().createFile(realDestination, 0777, newcwd);
3276  dest = findFileWithAbiFallbacks(realDestination, newcwd);
3277  if (!dest)
3278  {
3279  // Failed to create the file?
3280  return -1;
3281  }
3282  }
3283 
3284  // Gay algorithm.
3285  uint8_t *buf = new uint8_t[src->getSize()];
3286  src->read(0, src->getSize(), reinterpret_cast<uintptr_t>(buf));
3287  dest->truncate();
3288  dest->write(0, src->getSize(), reinterpret_cast<uintptr_t>(buf));
3289  VFS::instance().remove(realSource, oldcwd);
3290  delete[] buf;
3291 
3292  return 0;
3293 }
3294 
3295 int posix_linkat(
3296  int olddirfd, const char *oldpath, int newdirfd, const char *newpath,
3297  int flags)
3298 {
3299  F_NOTICE("linkat");
3300 
3301  File *oldcwd = check_dirfd(olddirfd, flags);
3302  if (!oldcwd)
3303  {
3304  return -1;
3305  }
3306 
3307  File *newcwd = check_dirfd(newdirfd);
3308  if (!newcwd)
3309  {
3310  return -1;
3311  }
3312 
3314  reinterpret_cast<uintptr_t>(oldpath), PATH_MAX,
3315  PosixSubsystem::SafeRead) &&
3317  reinterpret_cast<uintptr_t>(newpath), PATH_MAX,
3318  PosixSubsystem::SafeRead)))
3319  {
3320  F_NOTICE("link -> invalid address");
3321  SYSCALL_ERROR(InvalidArgument);
3322  return -1;
3323  }
3324 
3325  F_NOTICE(
3326  "linkat(" << olddirfd << ", " << oldpath << ", " << newdirfd << ", "
3327  << newpath << ", " << flags << ")");
3328 
3329  // Lookup this process.
3330  Process *pProcess =
3331  Processor::information().getCurrentThread()->getParent();
3332  PosixSubsystem *pSubsystem =
3333  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
3334  if (!pSubsystem)
3335  {
3336  ERROR("No subsystem for this process!");
3337  return -1;
3338  }
3339 
3340  // Try and find the target.
3341  String realTarget;
3342  String realLink;
3343  normalisePath(realTarget, oldpath);
3344  normalisePath(realLink, newpath);
3345 
3346  File *pTarget = 0;
3347  if ((flags & AT_EMPTY_PATH) && ((oldpath == 0) || (*oldpath == 0)))
3348  {
3349  FileDescriptor *pFd = pSubsystem->getFileDescriptor(olddirfd);
3350  if (!pFd)
3351  {
3352  // Error - no such file descriptor.
3353  SYSCALL_ERROR(BadFileDescriptor);
3354  return -1;
3355  }
3356 
3357  pTarget = pFd->file;
3358  }
3359  else
3360  {
3361  pTarget = findFileWithAbiFallbacks(realTarget, oldcwd);
3362  }
3363 
3364  if (flags & AT_SYMLINK_FOLLOW)
3365  {
3366  pTarget = traverseSymlink(pTarget);
3367  }
3368 
3369  if (!pTarget)
3370  {
3371  F_NOTICE(" -> target '" << realTarget << "' did not exist.");
3372  SYSCALL_ERROR(DoesNotExist);
3373  return -1;
3374  }
3375 
3376  bool result = VFS::instance().createLink(realLink, pTarget, newcwd);
3377 
3378  if (!result)
3379  {
3380  F_NOTICE(" -> failed to create link");
3381  return -1;
3382  }
3383 
3384  F_NOTICE(" -> ok");
3385  return 0;
3386 }
3387 
3388 int posix_symlinkat(const char *oldpath, int newdirfd, const char *newpath)
3389 {
3390  F_NOTICE("symlinkat");
3391 
3392  File *cwd = check_dirfd(newdirfd);
3393  if (!cwd)
3394  {
3395  return -1;
3396  }
3397 
3399  reinterpret_cast<uintptr_t>(oldpath), PATH_MAX,
3400  PosixSubsystem::SafeRead) &&
3402  reinterpret_cast<uintptr_t>(newpath), PATH_MAX,
3403  PosixSubsystem::SafeRead)))
3404  {
3405  F_NOTICE("symlink -> invalid address");
3406  SYSCALL_ERROR(InvalidArgument);
3407  return -1;
3408  }
3409 
3410  F_NOTICE(
3411  "symlinkat(" << oldpath << ", " << newdirfd << ", " << newpath << ")");
3412 
3413  bool worked =
3414  VFS::instance().createSymlink(String(newpath), String(oldpath), cwd);
3415  if (worked)
3416  return 0;
3417  else
3418  ERROR("Symlink failed for `" << newpath << "' -> `" << oldpath << "'");
3419  return -1;
3420 }
3421 
3422 int posix_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
3423 {
3424  F_NOTICE("readlinkat");
3425 
3426  File *cwd = check_dirfd(dirfd);
3427  if (!cwd)
3428  {
3429  return -1;
3430  }
3431 
3433  reinterpret_cast<uintptr_t>(pathname), PATH_MAX,
3434  PosixSubsystem::SafeRead) &&
3436  reinterpret_cast<uintptr_t>(buf), bufsiz,
3437  PosixSubsystem::SafeWrite)))
3438  {
3439  F_NOTICE("readlink -> invalid address");
3440  SYSCALL_ERROR(InvalidArgument);
3441  return -1;
3442  }
3443 
3444  F_NOTICE(
3445  "readlinkat(" << dirfd << ", " << pathname << ", " << buf << ", "
3446  << bufsiz << ")");
3447 
3448  String realPath;
3449  normalisePath(realPath, pathname);
3450 
3451  File *f = findFileWithAbiFallbacks(realPath, cwd);
3452  if (!f)
3453  {
3454  SYSCALL_ERROR(DoesNotExist);
3455  return -1;
3456  }
3457 
3458  if (!f->isSymlink())
3459  {
3460  SYSCALL_ERROR(InvalidArgument);
3461  return -1;
3462  }
3463 
3464  if (buf == 0)
3465  return -1;
3466 
3467  HugeStaticString str;
3468  HugeStaticString tmp;
3469  str.clear();
3470  tmp.clear();
3471 
3472  return Symlink::fromFile(f)->followLink(buf, bufsiz);
3473 }
3474 
3475 int posix_fchmodat(int dirfd, const char *pathname, mode_t mode, int flags)
3476 {
3477  F_NOTICE("fchmodat");
3478 
3479  File *cwd = check_dirfd(dirfd, flags);
3480  if (!cwd)
3481  {
3482  return -1;
3483  }
3484 
3485  if (!pathname)
3486  {
3487  if (flags & AT_EMPTY_PATH)
3488  {
3489  // no pathname provided but it's an empty path chmodat
3490  pathname = "";
3491  }
3492  else
3493  {
3494  // no pathname provided!
3495  SYSCALL_ERROR(InvalidArgument);
3496  return -1;
3497  }
3498  }
3499  else if (!PosixSubsystem::checkAddress(
3500  reinterpret_cast<uintptr_t>(pathname), PATH_MAX,
3501  PosixSubsystem::SafeRead))
3502  {
3503  F_NOTICE("chmod -> invalid address");
3504  SYSCALL_ERROR(InvalidArgument);
3505  return -1;
3506  }
3507 
3508  F_NOTICE(
3509  "fchmodat(" << dirfd << ", " << pathname << ", " << Oct << mode << Hex
3510  << ", " << flags << ")");
3511 
3512  if (mode == static_cast<mode_t>(-1))
3513  {
3514  F_NOTICE(" -> invalid mode");
3515  SYSCALL_ERROR(InvalidArgument);
3516  return -1;
3517  }
3518 
3519  bool onDevFs = false;
3520  String realPath;
3521  normalisePath(realPath, pathname, &onDevFs);
3522 
3523  if (onDevFs)
3524  {
3525  // Silently ignore.
3526  return 0;
3527  }
3528 
3529  // Lookup this process.
3530  Process *pProcess =
3531  Processor::information().getCurrentThread()->getParent();
3532  PosixSubsystem *pSubsystem =
3533  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
3534  if (!pSubsystem)
3535  {
3536  F_NOTICE(" -> No subsystem for this process!");
3537  return -1;
3538  }
3539 
3540  // AT_EMPTY_PATH only takes effect if the pathname is actually empty
3541  File *file = 0;
3542  if ((flags & AT_EMPTY_PATH) && ((pathname == 0) || (*pathname == 0)))
3543  {
3544  FileDescriptor *pFd = pSubsystem->getFileDescriptor(dirfd);
3545  if (!pFd)
3546  {
3547  // Error - no such file descriptor.
3548  SYSCALL_ERROR(BadFileDescriptor);
3549  return -1;
3550  }
3551 
3552  file = pFd->file;
3553  }
3554  else
3555  {
3556  file = findFileWithAbiFallbacks(realPath, GET_CWD());
3557  if (!file)
3558  {
3559  SYSCALL_ERROR(DoesNotExist);
3560  return -1;
3561  }
3562  }
3563 
3564  // Read-only filesystem?
3565  if (file->getFilesystem()->isReadOnly())
3566  {
3567  SYSCALL_ERROR(ReadOnlyFilesystem);
3568  return -1;
3569  }
3570 
3571  // Symlink traversal
3572  if ((flags & AT_SYMLINK_NOFOLLOW) == 0)
3573  {
3574  file = traverseSymlink(file);
3575  }
3576 
3577  if (!file)
3578  {
3579  SYSCALL_ERROR(DoesNotExist);
3580  return -1;
3581  }
3582 
3583  return doChmod(file, mode) ? 0 : -1;
3584 }
3585 
3586 int posix_faccessat(int dirfd, const char *pathname, int mode, int flags)
3587 {
3588  F_NOTICE("faccessat");
3589 
3590  File *cwd = check_dirfd(dirfd);
3591  if (!cwd)
3592  {
3593  return -1;
3594  }
3595 
3597  reinterpret_cast<uintptr_t>(pathname), PATH_MAX,
3598  PosixSubsystem::SafeRead))
3599  {
3600  F_NOTICE("access -> invalid address");
3601  SYSCALL_ERROR(InvalidArgument);
3602  return -1;
3603  }
3604 
3605  F_NOTICE(
3606  "faccessat(" << dirfd << ", " << pathname << ", " << mode << ", "
3607  << flags << ")");
3608 
3609  if (!pathname)
3610  {
3611  SYSCALL_ERROR(DoesNotExist);
3612  return -1;
3613  }
3614 
3615  String realPath;
3616  normalisePath(realPath, pathname);
3617 
3618  // Grab the file
3619  File *file = findFileWithAbiFallbacks(realPath, cwd);
3620 
3621  if ((flags & AT_SYMLINK_NOFOLLOW) == 0)
3622  {
3623  file = traverseSymlink(file);
3624  }
3625 
3626  if (!file)
3627  {
3628  F_NOTICE(" -> '" << realPath << "' does not exist");
3629  SYSCALL_ERROR(DoesNotExist);
3630  return -1;
3631  }
3632 
3633  // If we're only checking for existence, we're done here.
3634  if (mode == F_OK)
3635  {
3636  F_NOTICE(" -> ok");
3637  return 0;
3638  }
3639 
3640  if (!VFS::checkAccess(file, mode & R_OK, mode & W_OK, mode & X_OK))
3641  {
3642  // checkAccess does a SYSCALL_ERROR for us.
3643  F_NOTICE(" -> not ok");
3644  return -1;
3645  }
3646 
3647  F_NOTICE(" -> ok");
3648  return 0;
3649 }
3650 
3651 int posix_fstatat(int dirfd, const char *pathname, struct stat *buf, int flags)
3652 {
3653  F_NOTICE("fstatat");
3654 
3655  File *cwd = check_dirfd(dirfd, flags);
3656  if (!cwd)
3657  {
3658  F_NOTICE(" -> current working directory could not be determined");
3659  return -1;
3660  }
3661 
3663  if (!((!pathname) || (PosixSubsystem::checkAddress(
3664  reinterpret_cast<uintptr_t>(pathname), PATH_MAX,
3665  PosixSubsystem::SafeRead) &&
3667  reinterpret_cast<uintptr_t>(buf),
3668  sizeof(struct stat), PosixSubsystem::SafeWrite))))
3669  {
3670  F_NOTICE("fstat -> invalid address");
3671  SYSCALL_ERROR(InvalidArgument);
3672  return -1;
3673  }
3674 
3675  F_NOTICE(
3676  "fstatat(" << dirfd << ", " << (pathname ? pathname : "(n/a)") << ", "
3677  << buf << ", " << flags << ")");
3678 
3679  F_NOTICE(" -> cwd=" << cwd->getFullPath());
3680 
3681  if (!buf)
3682  {
3683  SYSCALL_ERROR(InvalidArgument);
3684  return -1;
3685  }
3686 
3687  // Lookup this process.
3688  Process *pProcess =
3689  Processor::information().getCurrentThread()->getParent();
3690  PosixSubsystem *pSubsystem =
3691  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
3692  if (!pSubsystem)
3693  {
3694  ERROR("No subsystem for this process!");
3695  return -1;
3696  }
3697 
3698  // AT_EMPTY_PATH only takes effect if the pathname is actually empty
3699  File *file = 0;
3700  if ((flags & AT_EMPTY_PATH) && ((pathname == 0) || (*pathname == 0)))
3701  {
3702  FileDescriptor *pFd = pSubsystem->getFileDescriptor(dirfd);
3703  if (!pFd)
3704  {
3705  // Error - no such file descriptor.
3706  SYSCALL_ERROR(BadFileDescriptor);
3707  return -1;
3708  }
3709 
3710  file = pFd->file;
3711  }
3712  else
3713  {
3714  String realPath;
3715  normalisePath(realPath, pathname);
3716 
3717  F_NOTICE(
3718  " -> finding file with real path " << realPath << " in "
3719  << cwd->getFullPath());
3720 
3721  file = findFileWithAbiFallbacks(realPath, cwd);
3722  if (!file)
3723  {
3724  SYSCALL_ERROR(DoesNotExist);
3725  F_NOTICE(" -> unable to find '" << realPath << "' here");
3726  return -1;
3727  }
3728  }
3729 
3730  if ((flags & AT_SYMLINK_NOFOLLOW) == 0)
3731  {
3732  file = traverseSymlink(file);
3733  }
3734 
3735  if (!file)
3736  {
3737  SYSCALL_ERROR(DoesNotExist);
3738  return -1;
3739  }
3740 
3741  if (!doStat(0, file, buf))
3742  {
3743  return -1;
3744  }
3745 
3746  F_NOTICE(" -> Success");
3747  return 0;
3748 }
3749 
3751 static ssize_t doGetXattr(
3752  const char *filepath, int fd, const char *name, void *value, size_t size,
3753  bool follow_links)
3754 {
3756  SYSCALL_ERROR(OperationNotSupported);
3757  return -1;
3758 }
3759 
3760 ssize_t
3761 posix_getxattr(const char *path, const char *name, void *value, size_t size)
3762 {
3763  return doGetXattr(path, -1, name, value, size, true);
3764 }
3765 
3766 ssize_t
3767 posix_lgetxattr(const char *path, const char *name, void *value, size_t size)
3768 {
3769  return doGetXattr(path, -1, name, value, size, false);
3770 }
3771 
3772 ssize_t posix_fgetxattr(int fd, const char *name, void *value, size_t size)
3773 {
3774  return doGetXattr(nullptr, fd, name, value, size, true);
3775 }
3776 
3777 int posix_mknod(const char *pathname, mode_t mode, dev_t dev)
3778 {
3779  F_NOTICE("mknod");
3781  reinterpret_cast<uintptr_t>(pathname), PATH_MAX,
3782  PosixSubsystem::SafeRead))
3783  {
3784  F_NOTICE(" -> invalid address for pathname");
3785  SYSCALL_ERROR(InvalidArgument);
3786  return -1;
3787  }
3788 
3789  F_NOTICE("mknod(" << pathname << ", " << mode << ", " << dev << ")");
3790 
3791  File *targetFile = findFileWithAbiFallbacks(String(pathname), GET_CWD());
3792  if (targetFile)
3793  {
3794  F_NOTICE(" -> already exists");
3795  SYSCALL_ERROR(FileExists);
3796  return -1;
3797  }
3798 
3799  // Open parent directory if we can.
3800  const char *parentDirectory = DirectoryName(pathname);
3801  const char *baseName = BaseName(pathname);
3802  if (!baseName)
3803  {
3804  F_NOTICE(" -> no filename provided");
3805  SYSCALL_ERROR(DoesNotExist);
3806  delete[] parentDirectory;
3807  return -1;
3808  }
3809 
3810  PointerGuard<const char> guard1(parentDirectory, true);
3811  PointerGuard<const char> guard2(baseName, true);
3812 
3813  // support mknod("foo") as well as mknod("/path/to/foo")
3814  File *parentFile = GET_CWD();
3815  if (parentDirectory)
3816  {
3817  String parentPath;
3818  normalisePath(parentPath, parentDirectory, nullptr);
3819  F_NOTICE("finding parent directory " << parentDirectory << "...");
3820  F_NOTICE(" -> " << parentPath << "...");
3821  parentFile = findFileWithAbiFallbacks(parentPath, GET_CWD());
3822 
3823  parentFile = traverseSymlink(parentFile);
3824  if (!parentFile)
3825  {
3826  // traverseSymlink sets error for us
3827  F_NOTICE(" -> symlink traversal failed");
3828  return -1;
3829  }
3830  }
3831  else
3832  {
3833  NOTICE("NO parent directory was found for path " << pathname);
3834  }
3835 
3836  if (!parentFile->isDirectory())
3837  {
3838  SYSCALL_ERROR(NotADirectory);
3839  F_NOTICE(" -> target parent is not a directory");
3840  return -1;
3841  }
3842 
3843  Directory *parentDir = Directory::fromFile(parentFile);
3844 
3845  if ((mode & S_IFIFO) == S_IFIFO)
3846  {
3847  // Need to create a FIFO (i.e. named pipe).
3848  Pipe *pipe = new Pipe(
3849  String(baseName), 0, 0, 0, 0, parentDir->getFilesystem(), 0,
3850  parentDir);
3851  parentDir->addEphemeralFile(pipe);
3852 
3853  F_NOTICE(" -> fifo/pipe '" << baseName << "' created!");
3854  F_NOTICE(" -> full path is " << pipe->getFullPath(true));
3855  }
3856  else
3857  {
3858  SYSCALL_ERROR(Unimplemented);
3859  F_NOTICE(" -> unimplemented mode requested");
3860  return -1;
3861  }
3862 
3863  return 0;
3864 }
3865 
3866 static int do_statfs(File *file, struct statfs *buf)
3867 {
3869  reinterpret_cast<uintptr_t>(buf), sizeof(struct statfs),
3870  PosixSubsystem::SafeWrite))
3871  {
3872  F_NOTICE(" -> invalid address for buf [" << buf << "]");
3873  SYSCALL_ERROR(InvalidArgument);
3874  return -1;
3875  }
3876 
3877  if (!file)
3878  {
3879  F_NOTICE(" -> file does not exist");
3880  SYSCALL_ERROR(DoesNotExist);
3881  return -1;
3882  }
3883 
3884  Filesystem *pFs = file->getFilesystem();
3885 
3887  bool bFilled = false;
3888  if (pFs == g_pDevFs)
3889  {
3890  F_NOTICE(" -> file '" << file->getName() << "' is on devfs");
3891 
3892  // Special handling for devfs
3893  if (file->getName() == "pts")
3894  {
3895  F_NOTICE(" -> filling statfs struct with /dev/pts data");
3896  ByteSet(buf, 0, sizeof(*buf));
3897  buf->f_type = 0x1CD1; // DEVPTS_SUPER_MAGIC
3898  buf->f_bsize = 4096;
3899  buf->f_namelen = PATH_MAX;
3900  buf->f_frsize = 4096;
3901  bFilled = true;
3902  }
3903  }
3904 
3905  if (!bFilled)
3906  {
3908  F_NOTICE(" -> filling statfs struct with ext2 data");
3909  ByteSet(buf, 0, sizeof(*buf));
3910  buf->f_type = 0xEF53; // EXT2_SUPER_MAGIC
3911  if (pFs->getDisk())
3912  {
3913  buf->f_bsize = pFs->getDisk()->getBlockSize();
3914  buf->f_blocks =
3915  pFs->getDisk()->getSize() / pFs->getDisk()->getBlockSize();
3916  }
3917  else
3918  {
3919  buf->f_bsize = 4096;
3920  buf->f_blocks = 0x100000; // incorrect...
3921  }
3922  buf->f_bfree = buf->f_blocks;
3923  buf->f_bavail = buf->f_blocks;
3924  buf->f_files = 1234;
3925  buf->f_ffree = 5678;
3926  buf->f_namelen = PATH_MAX;
3927  buf->f_frsize = 0;
3928  }
3929 
3930  F_NOTICE(" -> ok");
3931  return 0;
3932 }
3933 
3934 int posix_statfs(const char *path, struct statfs *buf)
3935 {
3936  F_NOTICE("statfs");
3937 
3939  reinterpret_cast<uintptr_t>(path), PATH_MAX,
3940  PosixSubsystem::SafeRead))
3941  {
3942  F_NOTICE(" -> invalid address for path");
3943  SYSCALL_ERROR(InvalidArgument);
3944  return -1;
3945  }
3946 
3947  F_NOTICE("statfs(" << path << ")");
3948  String normalisedPath;
3949  normalisePath(normalisedPath, path);
3950  F_NOTICE(" -> actually performing statfs on " << normalisedPath);
3951  File *file = findFileWithAbiFallbacks(normalisedPath, GET_CWD());
3952 
3953  return do_statfs(file, buf);
3954 }
3955 
3956 int posix_fstatfs(int fd, struct statfs *buf)
3957 {
3958  F_NOTICE("fstatfs(" << fd << ")");
3959 
3960  Process *pProcess =
3961  Processor::information().getCurrentThread()->getParent();
3962  PosixSubsystem *pSubsystem =
3963  reinterpret_cast<PosixSubsystem *>(pProcess->getSubsystem());
3964  if (!pSubsystem)
3965  {
3966  ERROR("No subsystem for this process!");
3967  return -1;
3968  }
3969 
3970  FileDescriptor *pFd = pSubsystem->getFileDescriptor(fd);
3971  if (!pFd)
3972  {
3973  // Error - no such file descriptor.
3974  SYSCALL_ERROR(BadFileDescriptor);
3975  return -1;
3976  }
3977 
3978  return do_statfs(pFd->file, buf);
3979 }
3980 
3981 int posix_mount(
3982  const char *src, const char *tgt, const char *fs, size_t flags,
3983  const void *data)
3984 {
3985  F_NOTICE("mount");
3986 
3988  reinterpret_cast<uintptr_t>(src), PATH_MAX,
3989  PosixSubsystem::SafeRead) &&
3991  reinterpret_cast<uintptr_t>(tgt), PATH_MAX,
3992  PosixSubsystem::SafeRead) &&
3994  reinterpret_cast<uintptr_t>(fs), PATH_MAX,
3995  PosixSubsystem::SafeRead)))
3996  {
3997  F_NOTICE(" -> invalid address");
3998  SYSCALL_ERROR(BadAddress);
3999  return -1;
4000  }
4001 
4002  String source(src);
4003  String target(tgt);
4004  String fstype(fs);
4005 
4006  F_NOTICE(
4007  "mount(" << source << ", " << target << ", " << fstype << ", " << Hex
4008  << flags << ", " << data << ")");
4009 
4010  // Is the target a valid directory?
4011  String targetNormalised;
4012  normalisePath(targetNormalised, tgt);
4013  File *targetFile = findFileWithAbiFallbacks(targetNormalised, nullptr);
4014  if (!targetFile)
4015  {
4016  F_NOTICE(" -> target does not exist");
4017  SYSCALL_ERROR(DoesNotExist);
4018  return -1;
4019  }
4020 
4021  if (!targetFile->isDirectory())
4022  {
4023  F_NOTICE(" -> target not a directory");
4024  SYSCALL_ERROR(NotADirectory);
4025  return -1;
4026  }
4027 
4028  Directory *targetDir = Directory::fromFile(targetFile);
4029 
4030  // Check for special filesystems.
4031  if (fstype == "proc")
4032  {
4033  F_NOTICE(" -> adding another procfs mount");
4034 
4035  Filesystem *pFs = VFS::instance().lookupFilesystem(String("proc"));
4036  if (!pFs)
4037  {
4038  SYSCALL_ERROR(DeviceDoesNotExist);
4039  return -1;
4040  }
4041 
4042  if (targetFile == pFs->getRoot() ||
4043  targetDir->getReparsePoint() == pFs->getRoot())
4044  {
4045  // Already mounted here?
4046  return 0;
4047  }
4048 
4049  // Add reparse point.
4050  targetDir->setReparsePoint(Directory::fromFile(pFs->getRoot()));
4051  return 0;
4052  }
4053  else if (fstype == "tmpfs")
4054  {
4055  F_NOTICE(" -> creating new tmpfs");
4056 
4057  RamFs *pRamFs = new RamFs;
4058  pRamFs->initialise(0);
4059 
4060  targetDir->setReparsePoint(Directory::fromFile(pRamFs->getRoot()));
4061  return 0;
4062  }
4063  else
4064  {
4065  F_NOTICE(" -> unsupported fstype");
4066  SYSCALL_ERROR(DeviceDoesNotExist);
4067  return -1;
4068  }
4069 
4070  SYSCALL_ERROR(PermissionDenied);
4071  return -1;
4072 }
4073 
4074 void generate_mtab(String &result)
4075 {
4076  result = "";
4077 
4078  struct Remapping *remap = g_Remappings;
4079  while (remap->from != nullptr)
4080  {
4081  if (remap->fsname)
4082  {
4083  String line;
4084  line.Format(
4085  "%s %s %s rw 0 0\n", remap->to, remap->from, remap->fsname);
4086 
4087  result += line;
4088  }
4089 
4090  ++remap;
4091  }
4092 
4093  // Add root filesystem.
4094  Filesystem *pRootFs = VFS::instance().lookupFilesystem(String("root"));
4095  if (pRootFs)
4096  {
4099  String line;
4100  line.Format("/dev/sda1 / ext2 rw 0 0\n");
4101 
4102  result += line;
4103  }
4104 
4105  F_NOTICE("generated mtab:\n" << result);
4106 }
T * get() const
void unlockConsole(File *file)
Release a console master locked as above.
Definition: Console.cc:131
void removeWakeupWatcher(WakeReason *watcher)
Definition: Thread.cc:995
uint64_t offset
Offset within the file for I/O.
void activate(size_t n)
Starts the process of activating the given tty.
bool wasInterrupted()
Definition: Thread.h:229
virtual bool isFifo() const
Definition: File.cc:446
virtual Keyboard * getKeyboard()=0
void addWakeupWatcher(WakeReason *watcher)
Definition: Thread.cc:988
virtual int command(const size_t command, void *buffer)
Definition: File.cc:544
virtual bool initialise(Disk *pDisk)
Definition: RamFs.cc:139
Abi getAbi() const
size_t getId()
Definition: User.h:66
Definition: cmd.h:30
An in-RAM filesystem.
void reportPermission(SwitchPermission perm)
bool isReadOnly()
Definition: Filesystem.h:107
Time::Timestamp getAccessedTime()
Definition: File.cc:389
virtual int select(bool bWriting=false, int timeout=0)
Definition: File.cc:534
void freeFd(size_t fdNum)
bool createLink(const String &path, File *target, File *pStartNode=0)
Definition: VFS.cc:397
virtual void getName(String &str)
Definition: Device.cc:121
struct vt_mode getTerminalMode(size_t n) const
void monitor(Thread *pThread, Event *pEvent)
Definition: File.cc:683
MemoryMappedObject * mapAnon(uintptr_t &address, size_t length, MemoryMappedObject::Permissions perms)
Tree< Filesystem *, List< String * > * > & getMounts()
Definition: VFS.h:98
SharedPointer< class NetworkSyscalls > networkImpl
Network syscall implementation for this descriptor (if it&#39;s a socket).
virtual uintptr_t getUserStart() const =0
virtual bool supports(const size_t command) const
Definition: File.cc:539
virtual void setLedState(char state)
Definition: Keyboard.cc:30
virtual size_t getBlockSize() const
Definition: File.cc:549
static Directory * fromFile(File *pF)
Definition: Directory.h:50
WakeReason
Definition: Thread.h:82
static KeymapManager & instance()
Singleton design.
Definition: KeymapManager.h:41
void setReparsePoint(Directory *pTarget)
Definition: Directory.cc:154
Definition: String.h:49
Filesystem * lookupFilesystem(const String &alias)
Definition: VFS.cc:221
virtual uintptr_t getKernelStart() const =0
static ProcessorInformation & information()
Definition: Processor.cc:45
void addFileDescriptor(size_t fd, FileDescriptor *pFd)
static VFS & instance()
Definition: VFS.cc:56
Definition: User.h:32
File * file
Our open file pointer.
Disk * getDisk()
Definition: Filesystem.h:101
Definition: Disk.h:32
Group * getGroup(size_t id)
Definition: UserManager.cc:105
Time::Timestamp getCreationTime()
Definition: File.cc:378
virtual File * getRoot() const
Definition: RamFs.h:104
size_t setPermissions(uintptr_t base, size_t length, MemoryMappedObject::Permissions perms)
virtual bool isSymlink()
Definition: File.cc:431
uint8_t convertPc102ScancodeToHidKeycode(uint8_t scancode, EscapeState &escape)
Converts a pc102 scancode into a HID keycode.
static bool checkAddress(uintptr_t addr, size_t extent, size_t flags)
#define WARNING(text)
Definition: Log.h:78
void invalidate(uintptr_t base, size_t length)
bool createSymlink(const String &path, const String &value, File *pStartNode=0)
Definition: VFS.cc:370
void sync(uintptr_t base, size_t length, bool async)
Definition: List.h:64
void insert(const K &key, const E &value)
Definition: Tree.h:173
virtual size_t getSize() const
Gets the size of the disk.
Definition: Disk.cc:69
Memory-mapped file interface.
#define NOTICE(text)
Definition: Log.h:74
virtual size_t getBlockSize() const
Gets the block size of the disk.
Definition: Disk.cc:74
bool isMember(User *pUser)
Definition: Group.cc:49
virtual String getFullPath(bool bWithLabel=true)
Definition: File.cc:718
Definition: Log.h:136
A key/value dictionary.
Definition: Tree.h:33
int flflags
File status flags (fcntl)
File * getCtty()
Definition: Process.h:167
static MemoryMapManager & instance()
bool createDirectory(const String &path, uint32_t mask, File *pStartNode=0)
Definition: VFS.cc:338
void setRootFile(File *pFile)
Definition: Process.h:390
bool createFile(const String &path, uint32_t mask, File *pStartNode=0)
Definition: VFS.cc:312
void setModifiedTime(Time::Timestamp t)
Definition: File.cc:405
virtual char getLedState()
Definition: Keyboard.cc:25
MemoryMappedObject * mapFile(File *pFile, uintptr_t &address, size_t length, MemoryMappedObject::Permissions perms, size_t offset=0, bool bCopyOnWrite=true)
bool remove(const String &path, File *pStartNode=0)
Definition: VFS.cc:423
virtual bool isSocket() const
Definition: File.cc:451
virtual bool isPipe() const
Definition: File.cc:441
void setTerminalMode(size_t n, struct vt_mode mode)
Definition: Log.h:140
virtual uint64_t read(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition: File.cc:116
KeymapEntry * getKeymapEntry(bool bCtrl, bool bShift, bool bAlt, bool bAltGr, uint8_t nCombinator, uint8_t keyCode)
Returns the keymap entry corresponding to given keycode and modifiers.
String getName() const
Definition: File.cc:411
Process * getParent() const
Definition: Thread.h:181
Time::Timestamp getModifiedTime()
Definition: File.cc:400
virtual void truncate()
Definition: File.cc:568
Definition: Thread.h:54
virtual void getName(String &str)
Definition: Disk.cc:46
Definition: RamFs.h:86
Definition: DevFs.h:287
int fdflags
File descriptor flags (fcntl)
virtual ProcessType getType()
Definition: Process.h:259
bool addEphemeralFile(File *pFile)
Add an ephemeral file to the directory.
Definition: Directory.cc:159
IoEvent * ioevent
IO event for reporting changes to files.
#define ERROR(text)
Definition: Log.h:82
void setInterrupted(bool b)
Definition: Thread.h:235
static UserManager & instance()
Definition: UserManager.h:34
virtual void sync()
Definition: File.cc:351
FileDescriptor * getFileDescriptor(size_t fd)
virtual File * open()
Definition: File.cc:572
size_t getNumChildren()
Definition: Directory.cc:74
virtual bool isDirectory()
Definition: File.cc:436
File * getChild(size_t n)
Definition: Directory.cc:55
Definition: Log.h:138
Directory * getReparsePoint() const
Get the reparse point attached to this directory. Reparse points allow locations on the filesystem to...
Definition: Directory.cc:149
Definition: File.h:66
size_t remove(uintptr_t base, size_t length)
virtual File * findFile(const String &path, File *workingDir)
Device * getParent() const
Definition: Device.h:149
E lookup(const K &key) const
Definition: Tree.h:192
static Pipe * fromFile(File *pF)
Definition: Pipe.h:42
void setAccessedTime(Time::Timestamp t)
Definition: File.cc:394
Structure representing an entry in the keymap table.
Definition: KeymapManager.h:73
Definition: Pipe.h:35
Definition: Group.h:32
static bool checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)
Definition: VFS.cc:448
virtual uint64_t write(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition: File.cc:183
virtual void threadException(Thread *pThread, ExceptionType eType)
virtual File * getRoot() const =0