Softpanorama

May the source be with you, but remember the KISS principle ;-)
Home Switchboard Unix Administration Red Hat TCP/IP Networks Neoliberalism Toxic Managers
(slightly skeptical) Educational society promoting "Back to basics" movement against IT overcomplexity and  bastardization of classic Unix

Process control

News Recommended Books Recommended Links Reference shmmax The Unix File system  

From http://www.scit.wlv.ac.uk/~jphb/spos/notes/processes.html#basics

(disasspered from the web)

Basic Ideas

A process is an "invocation" or "activation" of a program. A program is a list of instructions for execution by a computer. A program may be stored in any convenient form including handwritten notes on pieces of paper but is most commmonly stored in binary form in a file. To run the program it needs to be copied (or loaded) into the main computer memory and the central processing unit told to start reading (and obeying) instructions taken from that area of memory. The acitvity of executing the program's instructions is called running the process.

It will be seen that a potion of memory needs to be allocated to a process. The actual allocation of such an area of memory is a task for the loader. The memory area allocated to a program will usually be split into several sub-areas for particular.

The code area

This is known as the text area in Unix parlance and simply contains the executable code of the program. If there are several processes running the same program there will still only be one code area as it is identical for all processes. The current state of a process is determined by its various data areas. The kernel process exchange (or switch) mechanism will activate a particular process by indicating to the hardware

The data area

This holds the data being processed by the program, it's size is initially determined by the loader from information in the binary file which specifies the amount of initialised data to be copied form the binary file and the amount of uninitialised space to be allocated to the process. On some systems the space may be initialised to zero but this is not universal and such areas may contain "droppings" left over from previous processes, a possible security problem. On older Unix systems the uninitialised space is known as bss from a PDP/11 assembler mnemonic.

The Unix size command will give the memory requirement information for a binary file.

bash$ size testhand2
92763 + 7564 + 2320 = 102647

The above example shows that loading the binary file testhand2 will require 102647 bytes of memory with 92763 bytes for code, 7564 bytes for initialised data and 2320 bytes for non-initialised data.

The stack area and the arena

All modern processors expect programs to be built out of functions and procedures. Whenever a function is called a stack frame is created to store data related to the current invocation of the function such as the return address, saved state, local copies of parameters and, of course, local data. The stack is normally built within the data area of the process and the memory allocated to the stack can be expanded as needed.

Dynamic memory allocation as supported by functions such as malloc will normally be in a separate area of memory known as the arena or the heap. It is also part of the processes data area and also expands as required.

The stack and the arena need to be kept separate from the initialised and uninitialised data areas, this is normally achieved by using widely separated parts of a large virtual address space.

System calls

A system call is a function like mechanism whereby a process can request services from the kernel. A system call includes a special instruction which causes a software interrupt (sometimes called a trap), responding to this interrupt switches the processer into kernel or priviliged mode whilst maintaining the process identity. The response also involves switching the stack pointer to the kernel stack so that any kernel functions that are called in response to the system call will use the kernel stack rather than the user stack.

It is interesting to note the overheads associated with handling a disc transfer completion interrupt are "charged" to the process that happens to be running when the interrupt occurs.

Process Information

There will, inevitably, be a significant amount of information about a process that is only relevant to the kernel. This will include data such as the process user-id (for access rights checks), pointers to open file information blocks, saved register states for processes not currently running, process "environment" etc., etc. Some of this information is stored in an entry in the process table which has an entry for every current process and some is stored in a per-process memory area called the u_area on Unix systems.

Details of the structure of a process table entry may be found in the file /usr/include/sys/proc.h and the u_area in the file /usr/include/sys/user.h.

Process states

Processes can only be created by the system call fork(), apart from process 1 which is "hand-crafted" at boot time and is the ultimate parent of all other processes. Once a process has been created it can be in various states as shown in the following diagram (based on Bach).

