Conversation
Question for users/developers of non-Linux UNIX platforms: does fstat on a pipe or socket or similar return a unique (st_dev, st_ino) pair that will be equal for the same file descriptor in different programs? For instance, if you create a pipe and have the write end inherited as the stdout for a whole tree of programs, can they all call fstat on that fd and see the same dev/ino pair? (This is true on Linux, but I want to check the assumption that it's universally true.)
2
0
0
On what platform does it not hold?
1
0
0

@josh

So you mean like (words can mix up stuff):

#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char **argv)
{
	char *line = NULL;
	struct stat sb;
	size_t len;
	int fds[2];
	pid_t pid;
	ssize_t n;
	if (pipe(fds) < 0) {
		perror("pipe");
		exit(1);
	}
	pid = fork();
	if (pid < 0) {
		perror("fork");
		exit(1);
	}
	if (pid == 0) {
		dup2(fds[1],  STDOUT_FILENO);
		close(fds[0]);
		close(fds[1]);
		if (fstat(STDOUT_FILENO, &sb) < 0) {
			perror("fstat");
			exit(1);
		}
		printf("child: st_dev=%u, st_ino=%llu\n", sb.st_dev, sb.st_ino);
	} else {
		dup2(fds[0],  STDIN_FILENO);
		if (fstat(fds[1], &sb) < 0) {
			perror("fstat");
			exit(1);
		}
		printf("parent: st_dev=%u, st_ino=%llu\n", sb.st_dev, sb.st_ino);
		close(fds[0]);
		close(fds[1]);
		n = getline(&line, &len, stdin);
		if (n < 0)  {
			fprintf(stderr, "Unexpected EOF\n");
			exit(1);	
		}
		fwrite(line, n, 1, stdout);
		free(line);
		wait(&pid);
	}
	exit(0);
}

? With M1 generation MacBook Pro I get:

$ ./test
parent: st_dev=0, st_ino=9204210306621897207
child: st_dev=0, st_ino=9204210306621897207
1
0
0
Yes, or the same thing with socketpair() or just a connected TCP socket.

Interesting that it has `st_dev=0` and an `st_ino` value that looks like it's intentionally close to 2^63, but it does look like it might be a unique value.
1
0
0
@bugaevc @josh thanks for educating, nice to learn details like this, appreciate it :-) i had no idea tbh. just thought that a test program could help out with the question
0
0
0
Interesting. Unique as long as the pipe exists, at least, which is good enough for the purposes I'd want to use it for.
0
0
0
Argh. That breaks the use case I wanted to use this for. (Namely, telling a program something about one of its fds via the environment, while not unintentionally telling a subprocess of that program the same thing if the fd has changed. I wanted to uniquely identify the fd.)
1
0
0

@josh so like systemd's JOURNAL_STREAM? (But that one only has to work on Linux of course.)

1
0
0
Yes, exactly. The problem I was trying to solve was how to tell a program it should send color to a pipe, including subprograms that are also writing to the *same* pipe, but not cause breakage with subprograms whose output is redirected and should not include color. (There are proposed approaches for force-enabling color, which is useful for things like IDEs and CI, but as currently specified they can cause build breakage.)
1
0
0

@josh @bugaevc what about using sgid as an identifier + SCM_RIGHTS? Not sure if it fits to the context, just.came to mind.

2
0
0

@josh @bugaevc I mean with SCM_RIGHTS you can send a payload and the receiver can check uid/sgid and thus is often quite useful tool to do all sorts of handshakes within a single machine.

0
0
0
Not sure what you mean by using sgid as the identifier. SCM_RIGHTS doesn't help in this context; this is for programs that have an ordinary stdin/stdout/stderr and just need to know whether the fd they already have (0/1/2) is one they should send color to even though it isn't a tty.
1
0
0
@josh @bugaevc I meant just that when you receive fd's you can check by sender's sgid's whether it is legit sender and make assumptions that fd's are legit for whatever you are doing. Or check LSM labels if the target is only linux.
1
0
0

Jarkko Sakkinen

Edited 1 year ago
@josh @bugaevc Maybe it is not a fit for the case but one more heavy-lifting way would be to have a daemon/service that you would connect with UDS socket and processes would report the situation and that service could perhaps send fd that could be used to query/report. This is about what I was thinking but probably too far fetched I guess.

I.e. you have a piped process tree and outside service to keep track of things...
2
0
0

Jarkko Sakkinen

Edited 1 year ago
@bugaevc @josh or alternatively to this scheme shm known by all processes could be used as a database to keep track of things. For me this looks like sort of problem that is pretty nasty to solve without any shared repository to get bird eye view of the process tree.
0
0
0
I think that'd be far too heavyweight for this use case. I was looking for something that'd take a few lines of code to set up, and a few lines to verify.
1
0
1
@josh @bugaevc why there can't be an additional pipe (i.e. not stdin/stderr/stdout) for reporting how things are?
1
0
0
Doing something like "send a message over a pipe and get back a response" is much more complex than "check an environment variable and stat an fd". And giving a program an extra fd is also more error-prone; it might break programs that don't expect it, and it won't necessarily get inherited because programs might close it.
1
0
0
@josh @bugaevc true :-) if i actually had to work on this kind of problem i would look up binder implementation for inspiration (not sure exactly what but it is sort of code base that i like to read when I have any problem to solve related to IPC). there was recently rust version of binder submitted to LKML
0
0
0