2010-06-16 17 views
1

Je travaille sur un init pour un initramfs en C++ pour Linux. Ce script est utilisé pour déverrouiller le lecteur crypté DM-Crypt w/LUKS et définir les unités LVM disponibles.Problèmes avec les appels system() sous Linux

Puisque je ne veux pas avoir à réimplémenter la fonctionnalité de cryptsetup et gpg j'utilise des appels système pour appeler les exécutables. L'utilisation d'un appel système pour appeler gpg fonctionne bien si le système est déjà entièrement activé (j'ai déjà un script bash basé sur initramfs qui fonctionne bien pour l'afficher, et j'utilise grub pour éditer la ligne de commande pour l'afficher en utilisant le vieux initramfs). Cependant, dans l'initramfs, il n'agit jamais comme s'il était appelé. Même les commandes comme system("echo BLAH"); échouent.

Alors, est-ce que quelqu'un a quelque chose à ajouter?


Éditer: J'ai donc trouvé ce qui causait mes erreurs. Je n'ai aucune idée de pourquoi il provoquerait des erreurs, mais je l'ai trouvé.

Afin de permettre le branchement à chaud, je devais écrire /sbin/mdev à /proc/sys/kernel/hotplug ... mais je fini par passer autour des paramètres (une fonction que je me suis écrit pas moins) donc j'écrivais /proc/sys/kernel/hotplug à /sbin/mdev.

Je n'ai aucune idée de pourquoi cela causerait le problème, mais il l'a fait.

Répondre

6

Amardeep est juste, system() sur Posix tapez les systèmes exécute la commande via /bin/sh.

Je doute que vous ayez réellement besoin d'invoquer ces programmes dont vous parlez via un shell Bourne. Une bonne raison serait si vous aviez besoin d'avoir l'ensemble de variables d'environnement par défaut, mais puisque /etc/profile est probablement aussi indisponible si tôt dans le processus de démarrage, je ne vois pas comment cela peut être le cas ici.

Au lieu de cela, utiliser le modèle fork()/exec() standard:

int system_alternative(const char* pgm, char *const argv[]) 
{ 
    pid_t pid = fork(); 
    if (pid > 0) { 
     // We're the parent, so wait for child to finish 
     int status; 
     waitpid(pid, &status, 0); 
     return status; 
    } 
    else if (pid == 0) { 
     // We're the child, so run the specified program. Our exit status will 
     // be that of the child program unless the execv() syscall fails. 
     return execv(pgm, argv); 
    } 
    else { 
     // Something horrible happened, like system out of memory 
     return -1; 
    } 
} 

Si vous avez besoin de lire stdout du processus appelé ou envoyer des données à son stdin, vous aurez besoin de faire une redirection de poignée standard via pipe() ou dup2() là-bas.

Vous pouvez tout apprendre sur ce genre de chose dans tout bon livre de programmation Unix. Je recommande Programmation avancée dans l'environnement UNIX par W. Richard Stevens.La deuxième édition co-rédigée par Rago ajoute du matériel pour couvrir les plateformes apparues depuis que Stevens a écrit la première édition, comme Linux et OS X, mais les bases comme celle-ci n'ont pas changé depuis l'édition originale.

+0

Merci beaucoup pour votre aide. Vous avez effectivement répondu à une question que je n'ai pas posée pour savoir pourquoi diable il est dit dans les pages de manuel d'utiliser la famille de fonctions 'exec()' au lieu de 'system()' quand elles ont des effets très différents. Si cela ne vous dérange pas, avez-vous un lien utile pour la sortie de la tuyauterie? (De toute façon, j'ai commandé le livre que vous avez suggéré, donc j'obtiendrai éventuellement une bonne ressource :)) – Thomas

+1

Stevens le couvre dans la section 14.2 dans la première édition. Dans la deuxième édition, il est passé à la section 15.2. –

+0

Merci. Je vais être sûr de le chercher. – Thomas

6

Je crois que la fonction system() exécute votre commande dans un shell. Le shell exécutable est-il monté et disponible au début de votre processus de démarrage? Vous pourriez vouloir utiliser fork() et execve().

EDIT: Assurez-vous que vos outils de cryptographie se trouvent également sur un volume monté.

1

Qu'avez-vous dans initramfs? Vous pouvez effectuer les opérations suivantes:

int main() { 
    return system("echo hello world"); 

} 

Et strace puis dans un initscript comme celui-ci:

strace -o myprog.log myprog 

Regardez le journal une fois que votre système est démarré