File System Information in Linux

Huican Ping Notes

 

In addition to process ID information, the process environment contains file system information. Every open file has an integer file descriptor value that the operating system uses as an index to a 1024-entry file descriptor table located in the u (user) area (see my previous notes: Process and Process Memory) for the process. The per-process file descriptor table references a system file table, which is located in kernel space. In turn, the system file table maps to a System Inode table that contains a reference to a more complete internal description of the file.

Fig1: Process/System file table relationships

 

Fork(): 

  When the fork system call is successful, fork returns the process ID of the child process to the parent process, and it returns a 0 to the child process. So a process can easily determine if it a parent or child process by checking the return value from fork.

  When a fork system call is made, the operating system generates a copy of the parent process, which becomes the child process. The OS passes to the child process most of the parent's system information (e.g. open file descriptors, environment information). However, some information is unique to the child process:

  1. The child has its own PID.

  2. The child has a different parent process ID (PPID) than its parent.

  3. System-imposed process limits are reset (amount of CPU time etc).

  4. All record locks on files are reset.

  5. The action to be taken when receiving signals is different.

Let's see a small example:

 

#include <iostream>

#include< sys/types.h>

#include<unistd.h>

using namespace std;

 

int main( )

{
cout << "Parent process \t PID " << getpid() << "\t PPID "<< endl;

if (fork( ) == 0) // Generate some processes
      cout << "Child process \t PID " << getpid()<< "\t PPID "<< endl;

 

cout<<"will return 2 times"<<endl;
return 0;

It is a straight-forward program and we notice that the PIDs are different and also the program will return 2 times, one is parent's and the other is child's.

 

File information:

There are a number of system calls that a process can use to obtain file information. The most useful one is "stat" system call. Its prototype is like this:

    int stat(const char *file_name, struct stat *buf)

 

The stat structure, which contains the following fields:
struct stat {
dev_t st_dev; /* device */
ino_t st_ino; /* inode */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device type (if inode device) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last change */
};

 


Here is a small program which use the stat call:

/*
Using the stat system call
*/
#include <iostream>
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
using namespace std;
const int N_BITS = 3;
int main(int argc, char *argv[ ])

{
unsigned int mask = 0700;
struct stat buff;
static char *perm[] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
if (argc > 1) {
    if ((stat(argv[1], &buff) != -1)) 

        {
           cout << "Permissions for " << argv[1] << " ";
           for (int i=3; i; --i) 

              {
              cout << perm[(buff.st_mode & mask) >> (i-1)*N_BITS];
              mask >>= N_BITS;
              }
        cout << endl;
       } 

  else 

      {
       perror(argv[1]);
      return 1;
     }
  }

else 

{
cerr << "Usage: " << argv[0] << " file_name\n";
return 2;
}
return 0;
}

 

The /proc filesystem

Linux implement a special virtual filesystem called /proc that stores information about the kernel, kernel data structures, and the state of each process and associated threads. Here in Linux a thread is implemented as a special type of process. 

 

The /proc filesystem is stored in memory, not on disk. The majority of the information provided is read-only and can vary greatly from one version of Linux to another. Standard system calls (such as open, read, etc.) can be used by programs to access /proc files. 

 

Linux provides a procinfo command that generates a formatted display of /proc information. The below is an example. We can see that it give us a lot of system information.

 

/home/pinghc>procinfo
Linux 2.4.18-14 (bhcompile@stripples.devel.redhat.com) (gcc 3.2 20020903 ) #1 1CPU [dminos2.(none)]

Memory: Total Used Free Shared Buffers Cached
Mem: 512420 395184 117236 0 114272 138116
Swap: 1132540 17956 1114584

Bootup: Thu May 29 00:36:02 2003 Load average: 2.46 2.05 1.20 2/67 10662

user : 13d 8:15:52.27 21.8% page in : 3510603 disk 1: 568211r 5991753w
nice : 2d 1:02:42.46 3.3% page out: 59347972
system: 1d 14:50:36.31 2.6% swap in : 5872
idle : 44d 6:07:58.23 72.2% swap out: 11973
uptime: 61d 6:17:09.00 context :2905550290

irq 0:2710030990 timer irq 9: 0 usb-uhci 
irq 1: 369868 keyboard irq 10: 10373237 usb-uhci, eth0 
irq 2: 0 cascade [4] irq 11: 0 usb-uhci, Intel ICH4 
irq 3: 0 ehci-hcd irq 12: 2699435 PS/2 Mouse 
irq 4: 3 irq 14: 6280674 ide0 
irq 6: 6 irq 15: 104263491 ide1 
irq 8: 2 rtc 

 

In the /proc file systam are a variety of data files and subdirectories. A typical /proc file sysmte is like this:

/home/pinghc>ls /proc
1 10513 2 3 3023 3032 7 891 dma ioports misc slabinfo
1016 10514 263 3002 3024 4 763 900 driver irq modules speakup
1017 10540 264 3005 3025 5 8 973 execdomains kcore mounts stat
1018 10558 2931 3010 3026 6 801 991 fb kmsg mtrr swaps
1019 10665 2989 3012 3027 642 815 apm filesystems ksyms net sys
1020 10676 2990 3015 3028 646 852 bus fs loadavg partitions sysvipc
1021 1073 2995 3017 30280 663 862 cmdline ide locks pci tty
1022 1074 2997 3019 3029 68 872 cpuinfo interrupts mdstat scsi uptime
10511 12 2999 3021 3030 682 881 devices iomem meminfo self version

One can see that Numerical entries, such as 1 or 3023, are process subdirectories for existing processes and contain information specific to the process. Nonnumeric entries, excluding the self entry, has kernel-related information. 

A wide array of data on each process is kept by the operating system. This data is found in the /proc directory in a decimal number subdirectory named for the process's ID. Each process subdirectory includes:

This is a example:

/proc/12>ls
ls: cannot read symbolic link cwd: Permission denied
ls: cannot read symbolic link root: Permission denied
ls: cannot read symbolic link exe: Permission denied
cmdline cwd environ exe fd maps mem mounts root stat statm status