I'm trying to write a program that will fork a series of FTP sessions. For each session, there should be separate input and output files associated with stdin and stdout/stderr.
I keep reading how I should be able to do that with dup2() in the child process before the execl(), but it's not working for me. Could someone please explain what I've done wrong?
The program also has a 30-second sniper alarm for testing and killing of FTPs that go dormant for too long.
Thanks in advance for anything you can offer.
--
AndrewBS42@hotmail.com
The code: (ftpmon.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
void imgPull_ftp_timeout_action( int signo);
pid_t child_pid = 0;
void imgPull_ftp_timeout_action( int signo)
{
int result = 0;
/* timeout! Kill the child */
if ((result = kill(child_pid, SIGTERM)) != 0)
{
perror("kill()");
}
return;
}
int main( int argc,
char *argv[])
{
int status = 0;
int script_fd = 0;
int log_fd = 0;
int dummy = 0;
int child_status = 0;
mode_t log_mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
pid_t term_pid = 0;
char *ftp_executable = "/usr/bin/ftp";
char *script_name = "/home/abs/ftp/script.ftp";
char *log_name = "/home/abs/ftp/script.ftp.log";
struct sigaction img_sigaction_alrm;
/* Set up signal handlers for alarm */
memset(&(img_sigaction_alrm), '\0', sizeof(img_sigaction_alrm));
img_sigaction_alrm.sa_handler = imgPull_ftp_timeout_action;
sigaction(SIGALRM, &(img_sigaction_alrm), NULL);
/* fork() */
alarm(30);
child_pid = fork();
if (child_pid == -1)
{
/* error */
perror("fork()");
return(1);
}
else if (child_pid == 0)
{
/* I am child. */
/* Set up to re-direct my input and output to files */
/* Open (for read) what will be the stdin for the FTP */
if ((script_fd = open(script_name, O_RDONLY)) == -1)
{
perror("open() for script");
exit(1);
}
/* Open (for write) what will be the stdout/stderr for the FTP */
if ((log_fd = creat(log_name, log_mode)) == -1)
{
perror("open() for log");
exit(1);
}
/* Call dup2() to point the child's stdin to the script */
if ((dummy = dup2(STDIN_FILENO, script_fd)) == -1)
{
perror("dup2() for script (stdin)");
exit(1);
}
/* Call dup2() to point the child's stdout to the log */
if ((dummy = dup2(STDOUT_FILENO, log_fd)) == -1)
{
perror("dup2() for log (stdout)");
exit(1);
}
/* Call dup2() to point the child's stderr to the log */
if ((dummy = dup2(STDERR_FILENO, log_fd)) == -1)
{
perror("dup2() for log (stderr)");
exit(1);
}
close(script_fd);
close(log_fd);
/* do FTP */
if ((dummy = execl(ftp_executable,
ftp_executable, "-i", "-n", "-v", "gila-crstest.gilacorp.com", (char *) NULL)) == -1)
{
perror("execl()");
exit(1);
}
}
else
{
/* I am parent. */
/* Wait for child to end */
if ((term_pid = waitpid(child_pid, &child_status, 0)) == -1)
{
perror("waitpid()");
exit(1);
}
/* disable alarm */
alarm(0);
if (WIFEXITED(child_status))
{
printf("child exited normally, status = %d\n", WEXITSTATUS(child_status));
}
if (WIFSIGNALED(child_status))
{
printf("child terminated by uncaught signal %d\n", WTERMSIG(child_status));
}
}
return(0);
}
The FTP script: (script.ftp) (I want this to be stdin)
user abs NoneOfYourBusiness
ascii
hash
cd ftp
get interesting.txt
bye
The output:
$ ftpmon
Connected to gila-crstest.gilacorp.com (172.16.20.8).
220 (vsFTPd 2.0.1)
ftp> waitpid(): Interrupted system call
Why am I getting the ftp> prompt? If the dup2() works, shouldn't it be taking input from my script and not my terminal? In stead, it does nothing, and winds up getting killed after 30 seconds.
The log file is created, but it's empty after the run.