Você sempre pode usar um truque LD_PRELOAD
para o Linux imitar o modo BSD. fddup.c
:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int whichfd(const char *pathname)
{
unsigned int fd;
if (sscanf(pathname, "/dev/fd/%u", &fd) == 1)
return fd;
else
return -1;
}
int open(const char *pathname, int flags, mode_t mode)
{
static int (*orig)(const char *, int, mode_t) = 0;
int fd = whichfd(pathname);
if (fd >= 0)
return dup(fd);
else {
if (!orig)
orig = dlsym(RTLD_NEXT,"open");
if (!orig) abort();
return orig(pathname, flags, mode);
}
}
FILE *fopen(const char *path, const char *mode)
{
static FILE *(*orig)(const char *, const char *) = 0;
int fd = whichfd(path);
if (fd >= 0)
return fdopen(dup(fd), mode);
else {
if (!orig)
orig = dlsym(RTLD_NEXT,"fopen");
if (!orig) abort();
return orig(path, mode);
}
}
(talvez você precise envolver mais como freopen()
).
gcc -Wall -fPIC -shared -o fddup.so fddup.c -ldl
E então:
socat TCP:localhost:22 'EXEC:env LD_PRELOAD=./ddup.so cat /dev/fd/0,nofork'
Note que o Linux e o BSD são fundamentalmente diferentes. Não é tanto que você não possa abrir /dev/fd/0
quando é um socket, mas /dev/fd/x
é um link simbólico para o arquivo que está aberto no fd x. Você não pode fazer open()
em uma tomada, isso não faria sentido. open("/dev/fd/x")
não é de todo um dup(x)
como no BSD. Parece que quando o arquivo é um pipe, mas não é mesmo assim, ele é na verdade o mesmo que abrir um pipe nomeado (você pode até mesmo abri-lo no outro modo (read vs write) para obter a outra extremidade do arquivo. o tubo).
Ambas as abordagens têm seus prós e contras. Parece-me que a sua aplicação deve ter números fd como argumentos, não use /dev/fd/x
, que é um hack em primeiro lugar de qualquer maneira e, por exemplo, faria com que você desperdiçasse fds.