As shown above, aprocess can be in any one of nine distinct states.
  1. Created

    A freshly created process. Whether freshly created processes are entirely resident in memory depends on the details of the memory management system. This state may also include processes that have not yet been fully created.

  2. Ready to run, in memory

    There is no reason why the process should not run apart from the fact that some other process is currently running.

  3. Running in kernel mode

    The process is running in kernel mode. It may be handling a system call or an interrupt or some other process (also in kernel mode) may have scheduled it to run. The process may determine that it has finished (either normally via an exit() or via some kernel detected abnormal condition) or that it is blocked awaiting some event such as a time signal or peripheral activity.

  4. Running in user mode

    The normal state.

  5. Pre-empted

    The process has been interrupted and is about to resume normal user mode operation. The kernel scheduler may move a process into this state.

  6. Zombie (or defunct)

    The process will not run again but information, such as the exit code, has not been collected by the parent process so a process table slot is still required to store this information.

  7. Sleeping in memory

    The process is blocked awaiting an event. All that can happen is that the process can be woken up (by changing its status to "ready to run") or swapped out.

  8. Sleeping, swapped out

    The process is waiting for an event (details in the process table entry for the process) and has been swapped out.

  9. Ready to run, swapped out

    Before running the process needs to copied back in to memory.

The concept of swapping implies that the entire memory image of a process is moved between backing storage (disc) and memory. Modern systems still maintain copies of process images in the swapping area but dynamic paged memory management automatically deals with the issues of moving page images between backing store and main memory resulting in a blurring of the distinction between "swapped out" and "in memory" processes.

Process Information

The Unix operating system supports a number of standard commands for determining information about the processes currently running on a computer. The most commonly used is undoubtedly 'ps', unfortunately this is one of the Unix commands that come in two flavours, one system V derived and one BSD derived. Which flavour you get when you type "ps" depends on your search path.

Here's some typical output from the BSD variant.

# ps -aguwwx | head -10
USER       PID %CPU %MEM   SZ  RSS TT       S    START  TIME COMMAND
root     12885  8.4  0.8 2152 1960 pts/0    O 15:18:19  0:01 ps -aguwwx
root         3  1.3  0.0    0    0 ?        S   Aug 12 1191:52 fsflush
ftp      12881  0.5  0.6 1884 1444 ?        S 15:18:13  0:00 in.ftpd -l
root       173  0.5 18.04866845928 ?        S   Aug 12 265:51 /usr/sbin/in.named
root       134  0.4  0.5 5248 1184 ?        S   Aug 12 611:21 /usr/multicast/mrouted
root     12884  0.2  0.2  744  528 pts/0    S 15:18:19  0:00 head -10
nobody   12751  0.2  0.9 3032 2208 ?        S 15:14:47  0:00 /appsy/apache_1.3.3/src/httpd -f /appsy/apache_1.3.3/etc/httpd.conf
nobody   12238  0.2  0.9 3032 2220 ?        S 14:59:11  0:01 /appsy/apache_1.3.3/src/httpd -f /appsy/apache_1.3.3/etc/httpd.conf
nobody   12695  0.2  0.9 3032 2224 ?        S 15:12:38  0:00 /appsy/apache_1.3.3/src/httpd -f /appsy/apache_1.3.3/etc/httpd.conf

The listing is in CPU usage order and has been trimmed to show the 10 most CPU intensive processes. Most of the column headings are fairly obvious, "SZ" is the combined size of the data and stack segments (in kbytes), "RSS" is the real memory used by the process. Some interesting points to note from the listing above.

For more information about processes the ps command may be used with the -l flag (meaning long listing), the processes are no longer listed in CPU usage order.

# ps -aglwx | head -15
 F   UID   PID  PPID CP PRI NI   SZ  RSS    WCHAN S TT        TIME COMMAND
19     0     0     0  0  96  0    0    0          T ?         0:00 sched
 8     0     1     0  0  58 20 1572  100 ufstrans S ?        25:02 /etc/init -
19     0     2     0  0  98  0    0    0  push_cv S ?         0:54 pageout
19     0     3     0  1  60  0    0    0 fsflush_ S ?        1242:51 fsflush
 8     0    19   390  0   0       0    0                   Z  0:00  
 8     0   131     1  0  58 20 1312  168 clnt_max S ?         5:04 /usr/sbin/in.rdisc -s
 8     0   134     1  1  58 20 5248 1120    zscom S ?        637:17 /usr/multicast/mrouted
 8     0   139     1  0  58 20 2248  680    zscom S ?        952:34 /usr/sbin/rpcbind
 8     0   141     1  0  58 20 1568  476    zscom S ?        289:10 /usr/sbin/keyserv
 8     0   147     1  0  58 20 1800  640    zscom S ?         1:14 /usr/sbin/nis_cachemgr
 8     0   149     1  0  31 20 1716    4    zscom S ?         0:00 /usr/sbin/kerbd
 8     0   173     1  0  58 204866845328    zscom S ?        280:57 /usr/sbin/in.named
 8     0   178     1  0  58 20 1764  524    zscom S ?         3:21 /usr/sbin/inetd -s
 8     0   181     1  0  59 20 1964  412    zscom S ?         0:07 /usr/lib/nfs/statd

