Read noonnamed pipe in terminal - c

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

Related

why open file descriptors are not getting reused instead they are increasing in number value

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

Reopen an existing file descriptor with open("/dev/fd/n", mode)

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.

trying to run arbitrary commands and parse their output

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

how to open /dev/console in C

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.

How to access all pipes in the system from Linux kernel space

I want to add a new system call to the Linux kernel that will show information about all pipes that are created in the system.
How can I get the inode (or any other related structure that will allow me to access the pipe_inode_info) of every pipe in the pipefs?
I have been looking at struct vfsmount, struct dentry and struct super_block, but I have not found the proper way. Is there any way I could get the file structure of every file in the pipefs?
First I go to /proc directory and the issue:
ls -al */fd |grep pipe
(try taking away the "pipe" above and u will learn more.) and the results are (just a snapshot):
l-wx------ 1 root root 64 2011-05-14 23:12 17 -> pipe:[39208]
l-wx------ 1 root root 64 2011-05-14 23:12 2 -> pipe:[16245]
lr-x------ 1 root root 64 2011-05-14 23:12 4 -> pipe:[23406]
l-wx------ 1 root root 64 2011-05-14 23:12 8 -> pipe:[23406]
l-wx------ 1 root root 64 2011-05-14 23:12 17 -> pipe:[39532]
l-wx------ 1 root root 64 2011-05-14 23:12 2 -> pipe:[16245]
lr-x------ 1 root root 64 2011-05-14 23:12 4 -> pipe:[23406]
l-wx------ 1 root root 64 2011-05-14 23:12 8 -> pipe:[23406]
l-wx------ 1 root root 64 2011-05-14 23:12 1 -> pipe:[16245]
lr-x------ 1 root root 64 2011-05-14 23:12 16 -> pipe:[40032]
l-wx------ 1 root root 64 2011-05-14 23:12 17 -> pipe:[40032]
l-wx------ 1 root root 64 2011-05-14 23:12 2 -> pipe:[16245]
lr-x------ 1 root root 64 2011-05-14 23:12 4 -> pipe:[23406]
l-wx------ 1 root root 64 2011-05-14 23:12 8 -> pipe:[23406]
l-wx------ 1 tteikhua tteikhua 64 2011-05-14 23:13 1 -> pipe:[16245]
l-wx------ 1 tteikhua tteikhua 64 2011-05-14 23:13 12 -> pipe:[66674]
lr-x------ 1 tteikhua tteikhua 64 2011-05-14 23:13 13 -> pipe:[66674]
l-wx------ 1 root root 64 2011-05-14 23:30 1 -> pipe:[101794]
And if u want to see the process that created the pipe, just remove the "grep", for example:
Here it shows that the pid=1 is having a pipe fd at 6759:
1/fd:
total 0
dr-x------ 2 root root 0 2011-05-14 23:29 .
dr-xr-xr-x 7 root root 0 2011-05-14 22:59 ..
lrwx------ 1 root root 64 2011-05-14 23:29 0 -> /dev/console (deleted)
lrwx------ 1 root root 64 2011-05-14 23:29 1 -> /dev/console (deleted)
lrwx------ 1 root root 64 2011-05-14 23:29 2 -> /dev/console (deleted)
lr-x------ 1 root root 64 2011-05-14 23:29 3 -> pipe:[6759]
And tracing the above back to fs/pipe.c (linux kernel source that print these):
/*
* pipefs_dname() is called from d_path().
*/
static char *pipefs_dname(struct dentry *dentry, char *buffer, int buflen)
{
return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
dentry->d_inode->i_ino);
}
static const struct dentry_operations pipefs_dentry_operations = {
.d_dname = pipefs_dname,
};
And reading fs/dcache.c:
char *d_path(const struct path *path, char *buf, int buflen)
{
if (path->dentry->d_op && path->dentry->d_op->d_dname)
return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
and since d_path() is an exported symbol,
EXPORT_SYMBOL(d_path);
you should be able to call it from anywhere, and derive the information about the path - if it is a pipe then the corresponding pipefs_dname() will be called - it filesystem dependent:
./fs/pipe.c:
.d_dname = pipefs_dname,
Read inode.c: init_inode_always() and u can see that i_pipe is set to NULL. It is not null only when the inode is a PIPE.
So u can always loop through all the process and get its opened file descriptor, and it the inode's i_pipe is set to non-NULL, you will know that that value is the inode number of the pipe.
I don't think such codes will exist in the kernel source (so not necessary to hunt for it - I have already tried) as it is much more efficient and safer to do it in userspace (like the "ls -al" command I explained earlier) then inside the kernel - generally the smaller the kernel the lesser security bugs and thus better stability etc.

Resources