3

I am using two pipes to read from the stdout of the ftp program and write to the stdin of the ftp program. But the output part doesn't work well which i can't find out why. It looks like the stdout of the ftp bin won't immediately go through the pipe to the read side.Please help me exam my code ,thank you so much. And ,here is my code:

#define _GNU_SOURCE  
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <errno.h>
#include <pthread.h>
#include <stdarg.h> 
#include <stdio.h>  
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/sysinfo.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <termios.h> 
#include <unistd.h>

typedef unsigned char UCHAR;

#define MAXBUFSIZE 1024 
#define BUFSIZE 10240 
typedef struct dev_info
{
    UCHAR   ip[4];
    UCHAR   id[16];
    uint8_t state;
} dev_info;

char filename[64];
char fullname[128];
char ip_own[16]={0};
time_t timer;
struct tm *tblock;
char proname[256] = {0};
char buf_error[BUFSIZE]={0};
static char buf[BUFSIZE];
FILE *file_r, *file_w;

void erroroutput(char * str, const char * _func, const int  _line)
{
    memset(buf_error, 0x00, BUFSIZE);
    sprintf(buf_error, "[%s:%d]%s: %s\n",_func, _line, str,strerror(errno));
    printf("%s",buf_error);
}

int checkchar(char c)
{
    if(c<=8)
        return -1;
    if((13<c)&(c<=31))
        return -1;
    if(c>=127)
        return -1;
    return 0;
}

pid_t rw_popen(char* cmd, FILE **rfile, FILE **wfile)
{
    int pipefd[2],pipefd2[2];
    pid_t pid;
    short int flags=0;
    if (pipe(pipefd) < 0)
    {
        erroroutput("pipe create error",__func__, __LINE__);
        return -1;
    }
    if (pipe(pipefd2) < 0)
    {
        erroroutput("pipe create error",__func__, __LINE__);
        return -1;
    }
    pid = fork();
    if (pid < 0)
    {
        fprintf(stdout, "[%s:%d]fail to fork!\n",__func__, __LINE__);
        return -1;
    }

    if (0 == pid)
    {
        close(pipefd[0]);
        dup2(pipefd[1], 1);
        close(pipefd[1]);
        dup2(pipefd2[0], 0);
        
        close(pipefd2[0]);
        close(pipefd[1]);
        char *argv[] = { "/bin/sh", "-c", cmd, NULL };
        fprintf(stderr,"[%s:%d](pid):=%d\n",__func__, __LINE__,pid);
        if (execvp("/bin/sh", argv) < 0) 
        {
            fprintf(stderr, "[%s:%d]fail to execvp!\n",__func__, __LINE__);
            exit(1);
        }
        fprintf(stderr, "[%s:%d]got here!\n",__func__, __LINE__);
        exit(0);
    }else
    {
        close(pipefd[1]);
        *rfile = fdopen(pipefd[0], "r");
        if(*rfile==NULL)
            fprintf(stderr,"[%s:%d]*rfile==NULL\n",__func__, __LINE__);
        close(pipefd2[0]);
        *wfile = fdopen(pipefd2[1], "w");
        if(*wfile==NULL)
            fprintf(stderr,"[%s:%d]*wfile==NULL\n",__func__, __LINE__);

        return pid;
    }
}
 
void rw_pclose(pid_t pid, FILE *rfile, FILE *wfile) {
    int status;
    waitpid(pid, &status, 0);
    fclose(rfile);
    fclose(wfile);
}

int waitc(char cc, FILE ** file_rr, char* buff,uint16_t len,char* fc,...)
{
    int c,i=0;
    va_list argp;  
    int argnum = 0;  
    char *para[10];  
    va_start(argp, fc);
    para[argnum]=fc;
    argnum++;
    while (1)  
    {  
        para[argnum] = va_arg(argp, char *);  
  
        if (strcmp(para[argnum],"") == 0)
            break;    
        argnum++;  
    }  
    va_end(argp);
    do
    {
        c=fgetc(*file_rr);
        if(feof(*file_rr))
        {
            fprintf(stderr, "[%s:%d]Got eof!\n",__func__, __LINE__);
            //return -1;
        }
        if(checkchar(c)<0)
            break;/**/
        putc(c,stdout);
        buff[i]=c;
        i++;
        for(int k=0;k<argnum;k++)
        {
            if(strstr(buff,para[k])!=NULL)
            {
                fprintf(stderr, "[%s:%d]Fail ! %s%d\n",__func__, __LINE__,para[k],k);
                return -1;
            }
        }
        if(i>=len)
        return -2;
    }
    while((char)c!=cc);
    return 0;
}/**/