This shows scheduling information (PRI (priority), NI (niceness) and CP (short-term CPU utilisation)), the nature of the event the process is waiting for (WCHAN) and process flags (F).

For full details consult the manual pages for the BSD version of ps and the System V version of ps. For more detailed and specialist information see the vmstat command.

Scheduling and Priorities

When there are several runnable processes available, the next one to be run will usually be selected on a priority basis. The prioirty is a function of the process history and a user manipulable parameter known as the niceness of the process, the higher the niceness, the lower the priority, the highest value is 20.

The command priocntl can be used to manipulate priorities. The command nice can be used to launch a process at a specified priority and renice can be used to modify the niceness of an existing process. Unless you are super-user you can only decrease the niceness of a process.


Top Visited
Switchboard
Latest
Past week
Past month

NEWS CONTENTS

Old News ;-)

[Jan 12, 2011] Fork, Exec and Process control

fork():

The fork() system call will spawn a new child process which is an identical process to the parent except that has a new system process ID. The process is copied in memory from the parent and a new process structure is assigned by the kernel. The return value of the function is which discriminates the two threads of execution. A zero is returned by the fork function in the child's process.

The environment, resource limits, umask, controlling terminal, current working directory, root directory, signal masks and other process resources are also duplicated from the parent in the forked child process.

Example:

print?

01 #include <iostream>
02 #include <string>
03
04 // Required by for routine
05 #include <sys/types.h>
06 #include <unistd.h>
07
08 #include <stdlib.h> // Declaration for exit()
09
10 using namespace std;
11
12 int globalVariable = 2;
13
14 main()
15 {
16 string sIdentifier;
17 int iStackVariable = 20;
18
19 pid_t pID = fork();
20 if (pID == 0) // child
21 {
22 // Code only executed by child process
23
24 sIdentifier = "Child Process: ";
25 globalVariable++;
26 iStackVariable++;
27 }
28 else if (pID < 0) // failed to fork
29 {
30 cerr << "Failed to fork" << endl;
31 exit(1);
32 // Throw exception
33 }
34 else // parent
35 {
36 // Code only executed by parent process
37
38 sIdentifier = "Parent Process:";
39 }
40
41 // Code executed by both parent and child.
42
43 cout << sIdentifier;
44 cout << " Global variable: " << globalVariable;
45 cout << " Stack variable: " << iStackVariable << endl;
46 }

Compile: g++ -o ForkTest ForkTest.cpp
Run: ForkTest

Parent Process: Global variable: 2 Stack variable: 20
Child Process:  Global variable: 3 Stack variable: 21

[Potential Pitfall]: Some memory duplicated by a forked process such as file pointers, will cause intermixed output from both processes. Use the wait() function so that the processes do not access the file at the same time or open unique file descriptors. Some like stdout or stderr will be shared unless synchronized using wait() or some other mechanism. The file close on exit is another gotcha. A terminating process will close files before exiting. File locks set by the parent process are not inherited by the child process.

[Potential Pitfall]: Race conditions can be created due to the unpredictability of when the kernel scheduler runs portions or time slices of the process. One can use wait(). the use of sleep() does not guarentee reliability of execution on a heavily loaded system as the scheduler behavior is not predictable by the application.

Note on exit() vs _exit(): The C library function exit() calls the kernel system call _exit() internally. The kernel system call _exit() will cause the kernel to close descriptors, free memory, and perform the kernel terminating process clean-up. The C library function exit() call will flush I/O buffers and perform aditional clean-up before calling _exit() internally. The function exit(status) causes the executable to return "status" as the return code for main(). When exit(status) is called by a child process, it allows the parent process to examine the terminating status of the child (if it terminates first). Without this call (or a call from main() to return()) and specifying the status argument, the process will not return a value.

#include <stdlib.h>

void exit(int status);
                
#include <unistd.h>

void _exit(int status);
                

Man Pages:


vfork():

