The Pedigree Project  0.1
ProcFs.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 "ProcFs.h"
21 
22 #include "modules/system/users/Group.h"
23 #include "modules/system/users/User.h"
24 #include "pedigree/kernel/BootstrapInfo.h"
25 #include "pedigree/kernel/LockGuard.h"
26 #include "pedigree/kernel/Version.h"
27 #include "pedigree/kernel/machine/Device.h"
28 #include "pedigree/kernel/processor/Processor.h"
29 #include "pedigree/kernel/time/Time.h"
30 
31 #include "file-syscalls.h"
32 
33 #include "PosixProcess.h"
34 
36 extern size_t g_FreePages;
37 extern size_t g_AllocedPages;
38 
39 MeminfoFile::MeminfoFile(size_t inode, Filesystem *pParentFS, File *pParent)
40  : File(String("meminfo"), 0, 0, 0, inode, pParentFS, 0, pParent),
41  m_pUpdateThread(0), m_bRunning(false), m_Contents(), m_Lock(false)
42 {
43  setPermissionsOnly(FILE_UR | FILE_UW | FILE_GR | FILE_GW | FILE_OR);
44  setUidOnly(0);
45  setGidOnly(0);
46 
47  m_bRunning = true;
48  m_pUpdateThread = new Thread(
49  Processor::information().getCurrentThread()->getParent(), run, this);
50 }
51 
52 MeminfoFile::~MeminfoFile()
53 {
54  m_bRunning = false;
55  m_pUpdateThread->join();
56 }
57 
58 size_t MeminfoFile::getSize()
59 {
60  LockGuard<Mutex> guard(m_Lock);
61  return m_Contents.length();
62 }
63 
64 int MeminfoFile::run(void *p)
65 {
66  MeminfoFile *pFile = reinterpret_cast<MeminfoFile *>(p);
67  pFile->updateThread();
68  return 0;
69 }
70 
71 void MeminfoFile::updateThread()
72 {
73  while (m_bRunning)
74  {
75  m_Lock.acquire();
76  uint64_t freeKb = (g_FreePages * 4096) / 1024; // each page is 4K
77  uint64_t allocKb = (g_AllocedPages * 4096) / 1024; // each page is 4K
78  m_Contents.Format(
79  "MemTotal: %ld kB\nMemFree: %ld kB\nMemAvailable: %ld kB\n",
80  freeKb + allocKb, freeKb, freeKb);
81  m_Lock.release();
82 
83  Time::delay(1 * Time::Multiplier::Second);
84  }
85 }
86 
88  uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock)
89 {
90  LockGuard<Mutex> guard(m_Lock);
91 
92  if (location >= m_Contents.length())
93  {
94  return 0; // EOF
95  }
96  else if ((location + size) > m_Contents.length())
97  {
98  size = m_Contents.length() - location;
99  }
100 
101  char *destination = reinterpret_cast<char *>(buffer);
102  const char *source = static_cast<const char *>(m_Contents);
103 
104  StringCopy(destination, source);
105 
106  return size;
107 }
108 
110  uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock)
111 {
112  return 0;
113 }
114 
115 PciDevicesFile::PciDevicesFile(
116  size_t inode, Filesystem *pParentFS, File *pParent)
117  : File(String("devices"), 0, 0, 0, inode, pParentFS, 0, pParent),
118  m_Contents()
119 {
120  setPermissionsOnly(FILE_UR | FILE_UW | FILE_GR | FILE_GW | FILE_OR);
121  setUidOnly(0);
122  setGidOnly(0);
123 
124  resync();
125 }
126 
127 PciDevicesFile::~PciDevicesFile()
128 {
129 }
130 
131 size_t PciDevicesFile::getSize()
132 {
133  return m_Contents.length();
134 }
135 
137  uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock)
138 {
139  resync();
140 
141  if (location >= m_Contents.length())
142  {
143  return 0; // EOF
144  }
145  else if ((location + size) > m_Contents.length())
146  {
147  size = m_Contents.length() - location;
148  }
149 
150  char *destination = reinterpret_cast<char *>(buffer);
151  const char *source = static_cast<const char *>(m_Contents);
152 
153  StringCopy(destination, source);
154 
155  return size;
156 }
157 
159  uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock)
160 {
161  return 0;
162 }
163 
165 {
166  m_Contents = String();
167 
168  auto printer = [this](Device *p) -> Device * {
169  String initial;
170  initial.Format(
171  "%02x%02x\t%04x%04x\t%x", p->getPciBusPosition(),
172  (p->getPciDevicePosition() << 4) | p->getPciFunctionNumber(),
173  p->getPciVendorId(), p->getPciDeviceId(), p->getInterruptNumber());
174 
175  String resStart;
176  String resLength;
177  for (size_t i = 0; i < 7; ++i)
178  {
179  String thisResStart;
180  String thisResLength;
181 
182  if (i < p->addresses().count())
183  {
184  size_t length = p->addresses()[i]->m_Size;
185 
186  uintptr_t address = p->addresses()[i]->m_Address;
187  uintptr_t flags = 0;
188  if (p->addresses()[i]->m_IsIoSpace)
189  {
190  flags = 1;
191  }
192 
194  thisResStart.Format("\t%16lx", address | flags);
195  thisResLength.Format("\t%16lx", length ? length + 1 : 0);
196  }
197  else
198  {
199  thisResStart.Format("\t%16lx", 0);
200  thisResLength.Format("\t%16lx", 0);
201  }
202 
203  resStart += thisResStart;
204  resLength += thisResLength;
205  }
206 
207  m_Contents += initial;
208  m_Contents += resStart;
209  m_Contents += resLength;
210  m_Contents += "\t";
211  m_Contents += "\n";
212 
213  return p;
214  };
215 
216  auto callback = pedigree_std::make_callable(printer);
217  Device::foreach (callback, nullptr);
218 }
219 
220 MountFile::MountFile(size_t inode, Filesystem *pParentFS, File *pParent)
221  : File(String("mounts"), 0, 0, 0, inode, pParentFS, 0, pParent)
222 {
223  setPermissionsOnly(FILE_UR | FILE_GR | FILE_OR);
224  setUidOnly(0);
225  setGidOnly(0);
226 }
227 
228 MountFile::~MountFile() = default;
229 
231  uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock)
232 {
233  String mounts;
234  generate_mtab(mounts);
235 
236  if (location >= mounts.length())
237  {
238  // "EOF"
239  return 0;
240  }
241 
242  if ((location + size) >= mounts.length())
243  {
244  size = mounts.length() - location;
245  }
246 
247  char *destination = reinterpret_cast<char *>(buffer);
248  StringCopyN(
249  destination, static_cast<const char *>(mounts) + location, size);
250 
251  return size;
252 }
253 
255  uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock)
256 {
257  return 0;
258 }
259 
260 size_t MountFile::getSize()
261 {
262  String mounts;
263  generate_mtab(mounts);
264  return mounts.length();
265 }
266 
267 UptimeFile::UptimeFile(size_t inode, Filesystem *pParentFS, File *pParent)
268  : File(String("uptime"), 0, 0, 0, inode, pParentFS, 0, pParent)
269 {
270  setPermissionsOnly(FILE_UR | FILE_GR | FILE_OR);
271  setUidOnly(0);
272  setGidOnly(0);
273 }
274 
275 UptimeFile::~UptimeFile() = default;
276 
278  uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock)
279 {
280  String f = generateString();
281 
282  if (location >= f.length())
283  {
284  // "EOF"
285  return 0;
286  }
287 
288  if ((location + size) >= f.length())
289  {
290  size = f.length() - location;
291  }
292 
293  char *destination = reinterpret_cast<char *>(buffer);
294  StringCopyN(destination, static_cast<const char *>(f) + location, size);
295 
296  return size;
297 }
298 
300  uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock)
301 {
302  return 0;
303 }
304 
305 size_t UptimeFile::getSize()
306 {
307  String f = generateString();
308  return f.length();
309 }
310 
311 String UptimeFile::generateString()
312 {
313  Timer *pTimer = Machine::instance().getTimer();
314  uint64_t uptime = pTimer->getTickCount();
315 
316  String f;
317  f.Format("%d.0 0.0", uptime);
318 
319  return f;
320 }
321 
322 ConstantFile::ConstantFile(
323  String name, const char *value, size_t size, size_t inode,
324  Filesystem *pParentFS, File *pParent)
325  : File(name, 0, 0, 0, inode, pParentFS, 0, pParent), m_Contents()
326 {
327  setPermissionsOnly(FILE_UR | FILE_UW | FILE_GR | FILE_GW | FILE_OR);
328  setUidOnly(0);
329  setGidOnly(0);
330 
331  m_Contents = new char[size];
332  m_Size = size;
333  MemoryCopy(m_Contents, value, size);
334 }
335 
336 ConstantFile::~ConstantFile()
337 {
338  delete[] m_Contents;
339 }
340 
342  uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock)
343 {
344  if (location >= m_Size)
345  {
346  return 0; // EOF
347  }
348  else if ((location + size) > m_Size)
349  {
350  size = m_Size - location;
351  }
352 
353  char *destination = reinterpret_cast<char *>(buffer);
354  const char *source = m_Contents + location;
355 
356  MemoryCopy(destination, source, size);
357 
358  return size;
359 }
360 
362  uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock)
363 {
364  return 0;
365 }
366 
367 size_t ConstantFile::getSize()
368 {
369  return m_Size;
370 }
371 
372 ProcFsDirectory::~ProcFsDirectory() = default;
373 
374 ProcFs::~ProcFs()
375 {
376  delete m_pRoot;
377 }
378 
380 {
381  // Deterministic inode assignment to each ProcFs node
382  m_NextInode = 0;
383 
384  if (m_pRoot)
385  {
386  delete m_pRoot;
387  }
388 
389  m_pRoot =
390  new ProcFsDirectory(String(""), 0, 0, 0, getNextInode(), this, 0, 0);
391  // Allow user/group to read and write, but disallow all others anything
392  // other than the ability to list and access files.
393  m_pRoot->setPermissions(
394  FILE_UR | FILE_UW | FILE_UX | FILE_GR | FILE_GW | FILE_GX | FILE_OR |
395  FILE_OX);
396 
397  // dot entry
399  Directory *dot = new ProcFsDirectory(
400  String("."), 0, 0, 0, m_pRoot->getInode(), this, 0, 0);
401  dot->setPermissions(m_pRoot->getPermissions());
402  m_pRoot->addEntry(dot->getName(), dot);
403 
404  MeminfoFile *meminfo = new MeminfoFile(getNextInode(), this, m_pRoot);
405  m_pRoot->addEntry(meminfo->getName(), meminfo);
406 
408  MountFile *mounts = new MountFile(getNextInode(), this, m_pRoot);
409  m_pRoot->addEntry(mounts->getName(), mounts);
410 
411  UptimeFile *uptime = new UptimeFile(getNextInode(), this, m_pRoot);
412  m_pRoot->addEntry(uptime->getName(), uptime);
413 
414  String fs("\text2\nnodev\tproc\nnodev\ttmpfs\n");
415  ConstantFile *pFilesystems = new ConstantFile(
416  String("filesystems"), fs, fs.length(), getNextInode(), this, m_pRoot);
417  m_pRoot->addEntry(pFilesystems->getName(), pFilesystems);
418 
419  // Kernel command line
420  String cmdline; //(g_pBootstrapInfo->getCommandLine());
421  cmdline = "noswap quiet boot=live\n";
422  NOTICE("cmdline is '" << cmdline << "'");
423  ConstantFile *pCmdline = new ConstantFile(
424  String("cmdline"), cmdline, cmdline.length(), getNextInode(), this,
425  m_pRoot);
426  m_pRoot->addEntry(pCmdline->getName(), pCmdline);
427 
428  // /proc/version contains some extra version info (not same as uname)
429  String version;
430  version.Format(
431  "Pedigree version %s (%s@%s) %s", g_pBuildRevision, g_pBuildUser,
432  g_pBuildMachine, g_pBuildTime);
433  ConstantFile *pVersion = new ConstantFile(
434  String("version"), version, version.length(), getNextInode(), this,
435  m_pRoot);
436  m_pRoot->addEntry(pVersion->getName(), pVersion);
437 
438  ProcFsDirectory *pBusDir = new ProcFsDirectory(
439  String("bus"), 0, 0, 0, getNextInode(), this, 0, m_pRoot);
440  ProcFsDirectory *pPciDir = new ProcFsDirectory(
441  String("pci"), 0, 0, 0, getNextInode(), this, 0, pBusDir);
442 
443  pBusDir->setPermissions(
444  FILE_UR | FILE_UX | FILE_GR | FILE_GX | FILE_OR | FILE_OX);
445  pPciDir->setPermissions(
446  FILE_UR | FILE_UX | FILE_GR | FILE_GX | FILE_OR | FILE_OX);
447 
448  m_pRoot->addEntry(pBusDir->getName(), pBusDir);
449  pBusDir->addEntry(pPciDir->getName(), pPciDir);
450 
451  // Load PCI devices into bus/pci/devices file
452  auto printer = [pPciDir, this](Device *p) -> Device * {
453  String bus;
454  bus.Format("%02x", p->getPciBusPosition());
455 
456  // create config space file for this
457  File *d = VFS::instance().find(bus, pPciDir);
458  if (!d)
459  {
460  ProcFsDirectory *dir = new ProcFsDirectory(
461  bus, 0, 0, 0, getNextInode(), this, 0, pPciDir);
462  pPciDir->addEntry(dir->getName(), dir);
463 
464  d = dir;
465  }
466 
467  ProcFsDirectory *dir =
468  static_cast<ProcFsDirectory *>(Directory::fromFile(d));
469 
470  String fn;
471  fn.Format(
472  "%02x.%01x", p->getPciDevicePosition(), p->getPciFunctionNumber());
473 
474  // Sometimes the device file already exists, avoid creating duplicate
475  // files
476  File *e = VFS::instance().find(fn, dir);
477  if (!e)
478  {
479  PciBus::ConfigSpace space = p->getPciConfigHeader();
480 
481  ConstantFile *cf = new ConstantFile(
482  fn, reinterpret_cast<const char *>(&space), sizeof(space),
483  getNextInode(), this, dir);
484  dir->addEntry(cf->getName(), cf);
485  }
486 
487  String initial;
488  initial.Format(
489  "%02x%02x\t%04x%04x\t%x", p->getPciBusPosition(),
490  (p->getPciDevicePosition() << 4) | p->getPciFunctionNumber(),
491  p->getPciVendorId(), p->getPciDeviceId(), p->getInterruptNumber());
492 
493  String resStart;
494  String resLength;
495  for (size_t i = 0; i < 7; ++i)
496  {
497  String thisResStart;
498  String thisResLength;
499 
500  if (i < p->addresses().count())
501  {
502  size_t length = p->addresses()[i]->m_Size;
503 
504  uintptr_t address = p->addresses()[i]->m_Address;
505  uintptr_t flags = 0;
506  if (p->addresses()[i]->m_IsIoSpace)
507  {
508  flags = 1;
509  }
510 
512  thisResStart.Format("\t%16lx", address | flags);
513  thisResLength.Format("\t%16lx", length ? length + 1 : 0);
514  }
515  else
516  {
517  thisResStart.Format("\t%16lx", 0);
518  thisResLength.Format("\t%16lx", 0);
519  }
520 
521  resStart += thisResStart;
522  resLength += thisResLength;
523  }
524 
525  m_PciDevices += initial;
526  m_PciDevices += resStart;
527  m_PciDevices += resLength;
528  m_PciDevices += "\t";
529  m_PciDevices += "\n";
530 
531  return p;
532  };
533 
534  auto callback = pedigree_std::make_callable(printer);
535  Device::foreach (callback, nullptr);
536 
537  ConstantFile *pPciDevices = new ConstantFile(
538  String("devices"), m_PciDevices, m_PciDevices.length(), getNextInode(),
539  this, pPciDir);
540  pPciDir->addEntry(pPciDevices->getName(), pPciDevices);
541 
542  return true;
543 }
544 
545 size_t ProcFs::getNextInode()
546 {
547  return m_NextInode++;
548 }
549 
550 void ProcFs::revertInode()
551 {
552  --m_NextInode;
553 }
554 
556 {
557  size_t pid = proc->getId();
558 
559  String s;
560  s.Format("%d", pid);
561 
562  auto procDir = new ProcFsDirectory(s, 0, 0, 0, getNextInode(), this, 0, 0);
563  procDir->setPermissions(
564  FILE_UR | FILE_UX | FILE_GR | FILE_GX | FILE_OR | FILE_OX);
565 
567  if (proc->getUser())
568  {
569  procDir->setUid(proc->getUser()->getId());
570  }
571  if (proc->getGroup())
572  {
573  procDir->setGid(proc->getGroup()->getId());
574  }
575 
576  m_pProcessDirectories.insert(pid, procDir);
577  m_pRoot->addEntry(procDir->getName(), procDir);
578 
580 }
581 
583 {
584  size_t pid = proc->getId();
585 
586  String s;
587  s.Format("%d", pid);
588 
591 
592  m_pRoot->remove(s);
593  m_pProcessDirectories.remove(pid);
594 }
File * find(const String &path, File *pStartNode=0)
Definition: VFS.cc:243
virtual uint64_t writeBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
Definition: ProcFs.cc:158
virtual bool initialise(Disk *pDisk)
Definition: ProcFs.cc:379
virtual uint64_t readBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
Definition: ProcFs.cc:341
size_t getId()
Definition: User.h:66
size_t getId()
Definition: Process.h:108
void removeProcess(PosixProcess *proc)
Definition: ProcFs.cc:582
virtual Timer * getTimer()=0
void resync()
Definition: ProcFs.cc:164
static Directory * fromFile(File *pF)
Definition: Directory.h:50
Definition: String.h:49
static ProcessorInformation & information()
Definition: Processor.cc:45
static VFS & instance()
Definition: VFS.cc:56
Definition: Disk.h:32
Definition: Device.h:43
virtual uint64_t writeBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
Definition: ProcFs.cc:109
virtual uint64_t readBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
Definition: ProcFs.cc:230
virtual uint64_t readBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
Definition: ProcFs.cc:136
virtual uint64_t getTickCount()=0
#define NOTICE(text)
Definition: Log.h:74
virtual uint64_t writeBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
Definition: ProcFs.cc:299
virtual uint64_t readBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
Definition: ProcFs.cc:87
Group * getGroup() const
Definition: Process.h:211
size_t m_Size
Definition: String.h:210
static void foreach(Callback callback, Device *root=0)
Definition: Device.cc:94
User * getUser() const
Definition: Process.h:189
String getName() const
Definition: File.cc:411
Definition: Thread.h:54
virtual uint64_t readBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
Definition: ProcFs.cc:277
size_t getId()
Definition: Group.h:51
Definition: File.h:66
virtual uint64_t writeBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
Definition: ProcFs.cc:254
void addProcess(PosixProcess *proc)
Definition: ProcFs.cc:555
virtual uint64_t writeBytewise(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true)
Definition: ProcFs.cc:361