web-dev-qa-db-fra.com

Réouverture des descripteurs de fichiers stdout et stdin après les avoir fermés

J'écris une fonction qui, étant donné un argument, redirigera la sortie standard vers un fichier ou lira la sortie standard d'un fichier. Pour ce faire, je ferme le descripteur de fichier associé à la sortie standard ou stdin, de sorte que lorsque j'ouvre le fichier, il s'ouvre sous le descripteur que je viens de fermer. Cela fonctionne, mais le problème est qu'une fois cela fait, j'ai besoin de restaurer la stdout et la stdin à ce qu'elles devraient vraiment être.

Ce que je peux faire pour stdout est ouvert ("/ dev/tty", O_WRONLY); Mais je ne sais pas pourquoi cela fonctionne, et plus important encore, je ne connais pas de déclaration équivalente pour stdin.

J'ai donc, pour stdout

close(1);
if (creat(filePath, O_RDWR) == -1)
{
    exit(1);
}

et pour stdin

close(0);
if (open(filePath, O_RDONLY) == -1)
{
    exit(1);
}
30
RegisteredUser

Vous devez utiliser dup () et dup2 () pour cloner un descripteur de fichier.

int stdin_copy = dup(0);
int stdout_copy = dup(1);
close(0);
close(1);

int file1 = open(...);
int file2 = open(...);

< do your work. file1 and file2 must be 0 and 1, because open always returns lowest unused fd >

close(file1);
close(file2);
dup2(stdin_copy, 0);
dup2(stdout_copy, 1);
close(stdin_copy);
close(stdout_copy);

Cependant, il y a un détail mineur auquel vous voudrez peut-être faire attention (de l'homme dup):

Les deux descripteurs ne partagent pas d'indicateurs de descripteur de fichier (le close-on-execflag). L'indicateur de fermeture sur exécution (FD_CLOEXEC; voir fcntl (2)) pour le descripteur en double est désactivé.

Si c'est un problème, vous devrez peut-être restaurer l'indicateur close-on-exec, en utilisant éventuellement dup3 () au lieu de dup2 () pour éviter les conditions de concurrence.

Sachez également que si votre programme est multithread, d'autres threads peuvent accidentellement écrire/lire dans votre stdin/stdout remappé.

40
Ambroz Bizjak

Je pense que vous pouvez "enregistrer" les descripteurs avant de rediriger:

int save_in, save_out;

save_in = dup(STDIN_FILENO);
save_out = dup(STDOUT_FILENO);

Plus tard, vous pourrez utiliser dup2 pour les restaurer:

/* Time passes, STDIN_FILENO isn't what it used to be. */
dup2(save_in, STDIN_FILENO);

Je ne fais aucune vérification d'erreur dans cet exemple - vous devriez.

17
cnicutar

Vous pouvez créer un processus enfant et configurer la redirection uniquement à l'intérieur de l'enfant. Attendez ensuite que l'enfant se termine et continuez à travailler dans le processus parent. De cette façon, vous n'avez pas du tout à vous soucier d'inverser votre redirection.

Recherchez simplement des exemples de code utilisant fork () et wait ().

1
reed_do_it