The vfork() function is the same as fork() except that it does not make a copy of the address space. The memory is shared reducing the overhead of spawning a new process with a unique copy of all the memory. This is typically used when using fork() to exec() a process and terminate. The vfork() function also executes the child process first and resumes the parent process when the child terminates.

view source

print?
01 #include <iostream>
02 #include <string>
03
04 // Required by for routine
05 #include <sys/types.h>
06 #include <unistd.h>
07
08 using namespace std;
09
10
11 int globalVariable = 2;
12
13 main()
14 {
15 string sIdentifier;
16 int iStackVariable = 20;
17
18 pid_t pID = vfork();
19 if (pID == 0) // child
20 {
21 // Code only executed by child process
22
23 sIdentifier = "Child Process: ";
24 globalVariable++;
25 iStackVariable++;
26 cout << sIdentifier;
27 cout << " Global variable: " << globalVariable;
28 cout << " Stack variable: " << iStackVariable << endl;
29 _exit(0);
30 }
31 else if (pID < 0) // failed to fork
32 {
33 cerr << "Failed to fork" << endl;
34 exit(1);
35 // Throw exception
36 }
37 else // parent
38 {
39 // Code only executed by parent process
40
41 sIdentifier = "Parent Process:";
42 }
43
44 // executed only by parent
45
46 cout << sIdentifier;
47 cout << " Global variable: " << globalVariable;
48 cout << " Stack variable: " << iStackVariable << endl;
49 exit(0);
50 }

Compile: g++ -o VForkTest VForkTest.cpp
Run: VForkTest

Child Process:  Global variable: 3 Stack variable: 21
Parent Process: Global variable: 3 Stack variable: 21
                
Note: The child process executed first, updated the variables which are shared between the processes and NOT unique, and then the parent process executes using variables which the child has updated.

[Potential Pitfall]: A deadlock condition may occur if the child process does not terminate, the parent process will not proceed.

Man Pages:


clone():

The function clone() creates a new child process which shares memory, file descriptors and signal handlers with the parent. It implements threads and thus launches a function as a child. The child terminates when the parent terminates.
See the YoLinux POSIX threads tutorial

Man Pages:


wait():

The parent process will often want to wait until all child processes have been completed. this can be implemented with the wait() function call.

wait(): Blocks calling process until the child process terminates. If child process has already teminated, the wait() call returns immediately. if the calling process has multiple child processes, the function returns when one returns.

waitpid(): Options available to block calling process for a particular child process not the first one.

Code snipet:
view source

print?
01 #include <sys/wait.h>
02
03 ...
04
05 pid_t pID = <I>set to child process id with call to fork OR:</I>
06 // If set <-1, wait for any child process whose process group ID = abs(pID)
07 // If = -1, wait for any child process. Same as wait().
08 // If = 0, wait for any child process whose process group ID is same as calling process.
09 // If > 0, wait for the child whose process ID = pID.
10
11 ...
12 int childExitStatus;
13
14 pid_t ws = waitpid( pID, &childExitStatus, WNOHANG);
15
16 if( WIFEXITED(childExitStatus) )
17 {
18 // Child process exited thus exec failed.
19 // LOG failure of exec in child process.
20 cout << "Result of waitpid: Child process exited thus exec failed." << endl;
21 }
OR
view source

print?
01 ...
02 int childExitStatus;
03 pid_t ws = waitpid( pID, &childExitStatus, 0);
04 if( !WIFEXITED(childExitStatus) )
05 {
06 cerr << "waitpid() exited with an error: Status= "
07 << WEXITSTATUS(childExitStatus)
08 << endl;
09 }
10 else if( WIFSIGNALED(childExitStatus) )
11 {
12 cerr << "waitpid() exited due to a signal: "
13 << WTERMSIG(childExitStatus)
14 << endl;
15 }
Notes:

Man Pages:


Set system group ID and process ID:

Avoids orphaned process group when parent terminates. When parent dies, this will be a zombie. (No parent process. Parent=1) Instead, create a new process group for the child. Later process the group is terminated to stop all spawned processes. Thus all subsequent processes should be of this group if they are to be terminated by the process group id. Process group leader has the same process id and group process id. If not changed then the process group is that of the parent. Set the process group id to that of the child process.

view source

