# Combo of dup2 and execlp
---
###### tags: `C`
---
## Revision record
|version| comment | author |
|-------|--------------|--------|
|v0.1.0 |document built|Marco Ma|
|v0.1.1 | tag added |MArco Ma|
---
## Outline
* Introduction
* File descriptor
* dup2
* open(), close()
* open()
* close()
* execlp()
* Combo of open(), close(), dup2() and execlp()
---
## Introduction
Someday I was writing technical report, then I found something like this:
1. `main.c`
```cpp
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
int i;
for(i=0;i<10;i++){
close(i);
}
open("/dev/null",O_RDONLY);
int fd = open("./fd.txt", O_CREAT | O_WRONLY | O_APPEND ,0640);
dup2(1,2);
execlp("./log","./log",NULL);
}
```
2. `log.c`
```cpp
#include <stdio.h>
int main(){
fprintf(stderr,"Log: Not gonna end up in stderr.\n");
return 0;
}
```
After some data research and experiment. I finally notice that, when you execute `main.o`, the log in `log.c` is not gonna end up in standard error, but in `./fd.txt`.
---
## File descriptor
There's a file descriptor table in every process maintained by kernel. According to POSIX standard, there are three standard stream:
| fd |file pointer|
|-------|------------|
| 0 | STDIN |
| 1 | STDOUT |
| 2 | STDERR |
| 3 | NULL |
| 4 | NULL |
Generally, all user file will end up with `fd > 2`
| fd |file pointer|
|-------|------------|
| 0 | STDIN |
| 1 | STDOUT |
| 2 | STDERR |
| 3 | USER FILE1 |
| 4 | USER FILE2 |
---
## dup2 ---- duplicate a file descriptor
```cpp
int dup2(int oldfd, int newfd);
```
* oldfd: Source file descriptor
* newfd: Destination file descriptor
For example, assume we have a file descriptor table below:
| fd |file pointer|
|-------|------------|
| 0 | STDIN |
| 1 | STDOUT |
| 2 | STDERR |
after using
```cpp
dup2(0,1);
```
The file descriptor table will look like:
| fd |file pointer|
|-------|------------|
| 0 | STDIN |
| 1 | STDIN |
| 2 | STDERR |
---
## open(), close()
### open() ---- open or create a file.
```cpp
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
```
* pathname: The full path of the file
* flags: Define the way how system open file (Read only, write only, creat file .etc).
* mode_t: Permission of the file(ex. `0644` means `-rw-r--r--`)
### close() ---- close a file descriptor
```cpp
int close(int fd);
```
* fd: Target file descriptor
### Differents between open() and fopen()
---
`open()` have no buffer, system has to access file through storage(HDD, SSD .etc).
`fopen()` do have buffer, system does not have to access storage everytime.
---
`open()` is a POSIX standard function, which is not protable.
`fopen()` is a standard C library function, which is protable.
---
`open()` return a file descriptor, which is an `int`
`fopen()` return a file stream pointer, which is an `FILE *`
---
| |open()| fopen() |
|-------|------|----------------|
|buffer | NO | YES |
|library|POSIX |standard library|
|return | int | FILE * |
---
## execlp() ---- execute a file
```cpp
int execlp(const char *file, const char *arg, ...);
```
* file: File name of file need to execute
* arg: Arguments, the last argument must be `Null`
This function replace the current process image to the target process image.
## Combo of open(), close(), dup2() and execlp()
After all these function description, we can now back to `main.c` and `log.c`.
In the begining, we have a file descriptor table like this:
| fd |file pointer|
|-------|------------|
| 0 | STDIN |
| 1 | STDOUT |
| 2 | STDERR |
| 3 | NULL |
| 4 | NULL |
After the first few lines in `main.c`.
```cpp
int i;
for(i=0;i<10;i++){
close(i);
}
```
The table looks like this:
| fd |file pointer|
|-------|------------|
| 0 | NULL |
| 1 | NULL |
| 2 | NULL |
| 3 | NULL |
| 4 | NULL |
Yes, nothing inside, no man's land.
Then system starts to open file:
```cpp
open("/dev/null",O_RDONLY);
int fd = open("./fd.txt", O_CREAT | O_WRONLY | O_APPEND ,0640);
```
Now the table looks like this:
| fd |file pointer|
|-------|------------|
| 0 | /dev/null |
| 1 | ./fd.txt |
| 2 | NULL |
| 3 | NULL |
| 4 | NULL |
Then copy `fd==1` to `fd==2`
```cpp
dup2(1,2);
```
The new table becomes:
| fd |file pointer|
|-------|------------|
| 0 | /dev/null |
| 1 | ./fd.txt |
| 2 | ./fd.txt |
| 3 | NULL |
| 4 | NULL |
Finally we could execute `log`
```cpp
execlp("./log","./log",NULL);
```
Inside `log.c`
```cpp
#include <stdio.h>
int main(){
fprintf(stderr,"Log: Not gonna end up in stderr.\n");
return 0;
}
```
fprintf() has no idea that the file descirptor table has been changed, he printed the log to `fd = 2`, and that is not `stderr` anymore, it's `./fd.txt` now.
---
## printf() and fflush()