I try to run login(1) process as a coprocess of my program.
The program should receive the login prompt and write the login name.
login process starts nicely as a coprocess.
But it exits immediately before writing the login prompt.
Simplified version of the program (writing stuff etc removed):
int main( int argc, char** argv )
{
int fd1[2];
int fd2[2];
if(( pipe(fd1) != -1 ) && ( pipe(fd2) != -1 ))
{
const pid_t child_pid = fork();
if( child_pid == 0 )
{
dup2( fd2[0], STDIN_FILENO );
dup2( fd1[1], STDOUT_FILENO );
close( fd1[0] );
close( fd1[1] );
close( fd2[0] );
close( fd2[1] );
execl( "/bin/login", "login", (char*)NULL );
fprintf( stderr, "execl failed\n" );
}
else if( child_pid )
{
char buffer[1000];
ssize_t len;
close( fd1[1] );
close( fd2[0] );
len = read( fd1[0], buffer, sizeof(buffer) - 1 );
if( len > 0 )
fprintf( stderr, "%zd bytes received\n", len );
else if( len == 0 )
fprintf( stderr, "read return zero \n" );
else
fprintf( stderr, "read failed: %V \n", errno );
}
else
{
fprintf( stderr, "Fork failed: %V", errno );
}
}
else
{
fprintf( stderr, "Can not open pipes: %V", errno );
}
return 0;
}
When I run the program, the result is:
~ # my_program
read return zero
~ #
If I run it with strace, I got the following results (lot of unrelevant lines removed)
~ # strace -f my_program
[pid 4028] read(3, <unfinished ...>
[pid 4030] execve("/bin/login", ["login"], [/* 12 vars */]) = 0
[pid 4030] ioctl(0, TCGETS or SNDCTL_TMR_TIMEBASE, 0x7bc28aec) = -1 EINVAL (Invalid argument)
[pid 4030] exit_group(1) = ?
Process 4030 detached
[pid 4028] <... read resumed> ""..., 999) = 0
[pid 4028] --- SIGCHLD (Child exited) @ 0 (0) ---
[pid 4028] write(2, "read return zero \n"..., 18) = 18
The login process makes exit after failed ioctl(STDIN_FILENO, TCGETS,) call.
login seems to expect that input fd is a terminal or serial line.
Is there any way to fix my program?
loginexpects a TTY. Probably the easiest way to be able to interact withloginwould be to allocate a pseudoterminal via posix_openpt and pass the file descriptor of the slave instead of the pipe handle. (But I’m not an expert in the subject.)What are you trying to do? Perhaps an even better approach would be to do the authentication via PAM, depending on your use case.