print?
01 #include <sys/types.h>
02 #include <unistd.h>
03
04 #ifdef __gnu_linux__
05 pid_t pgid = setpgid(child_pID, child_pID);
06 #endif
07
08 ...
09 ...
10
11 if( pgid < 0)
12 {
13 cout << "Failed to set process group ID" << endl;
14 _exit(0); // If exec fails then exit forked process.
15 }
Use the setgid call to set the group id of the current process. Requires root access.

The macro testing for __gnu_linux__ is for cross platform support as man other OS's use a different system call.

Man Pages:


Kill all processes in a process group:

This is the real reason to set up a process group. One may kill all the processes in the process group without having to keep track of how many processes have been forked and all of their process id's.

See /usr/include/bits/signum.h for list of signals.

view source

print?
01 ...
02 int killReturn = killpg( pID, SIGKILL); // Kill child process group
03 if( killReturn == ESRCH) // pid does not exist
04 {
05 cout << "Group does not exist!" << endl;
06 }
07 else if( killReturn == EPERM) // No permission to send signal
08 {
09 cout << "No permission to send signal!" << endl;
10 }
11 else
12 cout << "Signal sent. All Ok!" << endl;
13 ...
Man Pages:
system() and popen():

The system() call will execute an OS shell command as described by a character command string. This function is implemented using fork(), exec() and waitpid(). The command string is executed by calling /bin/sh -c command-string. During execution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored. The call "blocks" and waits for the task to be performed before continuing.

view source

print?
1 #include <stdio.h>
2 #include <stdlib.h>
3 main()
4 {
5 system("ls -l");
6 printf("Command done!");
7 }
The statement "Command done!" will not print untill the "ls -l" command has completed.

The popen() call opens a process by creating a pipe, forking, and invoking the shell (bourne shell on Linux). The advantage to using popen() is that it will allow one to interrogate the results of the command issued.

This example opens a pipe which executes the shell command "ls -l". The results are read and printed out.

view source

print?
01 #include <stdio.h>
02 main()
03 {
04 FILE *fpipe;
05 char *command="ls -l";
06 char line[256];
07
08 if ( !(fpipe = (FILE*)popen(command,"r")) )
09 { // If fpipe is NULL
10 perror("Problems with pipe");
11 exit(1);
12 }
13
14 while ( fgets( line, sizeof line, fpipe))
15 {
16 printf("%s", line);
17 }
18 pclose(fpipe);
19 }

The second argument to popen:

Man Pages:


exec() functions and execve():

The exec() family of functions will initiate a program from within a program. They are also various front-end functions to execve().

The functions return an integer error code. (0=Ok/-1=Fail).


execl() and execlp():

The function call "execl()" initiates a new program in the same environment in which it is operating. An executable (with fully qualified path. i.e. /bin/ls) and arguments are passed to the function. Note that "arg0" is the command/file name to execute.

int execl(const char *path, const char *arg0, const char *arg1, const char *arg2, ... const char *argn, (char *) 0);

view source

print?
1 #include <unistd.h>
2 main()
3 {
4 execl("/bin/ls", "/bin/ls", "-r", "-t", "-l", (char *) 0);
5 }
Where all function arguments are null terminated strings. The list of arguments is terminated by NULL.

The routine execlp() will perform the same purpose except that it will use environment variable PATH to determine which executable to process. Thus a fully qualified path name would not have to be used. The first argument to the function could instead be "ls". The function execlp() can also take the fully qualified name as it also resolves explicitly.

Man Pages:


execv() and execvp():

This is the same as execl() except that the arguments are passed as null terminated array of pointers to char. The first element "argv[0]" is the command name.

int execv(const char *path, char *const argv[]);

view source

print?
1 #include <unistd.h>
2 main()
3 {
4 char *args[] = {"/bin/ls", "-r", "-t", "-l", (char *) 0 };
5
6 execv("/bin/ls", args);
7 }
The routine execvp() will perform the same purpose except that it will use environment variable PATH to determine which executable to process. Thus a fully qualified path name would not have to be used. The first argument to the function could instead be "ls". The function execvp() can also take the fully qualified name as it also resolves explicitly.

Man Pages:


execve():

The function call "execve()" executes a process in an environment which it assigns.

Set the environment variables:

Assignment:

   char *env[] = { "USER=user1", "PATH=/usr/bin:/bin:/opt/bin", (char *) 0 };
                

OR

Read from file:

view source

