I am studying in System Programming.
If we call open("/dev/fd/n", mode), we duplicate the n-th file descriptor and assign to a new file descriptor.
However, the mode we specify needs to be the subset of the referenced file (/dev/fd/n), and, I was wondering how is this working.
Does this create a new entry in the open file table?
If it does, why should the mode be a subset of /dev/fd/n's file status flag?
If not, how could I have two different file descriptor pointing to the same entry in file entry table with different file status flag?
When we open /dev/fd/n, we are not "duplicating" a file descriptor. We are opening a brand new file.
You may be confusing this with using dup. Since we know the binary value of n, we could do: int fdn = dup(n);. That would share things.
But, that is not what we're doing.
/dev/fd is a symlink to /proc/self/fd. If we do ls -l /proc/self/fd > /tmp/out, we'll get something like:
total 0
lrwx------. 1 cae cae 64 Nov 7 00:16 0 -> /dev/pts/2
l-wx------. 1 cae cae 64 Nov 7 00:16 1 -> /tmp/out
lrwx------. 1 cae cae 64 Nov 7 00:16 2 -> /dev/pts/2
lr-x------. 1 cae cae 64 Nov 7 00:16 3 -> /proc/35153/fd
If we do:
fd = open("/proc/self/0",O_WRONLY);
this is identical to doing:
fd2 = open("/dev/pts/2",O_WRONLY);
fd and fd2 do not share any flags/modes, etc. They are completely separate. Nor do they have any common flags/modes with fd 0.
Note that I deliberately specified /proc/self/0 [which is open for reading] and, yet, we opened it for writing.
It does not care about [nor use] the original descriptors flags, etc. Once again, it is just a "double level" symlink to the full path of the final target file: /dev/pts/2
It is the file permissions of the target file that dictate whether a given open is allowed (e.g. if the permissions were 0444, and we tried to open with O_WRONLY, that would return EPERM).
This would be no different than if we had a directory that looked like:
total 0
-rw-r--r--. 1 cae cae 0 Nov 7 00:29 a
lrwxrwxrwx. 1 cae cae 1 Nov 7 00:29 b -> a
lrwxrwxrwx. 1 cae cae 1 Nov 7 00:29 c -> a
lrwxrwxrwx. 1 cae cae 1 Nov 7 00:29 d -> c
We could do:
int fd1 = open("a",O_RDONLY);
int fd2 = open("b",O_WRONLY);
int fd3 = open("c",O_WRONLY);
int fd4 = open("d",O_WRONLY);
Those four file descriptors don't share anything. But, they are four separate streams to the same file. So, if we write to any of fd2, fd3, or fd4. Then, read from fd1 and we'll see the effect.
Related
I have a simple C HTTP server. I close file descriptors for disk files and new connection fds returned by accept(...), but I noticed that I am getting new file descriptor numbers that are bigger than the previous numbers: for example file descriptor from accept return starts with 4, then 5, then 4 again and so on until file descriptor reaches max open file descriptor on a system.
I have set the value to 10,000 on my system but I am not sure why exactly file descriptor number jumps to max value. And I am kind of sure than my program is closing the file descriptors.
So I would like to know if there are not thousands of connections then how come file descriptor new number are increasing periodically: in around 24 hours I get message accept: too many open files. What is this message?
Also, does ulimit -n number value get reset automatically without system reboot?
as mentioned in the answer. The output of _2$ ps aux | grep lh is
dr-x------ 2 fawad fawad 0 Oct 11 11:15 .
dr-xr-xr-x 9 fawad fawad 0 Oct 11 11:15 ..
lrwx------ 1 fawad fawad 64 Oct 11 11:15 0 -> /dev/pts/3
lrwx------ 1 fawad fawad 64 Oct 11 11:15 1 -> /dev/pts/3
lrwx------ 1 fawad fawad 64 Oct 11 11:15 2 -> /dev/pts/3
lrwx------ 1 fawad fawad 64 Oct 11 11:25 255 -> /dev/pts/3
and the output of ls -la /proc/$$/fd is
root 49855 0.5 5.4 4930756 322328 ? Sl Oct09 15:58 /usr/share/atom/atom --executed-from=/home/fawad/Desktop/C++-work/lhparse --pid=49844 --no-sandbox
root 80901 0.0 0.0 25360 5952 pts/4 S+ 09:32 0:00 sudo ./lh
root 80902 0.0 0.0 1100852 2812 pts/4 S+ 09:32 0:00 ./lh
fawad 83419 0.0 0.0 19976 916 pts/3 S+ 11:27 0:00 grep --color=auto lh
I like to know what is pts/4 etc. column. is this the file descriptor number.
It's likely that the socket that is represented by the file descriptor is in close_wait or time_wait state. Which means the TCP stack holds the fd open for a bit longer. So you won't be able to reuse it immediately in this instance.
Once the socket is fully finished with and closed, the file descriptor number will then available for reuse inside your program.
See: https://en.m.wikipedia.org/wiki/Transmission_Control_Protocol
Protocol Operation and specifically Wait States.
To see what files are still open you can run
ls -la /proc/$$/fd
The output of this will also be of help.
ss -tan | head -5
LISTEN 0 511 *:80 *:*
SYN-RECV 0 0 192.0.2.145:80 203.0.113.5:35449
SYN-RECV 0 0 192.0.2.145:80 203.0.113.27:53599
ESTAB 0 0 192.0.2.145:80 203.0.113.27:33605
TIME-WAIT 0 0 192.0.2.145:80 203.0.113.47:50685
here is part of code
scanf("%[^\n]%*c",command);
int pid;
pid=fork();
if (pid == 0) {
// Child process
char *argv[]={command ,NULL};
execvp(argv[0], argv);
exit (0);
}
When I give as input ls I want as output
1 copy of mysh1.c mysh1.c mysh3.c mysh.c New Folder
a.out helpmanual.desktop mysh2.c mysh4.c New File
and when i give ls -l /tmp
i'm waiting
total 12
-rw------- 1 antre antre 0 Nov 4 17:31 config-err-KT9sEZ
drwx------ 2 antre antre 4096 Nov 4 19:21 mozilla_antre0
drwx------ 2 antre antre 4096 Jan 1 1970 orbit-antre
drwx------ 2 antre antre 4096 Nov 4 17:31 ssh-HaOFtKdeIQnQ `
but i take:
1 copy of mysh1.c mysh1.c mysh3.c mysh.c New Folder
a.out helpmanual.desktop mysh2.c mysh4.c New File
It seems that you're trying to parse the output of ls -l in a C program for some reason.
That's unlikely to be the “right” thing to do. The usual mechanism is to use opendir and readdir to read the directory file, directly.
If you have some truly strange situation in which you cannot opendir (the only case that comes to mind is if you're running ls on a remote system, eg, over ssh), there is a mode in GNU ls specifically for producing an output record format that can be parsed by another program.
From the GNU coreutils info:
10.1.2 What information is listed
‘-D’
‘--dired’
With the long listing (‘-l’) format, print an additional line after
the main output:
//DIRED// BEG1 END1 BEG2 END2 ...
The BEGN and ENDN are unsigned integers that record the byte
position of the beginning and end of each file name in the output.
This makes it easy for Emacs to find the names, even when they
contain unusual characters such as space or newline, without fancy
searching.
If directories are being listed recursively (‘-R’), output a
similar line with offsets for each subdirectory name:
//SUBDIRED// BEG1 END1 ...
Finally, output a line of the form:
//DIRED-OPTIONS// --quoting-style=WORD
where WORD is the quoting style (*note Formatting the file
names::).
Here is an actual example:
$ mkdir -p a/sub/deeper a/sub2
$ touch a/f1 a/f2
$ touch a/sub/deeper/file
$ ls -gloRF --dired a
a:
total 8
-rw-r--r-- 1 0 Jun 10 12:27 f1
-rw-r--r-- 1 0 Jun 10 12:27 f2
drwxr-xr-x 3 4096 Jun 10 12:27 sub/
drwxr-xr-x 2 4096 Jun 10 12:27 sub2/
a/sub:
total 4
drwxr-xr-x 2 4096 Jun 10 12:27 deeper/
a/sub/deeper:
total 0
-rw-r--r-- 1 0 Jun 10 12:27 file
a/sub2:
total 0
//DIRED// 48 50 84 86 120 123 158 162 217 223 282 286
//SUBDIRED// 2 3 167 172 228 240 290 296
//DIRED-OPTIONS// --quoting-style=literal
Note that the pairs of offsets on the ‘//DIRED//’ line above
delimit these names: ‘f1’, ‘f2’, ‘sub’, ‘sub2’, ‘deeper’, ‘file’.
The offsets on the ‘//SUBDIRED//’ line delimit the following
directory names: ‘a’, ‘a/sub’, ‘a/sub/deeper’, ‘a/sub2’.
Here is an example of how to extract the fifth entry name,
‘deeper’, corresponding to the pair of offsets, 222 and 228:
$ ls -gloRF --dired a > out
$ dd bs=1 skip=222 count=6 < out 2>/dev/null; echo
deeper
Note that although the listing above includes a trailing slash for
the ‘deeper’ entry, the offsets select the name without the
trailing slash. However, if you invoke ‘ls’ with ‘--dired’ along
with an option like ‘--escape’ (aka ‘-b’) and operate on a file
whose name contains special characters, notice that the backslash
is included:
$ touch 'a b'
$ ls -blog --dired 'a b'
-rw-r--r-- 1 0 Jun 10 12:28 a\ b
//DIRED// 30 34
//DIRED-OPTIONS// --quoting-style=escape
If you use a quoting style that adds quote marks (e.g.,
‘--quoting-style=c’), then the offsets include the quote marks. So
beware that the user may select the quoting style via the
environment variable ‘QUOTING_STYLE’. Hence, applications using
‘--dired’ should either specify an explicit
‘--quoting-style=literal’ option (aka ‘-N’ or ‘--literal’) on the
command line, or else be prepared to parse the escaped names.
i just only needed to use strtok
Hellow.
I have very simple C program. I create pipe in program (standard, non-named). Can I read pipe of existing process in terminal (stream with > or cat?). I try it but my command do nothing. Im know tkat i can create named pipe who is very easy for external I/O.
I have number of pipe for /proc/number/fd
Why I need it? Just from debug (but not only, i know that gdb can look pipe). When i fork process, children inherits pts (terminal) and std io/out. Change pts is possible but it is bad way. So I will open next terminal and stream existing process pipie in it.
It is possible (and decent, dizzy way dont interesting me) or I must used named pipe?
Can I read pipe of existing process in terminal (stream with > or
cat?)
Yes, you can. Example rnpit.c:
#include <string.h>
main()
{
int pipefd[2];
pipe(pipefd);
write(pipefd[1], "pipe", strlen("pipe"));
sleep(99); // give us time to read the pipe
}
>rnpit&
[1] 1077
>ll /proc/${!}/fd
total 0
lrwx------ 1 armali ARNGO_res4 64 Apr 4 09:22 0 -> /dev/pts/5
lrwx------ 1 armali ARNGO_res4 64 Apr 4 09:22 1 -> /dev/pts/5
lrwx------ 1 armali ARNGO_res4 64 Apr 4 09:22 2 -> /dev/pts/5
lr-x------ 1 armali ARNGO_res4 64 Apr 4 09:22 3 -> pipe:[399466140]
l-wx------ 1 armali ARNGO_res4 64 Apr 4 09:22 4 -> pipe:[399466140]
>cat /proc/${!}/fd/3
pipe
I was reading wayland/weston code, the setting up tty part. I found it tries to acquire an available tty for doing KMS and start windows.
This is how it does:
if (!wl->new_user) {
wl->tty = STDIN_FILENO;
} else if (tty) {
t = ttyname(STDIN_FILENO);
if (t && strcmp(t, tty) == 0)
wl->tty = STDIN_FILENO;
else
wl->tty = open(tty, O_RDWR | O_NOCTTY);
} else {
int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
char filename[16];
if (tty0 < 0)
error(1, errno, "could not open tty0");
if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
error(1, errno, "failed to find non-opened console");
snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
wl->tty = open(filename, O_RDWR | O_NOCTTY);
close(tty0);
}
in src/weston-launch.c.
It tries to open('/dev/tty0') and find a tty that available if no tty is specified.
But you can't do that, neither /dev/tty0 nor 'available tty' belongs to you. I tested with my simpler version. And of course I couldn't open /dev/tty0.
Do you guys know how this magic is done?
The actual available devices for a tty depend on the system. On most interactive Unix/Unix-like systems you will have a "tty" whose name can be found from the command-line program tty. For example:
$ tty
/dev/pts/2
Likely, you also have a device named "tty", e.g.,
$ ls -l /dev/tty
lrwxrwxrwx 1 root other 26 Feb 9 2014 /dev/tty -> ../devices/pseudo/sy#0:tty
$ ls -lL /dev/tty
crw-rw-rw- 1 root tty 22, 0 Feb 9 2014 /dev/tty
You cannot open just any tty device, because most of them are owned by root (or other users to which they have been assigned).
For further discussion about the differences between /dev/console, /dev/tty and other tty-devices, see Cannot open /dev/console.
According to the console_codes(4) manual page:
VT_OPENQRY
Returns the first available (non-opened) console. argp points to an int which is set to the number of the vt (1 <= *argp <= MAX_NR_CONSOLES).
and for example on a Linux system I see this in /dev:
crw-rw-rw- 1 root 5, 0 Mon 04:20:13 tty
crw------- 1 root 4, 0 Mon 03:58:52 tty0
crw------- 1 root 4, 1 Mon 04:00:41 tty1
crw------- 1 tom 4, 2 Mon 04:30:31 tty2
crw------- 1 root 4, 3 Mon 04:00:41 tty3
crw------- 1 root 4, 4 Mon 04:00:41 tty4
crw------- 1 root 4, 5 Mon 04:00:41 tty5
crw------- 1 root 4, 6 Mon 04:00:41 tty6
crw------- 1 root 4, 7 Mon 03:58:52 tty7
crw------- 1 root 4, 8 Mon 03:58:52 tty8
crw------- 1 root 4, 9 Mon 03:58:52 tty9
crw------- 1 root 4, 10 Mon 03:58:52 tty10
crw------- 1 root 4, 11 Mon 03:58:52 tty11
All of those tty devices except one for which I have opened a console session are owned by root. To be able to log into one, a program such as getty acts to temporarily change its ownership. Doing a ps on my machine shows for example
root 2977 1 0 04:00 tty1 00:00:00 /sbin/getty 38400 tty1
root 2978 1 0 04:00 tty2 00:00:00 /bin/login --
root 2979 1 0 04:00 tty3 00:00:00 /sbin/getty 38400 tty3
root 2980 1 0 04:00 tty4 00:00:00 /sbin/getty 38400 tty4
root 2981 1 0 04:00 tty5 00:00:00 /sbin/getty 38400 tty5
root 2982 1 0 04:00 tty6 00:00:00 /sbin/getty 38400 tty6
Note that getty is running as root. That gives it the privilege to change the ownership of the tty device as needed. That is, while the ioctl may identify an unused tty, you need elevated privileges to actually open it. Linux (like any other Unix-like system) does not have a way to provide ensure that one process has truly exclusive access to a terminal. So it uses the device ownership and permissions to ensure this access.
If you're not the superuser then you should only try to access /dev/tty. That is a special device synonym for whichever tty is controlling the current process.
This is my code
fd=open("a",O_RDWR | O_CREAT);
printf("%d\n", fd);
if(fd < 0)
{
perror("error");
exit(1);
}
lseek(fd, 0, SEEK_SET);
read(fd, buf, 10);
write(STDOUT_FILENO, buf, 10);
getchar();//1
lseek(fd, 0, SEEK_SET);
write(fd, "xxxxxxxxxx", 10);
getchar();//2
lseek(fd, 0, SEEK_SET);
read(fd, buf, 10);
write(STDOUT_FILENO, buf, 10);
getchar();//3
next is something about file a
//file a, mode 600
//aaaaaaaaaaa
when at step 2, the text of file a will be changed into "xxxxx...".
then I use vim to change the text into "bbbbbbb..." in another terminal.
the output at step 3 is "xxxxx..."
however, when file a is
//file a, mode 606 or 660
//aaaaaaaaaaaa
do same thing as above
the output is "bbbbbbb...."
my system is os x 10.9
I can reproduce the problem, to my considerable surprise (Mac OS X 10.9.4).
However, as I hinted might be a possibility in my comment, the problem seems to be that vim is changing the inode number of the file when the file has 600 permission:
$ for mode in 600 606 660 666
> do
> echo "Mode: $mode"
> echo "abcdefghijklmnopqrst" > a
> chmod $mode a
> ls -li a
> vim a
> cat a
> ls -li a
> done
Mode: 600
25542402 -rw------- 1 jleffler staff 21 Sep 2 07:58 a
xxxxxxxxxxklmnopqrst
25542484 -rw------- 1 jleffler staff 21 Sep 2 07:58 a
Mode: 606
25542484 -rw----rw- 1 jleffler staff 21 Sep 2 07:58 a
xxxxxxxxxxklmnopqrst
25542484 -rw----rw- 1 jleffler staff 21 Sep 2 07:58 a
Mode: 660
25542484 -rw-rw---- 1 jleffler staff 21 Sep 2 07:58 a
xxxxxxxxxxklmnopqrst
25542484 -rw-rw---- 1 jleffler staff 21 Sep 2 07:58 a
Mode: 666
25542484 -rw-rw-rw- 1 jleffler staff 21 Sep 2 07:58 a
xxxxxxxxxxklmnopqrst
25542484 -rw-rw-rw- 1 jleffler staff 21 Sep 2 07:58 a
$
In each case, I ran the command 10rx and :x in vim.
I'm not clear why vim needs to change the inode when the file is 600 permission, but it smacks of a bug from where I'm sitting. It is behaviour I would not have expected at all (except that it explained what you saw).
Because the 'file descriptor' program (the outline code in the question) keeps the same file open, the inode number of the file it is working with does not change, but because vim rewrites the file with a new inode number (meaning: it creates a new file with a new name and inode number containing the modified contents, then removes the old version of a and replaces it with the new file), the edit made by vim (when the file has 600 permission) is not seen in the file that the program has open. At the end of the 'file descriptor' program when the permissions are 600, the file that it had open has no name and its contents are deleted by the system; the file that vim created has taken the place of the original file.