Comment puis-je définir des variables d'environnement pour un processus rsync distant?

12

Lorsque j'utilise rsync pour copier des fichiers d'un ordinateur à un autre, un processus rsync démarre aux deux extrémités. Cependant, du côté distant, les fichiers d'initialisation du shell ne sont apparemment pas lus, donc je ne peux pas configurer de variables d'environnement pour le processus rsync distant. Malheureusement, il y a un serveur sur lequel je dois rsync sur lequel rsync requiert une variable d'environnement pour fonctionner. Je ne suis pas administrateur sur le serveur, je ne peux donc pas modifier la configuration globale. Que puis-je faire pour définir des variables d'environnement pour un processus rsync distant?

Ryan C. Thompson
la source
Comment démarrez-vous le processus rsync sur le serveur? Pourriez-vous déclencher un script via ssh?
kraftan
Lorsque vous le faites rsync localfilename remotehost:remotefilename, un processus rsync démarre sur le serveur. Je ne sais pas exactement comment, mais il ne lit aucun fichier d'initialisation du shell.
Ryan C. Thompson

Réponses:

20

~/.profilen'est généralement pas lu lorsque vous exécutez ssh somecommand, contrairement à une session ssh interactive (ou à une autre méthode de connexion où vous démarrez une session interactive).

Ssh prend en charge l'envoi de variables d'environnement. Dans OpenSSH, utilisez la SendEnvdirective dans ~/.ssh/config. Cependant, la variable d'environnement spécifique doit être activée avec une AcceptEnvdirective dans la configuration du serveur , donc cela risque de ne pas fonctionner pour vous.

OpenSSH permet également de définir des variables d'environnement côté serveur. Encore une fois, cela doit être activé dans la configuration du serveur, ici avec la PermitUserEnvironmentdirective. Les variables peuvent être définies dans le fichier ~/.ssh/environment. En supposant que vous utilisez l'authentification par clé publique, vous pouvez également définir des variables par clé dans ~/.ssh/authorized_keys: ajouter environment="FOO=bar"au début de la ligne appropriée.

Une chose qui, selon moi, fonctionne toujours (curieusement) tant que vous utilisez l'authentification par clé publique consiste à (ab) utiliser l' command=option dans le authorized_keysfichier. Une clé avec une commandoption n'est valable que pour exécuter la commande spécifiée; mais la commande du authorized_keysfichier s'exécute avec la variable d'environnement SSH_ORIGINAL_COMMANDdéfinie sur la commande spécifiée par l'utilisateur (vide pour les sessions interactives). Vous pouvez donc utiliser quelque chose comme ça dans ~/.ssh/authorized_keys(bien sûr, cela ne s'appliquera pas si vous n'utilisez pas cette clé pour vous authentifier):

command="export LD_LIBRARY_PATH=\"$HOME\"/lib;
         if [ -n \"$SSH_ORIGINAL_COMMAND\" ]; then
           eval \"$SSH_ORIGINAL_COMMAND\";
         else exec \"$SHELL\"; fi" ssh-rsa …

Notez que j'ai mis des sauts de ligne ci-dessus pour plus de lisibilité, mais cela doit en fait être tout sur une seule ligne.

Une autre possibilité consiste à écrire un script wrapper ~/bin/rsync-wrappersur le serveur, quelque chose comme

#!/bin/sh
. ~/.profile
exec rsync "$@"

Passez ensuite --rsync-path='bin/rsync-wrapper'sur la rsyncligne de commande. L'argument to --rsync-pathest développé par un shell, donc si vous préférez, vous pouvez rendre la ligne de commande rsync autonome en passant quelque chose comme --rsync-path='. ~/.profile; rsync'.

Il existe une autre avenue qui dépend de votre shell de connexion étant bash ou zsh. Bash lit toujours ~/.bashrcquand il est invoqué par rshd ou sshd, même s'il n'est pas interactif (mais pas s'il est appelé comme sh). Zsh lit toujours ~/.zshenv.

## ~/.bashrc
if [[ $- != *i* ]]; then
  # Either .bashrc was sourced explicitly, or this is an rsh/ssh session.
  . ~/.profile
fi

## ~/.zshenv
if [[ $(ps -p $PPID -o comm=) = [rs]shd && $- != *l* ]]; then
  # Not a login shell, but this is an rsh/ssh session
  . ~/.profile
fi
Gilles 'SO- arrête d'être méchant'
la source
Eh bien, cela résume à peu près. J'espérais qu'il y avait une meilleure façon que d'utiliser un script wrapper.
Ryan C. Thompson
Mais attendez une minute. Si mes fichiers shell init ne sont pas lus, comment peut-il même trouver le binaire rsync sur le serveur? J'ai installé dans ~ / usr, un emplacement non standard que je dois ajouter à mon $PATHdans mes scripts d'initialisation shell.
Ryan C. Thompson
@Ryan: J'avais en fait oublié la méthode la plus directe (voir ma modification), mais elle nécessite également une directive pour être activée dans la configuration du serveur. Si vous avez trouvé un moyen de prendre votre PATHcompte en compte, vous devriez pouvoir y définir n'importe quelle autre variable. (Si cela ne fonctionne pas, essayez d'ajouter autant de traces que possible, en commençant par set -xn'importe quel script shell; remplacez le rsyncbinaire par un script wrapper qui vide l'environnement dans un fichier puis appelle le vrai binaire.)
SO de Gilles - Arrêtez d'être méchant '
Et alors ~/.ssh/rc?
Ryan C. Thompson
@Ryan: ~/.ssh/rcest exécuté par un processus shell séparé. Je pense que votre meilleur pari est un script wrapper ou --rsync-path='. ~/.profile; rsync'. Ou recompiler rsyncavec un chemin approprié selon votre autre question.
Gilles 'SO- arrête d'être méchant'