print?
01 #include <iostream>
02 #include <fstream>
03 #include <string>
04 #include <vector>
05
06 // Required by for routine
07 #include <sys/types.h>
08 #include <unistd.h>
09
10 using namespace std;
11
12 // Class definition:
13
14 class CReadEnvironmentVariablesFile
15 {
16 public:
17 CReadEnvironmentVariablesFile() { m_NumberOfEnvironmentVariables=0; };
18 ~CReadEnvironmentVariablesFile();
19 char **ReadFile(string& envFile);
20 private:
21 int m_NumberOfEnvironmentVariables;
22 char **m_envp;
23 };
24
25 // Read environment variables:
26
27 char **
28 CReadEnvironmentVariablesFile::ReadFile(string& envFile)
29 {
30 int ii;
31 string tmpStr;
32 vector<string> vEnvironmentVariables;
33
34 if( envFile.empty() ) return 0;
35
36 ifstream inputFile( envFile.c_str(), ios::in);
37 if( !inputFile )
38 {
39 cerr << "Could not open config file: " << envFile << endl;
40 return 0;
41 }
42
43 while( !inputFile.eof() )
44 {
45 getline(inputFile, tmpStr);
46 if( !tmpStr.empty() ) vEnvironmentVariables.push_back(tmpStr);
47 }
48
49 inputFile.close();
50
51 m_NumberOfEnvironmentVariables = vEnvironmentVariables.size();
52
53 // ---------------------------------------
54 // Generate envp environment variable list
55 // ---------------------------------------
56
57 // Allocate pointers to strings.
58 // +1 for array terminating NULL string
59
60 m_envp = new char * [m_NumberOfEnvironmentVariables + 1];
61
62 // Allocate arrays of character strings.
63
64 for(ii=0; ii < m_NumberOfEnvironmentVariables; ii++)
65 {
66 // Character string terminated with a NULL character.
67 m_envp[ii] = new char [vEnvironmentVariables[ii].size()+1];
68 strcpy( m_envp[ii], vEnvironmentVariables[ii].c_str());
69 }
70
71 // must terminate array with null string
72 m_envp[ii] = (char*) 0;
73
74 return m_envp;
75 }
76
77 // Free memory:
78
79 CReadEnvironmentVariablesFile::~CReadEnvironmentVariablesFile()
80 {
81 int ii;
82
83 // Free array's of characters
84 for(ii=0; ii < m_NumberOfEnvironmentVariables; ii++)
85 {
86 delete [] m_envp[ii];
87 }
88
89 // Free array of pointers.
90 delete [] m_envp;
91 }

Call execve:

view source

print?
01 string getErrMsg(int errnum);
02
03 main()
04 {
05 string envFile("environment_variables.conf");
06 CReadEnvironmentVariablesFile readEnvFile;
07 char **Env_envp = readEnvFile.ReadFile(envFile);
08
09 // Command to execute
10 char *Env_argv[] = { "/bin/ls", "-l", "-a", (char *) 0 };
11
12 pid_t pID = fork();
13 if (pID == 0) // child
14 {
15 // This version of exec accepts environment variables.
16 // Function call does not return on success.
17
18 int execReturn = execve (Env_argv[0], Env_argv, Env_envp);
19
20 cout << "Failure! execve error code=" << execReturn << endl;
21
22 cout << getErrMsg(execReturn) << endl;
23
24 _exit(0); // If exec fails then exit forked process.
25 }
26 else if (pID < 0) // failed to fork
27 {
28 cerr << "Failed to fork" << endl;
29 }
30 else // parent
31 {
32 cout << "Parent Process" << endl;
33 }
34 }

Handle errors:

view source

