La dernière fois j'ai montré comment Perl peut émuler bon nombre des filtres et autres outils de gestion de l'information d'UNIX. En retour du temps ainsi passé à "réinventer la roue", vous obtenez des scripts plus portables. Au bout d'un certain temps vous finirez quand même par devoir invoquer des commandes du système. C'est là que vous rencontrerez les véritables problèmes de portabilité. "Dans quel répertoire se trouve donc cette commande, et quelles sont ses options ?" Dans certains cas le nom même de la commande diffère - sur certaines machines system V, rsh est le shell restreint alors que remsh exécute les commandes sur la machine distante. Cet article est destiné à vous aider à vous y retrouver dans la tour de babel des dialectes UNIX et se termine par un shell script qui tournera sur la pluspart d'entre eux. Cet article parle peu de Perl, si donc vous n'avez pas le souci de maintenir des scripts pour de nombreuses architectures, peut-être ne vous interessera-t-il pas.
/bin/arch
qui retourne d'une façon ou d'une autre le constructeur et
l'architecture de la machine sur laquelle votre script exécute. La
commande arch
ne retourne pas toujours la version de l'OS
(c'est parfois bien utile), de plus, elle n'est pas universelle. Il
vaut donc mieux essayer /bin/uname
. Vous pouvez obtenir le hostname de la machine, son type d'OS et son architecture matérielle par l'instruction suivante :
($host, $os, $arch) = split(/\s+/, '/bin/uname -nrm');Ceci fonctionne sur tous les UNIX que j'ai rencontrés excepté sur Convex, qui pour des raisons que j'ignore n'implémente pas
uname
. Pour les machines dépourvues de la commande
uname
, il vous suffit de traiter un cas spécial sur la
base de /bin/hostname
. Si vous avez un grand nombre de
machines de ce cas particulier, vous pouvez construire un tableau
associatif static :
ENV{`PATH'} = "/bin:/usr/bin"; %machines = ("convex1", "ConvexOS: Convex", ...); ($host, $os, $arch) = split(/\s+/, '/bin/uname -nrm'); unless ($host) { chop($host = 'hostname'); ($os, $arch) = split(/:/, $machines{$host}); die "Unknown: $host\n" unless ($os); }Notez que j'ai utilisé un chemin relatif pour l'invocation de la commande hostname. (hostname se trouve dans
/bin
ou
/usr/bin
selon le type d'UNIX que vous utilisez. Je ne
l'ai jamais rencontré ailleurs). Si vous utilisez des chemins relatifs
dans vos scripts prenez bien soin d'initialiser $PATH
avec une liste de répertoires réputés sains ou vous vous exposez à des
chevaux de troie. N'incluez jamais le répertoire courant (".") ou un
répertoire utilisateur dans $PATH
.
Le problème est que les chaînes $os
et plus encore
$arch
ont une signification pour le constructeur mais pas
forcément pour les utilisateurs. Par example, sur les machines SGI
$arch
à la forme "IP\d+" alors que sur Amdahls c'est un
code numérique du type "580". Vous n'avez pas d'autre alternative
qu'examiner toutes vos machines pour obtenir la liste exhaustive des
valeurs possibles.
Quand vous aurez identifié le type de votre machine, vous pourrez choisir des valeurs par défaut puis les modifier en fonction de l'architectures et de la version de l'OS :
$bigwords = 0; $gooduucp = 1; $confdir = "/etc"; $ps = "ps -e" if ($arch =~ /^sun/) { $ps = "ps -ax"; $gooduucp = 0 unless ($os =~ /^4\./); } elsif ($arch =~ /^IP\d+$/) { $confdir = "/usr/etc"; } elsif ($arch =~ /^CRAY/) { $bigwords = 1; } : : else { die "$host: unknown arch $arch\n"; }Les Suns utilisent une commande ps à la Berkeley (à moins que vous ne tourniez Solaris 2.x - voyez pour celà
$os
). Les vieilles
versions de Sun ont un UUCP déficient. Les machines SGI rangent les
fichiers de configuration dans /usr/etc
au lieu de
/etc
. Les machines CRAY ont des mots longs, il faut être
prudent avec les shifts binaires. C'est une bonne précaution que de
traiter le cas des architectures inconnues.
Une solution consiste à implémenter un fichier de configuration
universelle qui définit les valeurs par défaut pour tous vos scripts
Perl. Rangez ce script au même endroit sur toutes vos machines, et vos
scripts n'ont qu`à invoquer ce fichier par require
ou par :
eval { do "$configfile"; }; die "Error in $configfile:\n$@" if ($@);Souvenez vous que si vous utilisez
require
, la dernière
instruction du fichier doit s'evaluer à vrai. La pluspart des packages
se terminenet simplement par :
1;
Si vous avez de nombreuses architectures ou de nombreux scripts Perl, ces conditions peuvent être longues. En revanche, vous n'avez qu'un seul fichier à maintenir, et il est relativement aisé d'ajouter une nouvelle architecture et de porter l'ensemble de vos script d'un seul coup.
Un seconde approche consiste à avoir un fichier de configuration par
machine dans
La troisième approche est en fait le mélange des deux idées
précédantes. Placez l'information spécifique d'une architécture ou
d'un OS dans des fichiers différents mais au même endroit pour chaque
machine. Une convention de nommage appropriée permettra à vos scripts
d'utiliser le bon :
Quelque soit la méthode que vous choisirez, faites attention à éviter
les collisions entre les noms de variables utilisées dans les scripts
et les fichiers de configuration. J'ai tendance à utiliser des
majuscules pour les variables des fichiers de configuration et des
minuscules dans les scripts.
1. Arnold, Bob, "If You've Seen One UNIX, You've Seen Them All", LISA
V Conference Proceedings, 1991.
/etc
. Vous pouvez alors simplement utiliser
des assignations au lieu d'avoir de longues conditionnelles. Bien que
ceci puisse paraître coûteux, il y a en fait de fortes chances pour
que vous n'ayez qu'un fichier par architecture ou au pire quelques
fichiers par architectures si vous avez de nombreuses versions d'OS
installées. Vous pourez distribuer les fichiers sur vos machines
depuis une machines "maîtresse" par un outil du type
rdist. Vous pouvez même imaginer un script
"méta-configurateur" tournant dans un cron qui reconstruit
automatiquement ce fichier sur chaque machine (un programme en Bourne
shell a été présenté par Bob Arnold à LISAV1).
$configdir = "/usr/local/configs";
($host, $os, $arch) = split(/\s+/, `/bin/uname -nrm`);
die "$host: no config file $arch.$os\n" unless (-f "$configdir/$arch.$os");
eval { "do $configdir/$arch.$os"; };
die "$host: config error:\n$@" if ($@);
Dans ce cas, tous les fichiers config
sont dans
/usr/local/configs
et ont leur nom composé de
$arch
et $os
retrounés par la commande
uname
.
Conclusion
Tout ceci vous apparaît certainement comme un gaspillage d'énerie si
vous n'êtes pas administrateur d'un gros site ou si vous n'avez qu'une
ou deux architectures à maintenir, et vous avez tout à fait
raison. (Je vous avais d'ailleurs prévenu dès le début de cet
article). Mais si vous êtes administrateur d'un gros site et que vous
vous bagarez avec de nombreux scripts Perl, ces technique vous
simplifiront grandement la vie.
Traduction de ;login: Vol. 19 No. 1, February 1994.
Dernière édition: 15 mars 1998 phb
Original 11/25/96pc
Back to the original
Retour à l'index