2012-03-26 9 views
4

Ich muss eine Funktion erstellen, die unter anderem einen untergeordneten Prozess hervorbringt. Ich möchte dieser Funktion eine optionale Liste von Dateidekriptoren übergeben, damit je nach den Bedürfnissen des Benutzers die Eingabe/Ausgabe des untergeordneten Prozesses umgeleitet werden kann.Redirect gabeled Prozessausgabe zu NULL

Ich habe Dutzende von Menschen gesehen zu reden, wie dies mit dup2 etwas wie dies zu tun:

if(pid < 0) // error forking. 
{ 
//... 
} 
else if(pid != 0) // Parent process. 
{ 
    ret = waitpid(pid, &status, 0); 
    return WEXITSTATUS(status); 
} 
else // Child process. 
{ 
    dup2(fd, STDIN_FILENO); // Clone passed file discriptor. 
    close(fd);   // Close the passed one, since we have already cloned. 
    execvp(arglist[ 0 ], arglist); 
} 

In Ordnung. All das ist im Internet. Meine Frage ist jetzt, wie (oder was ist der beste Weg), um auf /dev/null umzuleiten?

Sollte ich den Benutzer zwingen, open(/dev/null) und übergeben Sie es als fd oder gibt es einen besseren Weg?


EDIT:

Dies, wie ich wollte nicht so schön ist, aber ich konnte einen besseren Weg nicht finden, so dass ich beenden eine Reihe von Dateinamen nach oben vorbei, wo immer ein Benutzer umleiten möchten könnte, jeweils STDIN, STDOUT und STDERR:

static int do_exec(arglist_t arglist, const char *fio[ 3 ]) 
{ 
DEBUG__(OSU_DEBUG_LEVEL_1, "fio = %p\n", fio); 

    if (fio) 
    { 
     if (fio[ STDIN_FILENO ]) 
     { 
      int fd = open(fio[ STDIN_FILENO ], O_RDONLY); 

      if (-1 < fd) 
      { 
       dup2(fd, STDIN_FILENO); 
       close(fd); 
      } 
     } 

     if (fio[ STDOUT_FILENO ]) 
     { 
      int fd = open(fio[ STDOUT_FILENO ], O_WRONLY | O_CREAT | O_APPEND); 

      if (-1 < fd) 
      { 
       dup2(fd, STDOUT_FILENO); 
       close(fd); 
      } 
     } 

     if (fio[ STDERR_FILENO ]) 
     { 
      int fd = open(fio[ STDERR_FILENO ], O_WRONLY | O_CREAT | O_APPEND); 

      if (-1 < fd) 
      { 
       dup2(fd, STDERR_FILENO); 
       close(fd); 
      } 
     } 
    } 

    return execvp(arglist[ 0 ], arglist); 
} 
  • ich habe es noch nicht vollständig getestet, so dass es einige Fehler haben kann.

Wirklich dank @Zack und @gbulmer.

Antwort

4

Man könnte es als Konvention Ihrer API hat, die für das fd in -1 vorbei bedeutet /dev/null, zu verwenden und

// ... same as you have ... 

else // Child process 
{ 
    if (stdin_fd == -1) 
     stdin_fd = open("/dev/null", O_RDONLY); 
    if (stdin_fd == -1) 
     _exit(127); 
    dup2(stdin_fd, STDIN_FILENO); 
    close(stdin_fd); 

    // similarly for stdout and stderr 

    execvp(arglist[0], arglist); 
    _exit(127); 
} 

(Psst tun: Jedes Mal, wenn Sie Plätze auf der Innenseite der Klammern gesetzt, Gott tötet ein Kätzchen.)

+0

Ich weiß, das wird funktionieren, aber frage mich, ob es eine bessere Möglichkeit ist, das zu tun. Ich könnte Dateinamen wie @ gbulmer unten vorgeschlagen verwenden, testen Sie die Zeichenfolgen für NULL und lassen Sie meine API die Verantwortung für das Öffnen. Dies funktioniert auch und ohne Einschränkungen für jede Datei, aber wird mir noch einen Geschmack geben, dass es ein besserer Weg sein muss. Wirklich danke! – j4x

+0

Wie sieht ein "besserer Weg" für Sie aus? – zwol

+0

Ich würde gerne eine Lösung sehen, wo ich Parameter nicht explizit testen musste, Datei nach Name usw. öffnen, aber ich denke, dass es nicht möglich sein wird, also gebe ich auf. Ich werde tun, was Sie vorschlagen (siehe meine Bearbeitung). Vielen Dank! – j4x

1

Der Child-Prozess muss wissen, welche FDs als Oldfd für dup2 und welche fd zu dup2 zu verwenden.

Zum Beispiel, warum würde ein fd dup2 auf STDIN_FILENO sein?

Das Kind benötigt Informationen für das offene fd, und das fd sollte es dup2'd sein.

Um zu verallgemeinern, um Fälle zu behandeln, in denen Dateinamen und nicht nur fds behandelt werden, können Sie "/ dev/null" sagen, da es sich um einen echten Dateinamen handelt.

Also haben Sie einfach eine Liste von struct { int oldfd; char* filename; int newfd; } Strukturen, und der Job ist regulär, und die/dev/null ist kein Sonderfall. Wenn Oldfd -1 ist, öffne den Dateinamen auf newfd statt dup2 auf ihn.