Processus démarré à partir de la commande système en C hérite des FD parent

j'ai un exemple d'application D'écoute de serveur SIP sur les ports tcp et udp 5060. À un certain point dans le code, je fais un system("pppd fichier /etc/ppp/myoptions &");

après cela si je fais un netstat-apn, il me montre que les ports 5060 sont aussi ouverts pour pppd! Existe t'il une méthode pour éviter cela? Est-ce un comportement standard de la fonction système sous Linux?

Merci, Elison

10
demandé sur Elison Niven 2011-08-04 21:27:00

5 réponses

Oui, par défaut, à chaque fois que vous fourche d'un processus (qui system does), l'enfant hérite de tous les descripteurs de fichier du parent. Si l'enfant n'a pas besoin de ces descripteurs, il devrait les fermer. Le moyen de le faire avec system (ou toute autre méthode qui fait un fork+exec) est de définir le drapeau FD_CLOEXEC sur tous les descripteurs de fichiers qui ne devraient pas être utilisés par les enfants de votre processus. Cela va les faire fermer automatiquement chaque fois qu'un enfant exécute un autre programme.

Dans en général, chaque fois que votre programme ouvre un type de descripteur de fichier qui vivra pendant une période prolongée (comme une socket listen dans votre exemple), et qui ne devrait pas être partagé avec les enfants, vous devriez faire

fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);

sur le descripteur de fichier.


à partir de 2016? révision de la norme POSIX.1, vous pouvez utiliser le SOCK_CLOEXEC marquer ou'd dans le type de socket pour obtenir ce comportement automatiquement lorsque vous créez la socket:

listenfd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, 0);
bind(listenfd, ...
listen(listemfd, ...

qui il sera bien fermé même si un autre fil courant simultanément fait un system ou fork+exec appel. Heureusement, ce drapeau a été supporté pendant un certain temps sur les unixes Linux et BSD (mais pas OSX, malheureusement).

14
répondu Chris Dodd 2016-07-20 18:35:04

Vous devriez probablement éviter les system() fonction tout à fait. Il est intrinsèquement dangereux, en ce qu'il invoque la coquille, qui peut être trafiquée et plutôt non-portable, même entre les Unicies.

ce que vous devez faire est le fork()/exec() danse. Il va quelque chose comme ceci

if(!fork()){
     //close file descriptors
     ...

    execlp("pppd", "pppd", "file", "/etc/ppp/myoptions", NULL);
    perror("exec");
    exit(-1);
}
3
répondu Dave 2011-08-04 17:42:49

Oui, c'est le comportement standard de fork() sous Linux, dont system() est mis en œuvre.

l'identifiant retourné depuis le socket() appel est un descripteur de fichier valide. Cette valeur est utilisable avec des fonctions orientées fichier telles que read(),write(),ioctl() et close().

à L'inverse, que chaque descripteur de fichier est un socket n'est pas vrai. On ne peut pas ouvrir un fichier avec open() et passer ce descripteur, par exemple, bind() ou listen().

Lorsque vous appelez system() le processus enfant hérite des mêmes descripteurs de fichier que le parent. C'est de cette façon stdout (0),stdin (1), et stderr (2) sont héritées par des processus enfants. Si vous vous arrangez pour ouvrir une socket avec un descripteur de fichier 0, 1 ou 2, le processus enfant héritera que socket comme l'un des descripteurs d'e/s standard de fichier.

votre processus enfant hérite de chaque descripteur de fichier ouvert du parent, y compris le socket you ouvrir.

1
répondu Heath Hunnicutt 2011-08-04 17:45:19

Comme d'autres l'ont dit, c'est le comportement standard que les programmes dépendent.

quand il s'agit de l'empêcher Vous avez quelques options. Tout d'abord, fermer tous les descripteurs de fichier après le fork(), comme le suggère Dave. Deuxièmement, il y a le support POSIX pour utiliser fcntlFD_CLOEXEC pour définir un bit' close on exec ' sur une base per-fd.

enfin, puisque vous mentionnez que vous utilisez Linux, il y a un ensemble de modifications conçues pour vous permettre de régler le bit à la le point d'ouvrir les choses. Naturellement, cela dépend de la plate-forme. Un aperçu peut être trouvée à http://udrepper.livejournal.com/20407.html

cela signifie que vous pouvez utiliser un bitwise ou avec le 'type' dans votre appel de création de socket pour définir le SOCK_CLOEXEC drapeau. Pourvu que vous utilisiez le noyau 2.6.27 ou plus tard, c'est-à-dire.

1
répondu Arthur Shipkowski 2011-08-04 18:02:34

system() copie le processus courant puis lance un enfant dessus. (processus en cours n'est plus là. c'est probablement la raison pour laquelle pppd utilise le 5060. Vous pouvez essayer fork()/exec() créer un processus enfant et garder le parent en vie.

-1
répondu hari 2011-08-04 17:43:57