Podmiana standardowego strumienia wejsciowego na coś innego

0

<quote>Witam,
Próbuje napisać coś na wzór przekierowania strumienia w powłoce uniksowej.

#define _WITH_GETLINE
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>

int main()
{   
  char* line = NULL; size_t size;
  int length;

  while(1) {   
    printf("Stdout filename: ");
    getline(&line, &size, stdin);
    length = strlen(line);
    line[length-1] = 0;
    --length;
    
    if(*line == 0) {
      free(line);
      exit(1);
    }
        
    
    printf("Target file: %s\n", line);
    
    FILE* fp; FILE* bak;
    bak = stdin;
    if( ( fp = fopen(line, "a+") ) == NULL ) {
      fprintf(stderr, "Cannot create file!\n");
      exit(1);
    }
        
    fprintf(stderr, "This is error! #1\n");
    // podmieniam wskazniki plikow (co powinno spodowac zamiane deskryptorow)
    // nie przynosi to jednak efektu
    stdin = fp;
    stderr = fp;
    fprintf(stderr, "This is error! #2\n");
    
    fprintf(stdin, "Hello World #1\n");
    printf("Hello World #2\n");
    fprintf(stdin, "Hello World #3\n");

    // wykonaj jakies polecenie np. ls w zalozeniu ma przekierowac standardowe wyjscie do nowego pliku..
    char* cmd[2] = {"ls", NULL};
    pid_t pid;
    switch( pid = fork() ) {
      case -1:
	exit(3);
      case 0: // child
	execvp(cmd[0], cmd);
      default: // parent
	wait(NULL);
    }
    
    fclose(fp);
    stdin = bak;
   }    
}

Niestety, w tym przypadku przekierowanie strumienia dziala tylko dla komend wywolywanych w ten sposob:

fprintf(stdin, "Hello World #1\n");

Mimo, że domyślne wyjście to stdin przekierowanie działa. Wniosek: podmiana wskaźników nie zmienia deskryptora pliku. Raczej nie da się tego zrobić z użyciem biblioteki standardowej.

Moj cel jest nastepujacy:

  1. Chce, aby aplikacja zamianila deskryptor standardowego wyjscia an deskryptor pliku podanego przez uzytkownika.
  2. Dzieki temu przekieruje standardowe wyjscie i uzyskam efekt jak wydajac polecenie: ls > file
  3. Przywrocic wartosci poczatkowe.

Poniewaz to nie zadzialalo postanowilem sprobowac na funkcjach systemowych, rowniez bezskutecznie:

#define _WITH_GETLINE
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<fcntl.h>

int main()
{   
    char* line = NULL; size_t size;
    int length;

    printf("Stdout filename: ");
    getline(&line, &size, stdin);
    length = strlen(line);
    line[length-1] = 0;
    --length;
    
    if(*line == 0) {
      free(line);
      exit(1);
    }
        
    
    printf("Target file: %s\n", line);
    
    int fd;
    if( ( fd = open(line, O_WRONLY|O_CREAT, 0644) ) == -1 ) {
      fprintf(stderr, "Cannot create file!\n");
      exit(1);
    }
    
    dup2(1, fd);
        
    fprintf(stderr, "This is error! #1\n");
    fprintf(stderr, "This is error! #2\n");
    
    fprintf(stdin, "Hello World #1\n");
    printf("Hello World #2\n");
    fprintf(stdin, "Hello World #3\n");

    char* cmd[2] = {"ls", NULL};
    pid_t pid;
    switch( pid = fork() ) {
      case -1:
	exit(3);
      case 0: // child
	execvp(cmd[0], cmd);
      default: // parent
	wait(NULL);
    }
    
    close(fd);
    return 0;
  
}

Spodziewałem się, że podmiana deskryptora standardowego wyjscia na deskryptor pliku rozwiaze problem, ale to zla droga.

Bede wdzieczy za wskazowki.

Pozdrawiam,

0
man open fopen close pipe popen dup fcntl stdin

Nie wiem czy czegoś nie pominąłem.

0

Jestem już bliższy osiągnięcia tego co chcę.

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>

int main()
{
  remove("nowy.txt");
  // utworz plik  
  int new = open("/dev/fd/1", O_WRONLY);
  
  if(new == -1) {
    printf("Error");
    return 1;
  }
  printf("New: %d\n", new);
  
  int fd = open("nowy.txt", O_CREAT|O_WRONLY, 0644);
  printf("Now stdout is nowy.txt\n");
  // dup2(int oldd, int newd);
  dup2(fd, 1);
  printf("Blablabla!\n");
  printf("Sialalalalalala!\n");
  dup2(new, 1);
  close(fd);
  printf("Return to stdout!\n");
  close(new);
  printf("Bla!\n");
  
  return 0;
}

Uzyskałem ten efekt co chciałem. Aby znowu zapisywalo do domyslnego stdout, po prostu otwieram odpowiedni plik (/dev/fd/1) i tam podlaczam deskryptor.

Pozdrawiam,

1 użytkowników online, w tym zalogowanych: 0, gości: 1