int loginftp(char* addr, char * user ,char * passw)
{
    
    pid_t pid;
    char cmd[256];
    memset(cmd,0,sizeof(cmd));
    strcat(cmd,"ftp ");
    strcat(cmd,addr);
    strcat(cmd,"\n");
    fprintf(stderr, "[%s:%d]%s\n",__func__, __LINE__,cmd);
    
    pid = rw_popen(cmd, &file_r, &file_w);
    fprintf(stderr, "[%s:%d]pid=%d\n",__func__, __LINE__,pid);
    if (pid)
    {
        fputs("anonymous\n",file_w);
        fflush(file_w);
        memset(buf,0,BUFSIZE);
        waitc(':',&file_r,buf,BUFSIZE,"xxxxx","");
        
        fputs("anonymous\n",file_w);
        fflush(file_w);
        memset(buf,0,BUFSIZE);
        waitc(':',&file_r,buf,BUFSIZE,"xxxxx","");

        fputs("quit\n",file_w);
        fflush(file_w);
        memset(buf,0,BUFSIZE);
        waitc(':',&file_r,buf,BUFSIZE,"xxxxx","");

        int c[2]={0};
        c[0]=0x04;
        fputc(c[0],file_w);
        fflush(file_w);
//_rw_pclose2:
_rw_pclose1:
        rw_pclose(pid, file_r, file_w);
    }
    fprintf(stderr, "[%s:%d]got here!\n",__func__, __LINE__);
    return 0;
}

int main ( int argc, char * argv[] )
{
    //strcpy(proname, argv[0]);
    int ret;
    ret=loginftp("ftp.sjtu.edu.cn","anonymous","anonymous");
    fprintf(stderr, "[%s:%d]ret:%d\n",__func__, __LINE__,ret);
}

My makefile:

CC  = gcc
LD  = ld
AR  = ar
RANLIB  = ranlib
STRIP   = strip

CFLAGS  = -Wall -Wshadow -Wno-trigraphs -pipe
LDFLAGS = -lm -lpthread -g

BIN = unifyctrl
SRCS    = $(wildcard *.c)
OBJS    = $(SRCS:.c=.o)

all: $(BIN)

$(OBJS): %.o: %.c
    $(CC) -c -g $(CFLAGS) $< -o $@

$(BIN): $(OBJS)
    $(CC)  $(OBJS) $(LDFLAGS) -o $(BIN)
    $(STRIP) $(BIN)
clean:
    rm -rf *.o
    rm -rf $(BIN)
    rm -rf *.o *.bak *.c.bak a

The first outcome of my code should be like this:

Connected to ftp-tel.sjtu.edu.cn. 
220 (vsFTPd 3.0.2) 
Name (ftp.sjtu.edu.cn:d01):

but i only got this :

Password:
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Dery
  • 177
  • 1
  • 11
  • 2
    Most likely the ftp program is reading the password from the tty in raw mode, and not from the stdin pipe at all. – Keith Sep 22 '18 at 02:43
  • `if(feof(*file_rr))` **-->>** `if(c == -1 && feof(*file_rr))` ... or just `if(c== -1)` – wildplasser Sep 22 '18 at 12:01
  • @Keith em.... i dont quite get it. – Dery Sep 23 '18 at 08:18
  • @wildplasser I did what you suggest ,but nothing changed. Thank you anyway. – Dery Sep 23 '18 at 08:21
  • 1
    You'll have to interact with the ftp subprocess through a pty, rather than pipes. See [forkpty](http://man7.org/linux/man-pages/man3/openpty.3.html). – Keith Sep 23 '18 at 21:20

0 Answers0