print?
001 string getErrMsg(int errnum)
002 {
003
004 switch ( errnum ) {
005
006 #ifdef EACCES
007 case EACCES :
008 {
009 return "EACCES Permission denied";
010 }
011 #endif
012
013 #ifdef EPERM
014 case EPERM :
015 {
016 return "EPERM Not super-user";
017 }
018 #endif
019
020 #ifdef E2BIG
021 case E2BIG :
022 {
023 return "E2BIG Arg list too long";
024 }
025 #endif
026
027 #ifdef ENOEXEC
028 case ENOEXEC :
029 {
030 return "ENOEXEC Exec format error";
031 }
032 #endif
033
034 #ifdef EFAULT
035 case EFAULT :
036 {
037 return "EFAULT Bad address";
038 }
039 #endif
040
041 #ifdef ENAMETOOLONG
042 case ENAMETOOLONG :
043 {
044 return "ENAMETOOLONG path name is too long ";
045 }
046 #endif
047
048 #ifdef ENOENT
049 case ENOENT :
050 {
051 return "ENOENT No such file or directory";
052 }
053 #endif
054
055 #ifdef ENOMEM
056 case ENOMEM :
057 {
058 return "ENOMEM Not enough core";
059 }
060 #endif
061
062 #ifdef ENOTDIR
063 case ENOTDIR :
064 {
065 return "ENOTDIR Not a directory";
066 }
067 #endif
068
069 #ifdef ELOOP
070 case ELOOP :
071 {
072 return "ELOOP Too many symbolic links";
073 }
074 #endif
075
076 #ifdef ETXTBSY
077 case ETXTBSY :
078 {
079 return "ETXTBSY Text file busy";
080 }
081 #endif
082
083 #ifdef EIO
084 case EIO :
085 {
086 return "EIO I/O error";
087 }
088 #endif
089
090 #ifdef ENFILE
091 case ENFILE :
092 {
093 return "ENFILE Too many open files in system";
094 }
095 #endif
096
097 #ifdef EINVAL
098 case EINVAL :
099 {
100 return "EINVAL Invalid argument";
101 }
102 #endif
103
104 #ifdef EISDIR
105 case EISDIR :
106 {
107 return "EISDIR Is a directory";
108 }
109 #endif
110
111 #ifdef ELIBBAD
112 case ELIBBAD :
113 {
114 return "ELIBBAD Accessing a corrupted shared lib";
115 }
116 #endif
117
118 default :
119 {
120 std::string errorMsg(strerror(errnum));
121 if ( errnum ) return errorMsg;
122 }
123 }
124 }

Man Pages:

Data File: environment_variables.conf

PATH=/usr/bin:/bin
MANPATH=/opt/man
LANG=C
DISPLAY=:0.0

Man Pages:


Note: Don't mix malloc() and new. Choose one form of memory allocation and stick with it.

Malloc:

view source

print?
01 ..
02 ...
03
04 int ii;
05
06 m_envp = (char **) calloc((m_NumberOfEnvironmentVariables+1), sizeof(char **));
07
08 ...
09 // Allocate arrays of character strings.
10 int ii;
11 for(ii=0; ii < NumberOfEnvironmentVariables; ii++)
12 {
13 // NULL terminated
14 m_envp[ii] = (char *) malloc(vEnvironmentVariables[ii].size()+1);
15 strcpy( m_envp[ii], vEnvironmentVariables[ii].c_str());
16 }
17
18 // must terminate with null
19 m_envp[ii] = (char*) 0;
20
21 return m_envp;
22 }
23 ...
Free:
view source

print?
1 ...
2 // Free array's of characters
3 for(ii=0; ii < m_NumberOfEnvironmentVariables; ii++)
4 {
5 free(m_envp[ii]);
6 }
7 // Free array of pointers.
8 free(m_envp);
9 ...

Man Pages:

File System Information in Linux

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 ([email protected]) (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



Etc

Society

Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers :   Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism  : The Iron Law of Oligarchy : Libertarian Philosophy

Quotes

War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda  : SE quotes : Language Design and Programming Quotes : Random IT-related quotesSomerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose BierceBernard Shaw : Mark Twain Quotes

Bulletin:

Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 :  Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method  : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law

History:

Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds  : Larry Wall  : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOSProgramming Languages History : PL/1 : Simula 67 : C : History of GCC developmentScripting Languages : Perl history   : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history

Classic books:

The Peter Principle : Parkinson Law : 1984 : The Mythical Man-MonthHow to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Hater’s Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite

Most popular humor pages:

Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor

The Last but not Least Technology is dominated by two types of people: those who understand what they do not manage and those who manage what they do not understand ~Archibald Putt. Ph.D


Copyright © 1996-2021 by Softpanorama Society. www.softpanorama.org was initially created as a service to the (now defunct) UN Sustainable Development Networking Programme (SDNP) without any remuneration. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.

This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...

You can use PayPal to to buy a cup of coffee for authors of this site

Disclaimer:

The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the Softpanorama society. We do not warrant the correctness of the information provided or its fitness for any purpose. The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.

Last modified: March 12, 2019