Une protection contre les effacements accidentels
Un article de Wiki de la communauté Mandriva.
CETTE PAGE EST UNE VERSION RÉVISÉE DE LA PAGE OBSOLÈTE DE L'ANCIENNE BASE DE CONNAISSANCES : http://club.mandriva.com/xwiki/bin/view/KB/Protect ptyxs 1 mars 2008 à 14:33 (CET)
[modifier] Le problème
Dans Konqueror, vous venez de cliquer sur un fichier et de presser les touches MAJ + SUPPR ? Eh mais... Saperlipopette ! Je ne devais pas effacer ça, nom de nom !!!! Trop tard, le fichier est définitivement irrécupérable avec votre travail de la journée... Ou alors, en console, vous venez de taper quelque chose comme ceci :
et... bon sang de bon soir, je ne devais pas l'effacer maintenant ce grosmachin !! Trop tard... Pour éviter cette situation, il vous est proposé ici une « sauvegarde » systématique qui vous évitera de perdre inconsidérément vos données quand vous faites des bêtises en fin de journée, sous l'empire de la fatigue ou d'une bonne migraine. ATTENTION ce qui est proposé ne tient lieu en aucune façon d'une véritable sauvegarde de vos disques locaux sur des disques externes ou sur des disques d'autres machines, sauvegarde qui reste en tout état de cause absolument indispensable !! Nous exploitons dans ce qui suit les LIENS EN DUR. Je vous recommande donc de regarder, avant d'aller plus loin, la page Liens, liens symboliques et liens en dur. Nous supposerons ce contenu bien assimilé...
Les scripts proposés ici le sont évidemment sans garantie. Prenez-les comme des suggestions et n'hésitez pas à les modifier à votre guise. Même si le problème posé plus haut ne vous paraît pas essentiel, notez bien qu'étudier ces scripts et lire cette page attentivement devrait être aussi pour vous une bonne occasion d'apprendre des choses sur les scripts et sur le système Linux.
Tout ce qui suit est une simple implémentation d'idées originales de FF_Olivier du forum de Geckozone.
[modifier] Note sur l'installation des scripts
Il existe différentes façons d'installer un script sur son système pour le mettre à la disposition de l'ensemble des utilisateurs. Cette question est évidemment indépendante de notre propos. Néanmoins, pour fixer les idées et donner des exemples précis, je vais décrire brièvement comment je procède et je donnerai dans la suite les exemples en fonction de cette description.
Le répertoire /opt contient les applications que j'installe moi-même sans passer par RPM, soit que je les compile moi-même, soit que je les installe par le biais d'archives précompilées, soit qu'il s'agisse de scripts. Bien que ce ne soit pas strictement indispensable, /opt est situé, chez moi, sur une partition différente de / (mais /opt est monté dans /, bien sûr), de façon à pouvoir conserver son contenu en cas de réinstallation du système dans /. C'est à la racine de /opt que je copierai donc les scripts dont il est question ici. D'autre part, toutes les applications de /opt sont chez moi lancées par un lien situé dans le répertoire /usr/local/bin. Ce répertoire doit être dans le $PATH de chaque utilisateur. Je créerai donc dans /usr/local/bin un lien pour chacun des scripts proposés ici que j'utiliserai.
Dans ce qui suit, deux solutions concurrentes sont proposées. Vous pourrez employer :
- soit le script sauvliens.sh et le script sauvliens_stop.sh
- soit le script aSauver.sh et le script aSauver_stop.sh.
(vous pouvez cliquer sur leur nom pour les télécharger).
Vous devrez donc, si vous installez les scripts à ma mode, créer, dans /usr/local/bin, un lien pour chacun des deux scripts choisis. Pour cela, vous pourrez lancer pour chacun d'eux une commande de la forme générale ln -s chemin_du_script, après avoir fait de /usr/local/bin votre répertoire de travail.
Bien entendu, vous restez libre d'installer les scripts d'une autre manière qui vous conviendrait mieux ou vous serait plus habituelle.
N'oubliez pas qu'un script doit être rendu exécutable, par exemple, par un chmod (chmod +x nom_du_script), avant de pouvoir « fonctionner ». Par précaution, je mets ces scripts en la possession de root (chown root: nom_du_script), tout en vérifiant bien que mon chmod les a rendus exécutables par tous. Si ces questions de propriétés et de permissions ne sont pas claires pour vous, lisez la page Permissions du Wiki.
[modifier] Présentation générale de la protection
Effacer un fichier n'est irrémédiable que si ce fichier ne possède qu'un seul « nom ». Créer un lien en dur pour un fichier c'est lui donner un « nom » supplémentaire. L'idée de base de notre mécanisme de protection est donc de créer un lien en dur supplémentaire pour chacun des fichiers à protéger, lien qui sera stocké ailleurs sur le disque dur, bien à part : une fois ceci fait si, dans un répertoire protégé, vous effacez maintenant un fichier, alors vous pourrez encore y accéder (et le restaurer par copie) à partir du lien en dur créé par la procédure que nous proposons ici.
Vous trouverez ici un script appelé sauvliens.sh (cliquez sur son nom pour y accéder). Ce script peut être lancé avec ou sans l'argument init. Lorsque vous lancerez le script sauvliens.sh avec l'argument init, comme ceci :
alors, le script créera, dans un certain sous-répertoire, une réplique complète de l'arborescence (c'est-à-dire de l'emboîtement des répertoires et sous-répertoires) du répertoire que vous souhaitez protéger. Ensuite, il créera, dans cette arborescence, un lien en dur pour chaque fichier régulier du répertoire à protéger. Le répertoire qui contiendra les liens en dur créés par sauvliens.sh s'appellera, pour chaque utilisateur :
.sauvliens (le point initial de son nom en fait un répertoire caché).
Il sera situé à la racine du répertoire à protéger. Si vous y tenez vraiment, vous pourrez modifier le nom du répertoire qui contiendra les liens en dur, ainsi que sa position dans l'arborescence, en changeant la valeur assignée dans le script à certaines variables : NOM_DIR_LIENS et DIR_LIENS. Ensuite, il faudra veiller à étendre cette protection aux fichiers réguliers nouvellement créés. C'est ce que fera le script lorsqu'on l'appellera sans argument, simplement comme ceci :
Lancé de cette façon, le script sauvliens.sh créera, dans le répertoire de sauvegarde .sauvliens, une réplique de tous les nouveaux sous-répertoires du répertoire à protéger qui auront été créés dans les cinq minutes précédentes. Il créera, ensuite, toujours dans .sauvliens, un lien en dur pour tous les fichiers réguliers qui auront, eux aussi, été créés, dans le répertoire à protéger, au cours des cinq minutes précédentes. Le nouveau lien en dur sera placé dans la partie de l'arborescence de .sauvliens qui correspond à sa position dans le répertoire à protéger.
Il ne restera plus qu'à lancer ce script toutes les cinq minutes. Le démon crond pourra s'en charger pour nous, si nous éditons notre crontab d'utilisateur de telle sorte qu'elle contienne une ligne comme celle-ci :
'''*/5 * * * * /usr/local/bin/sauvliens.sh'''
Le script sera alors lancé à l'heure pile puis à 5, 10, 15 etc. Notez bien que chaque utilisateur y compris root doit éditer ainsi sa propre crontab et doit le faire évidemment en lançant la commande crontab -e sous sa propre identité. Pour plus de détails sur l'édition d'une crontab, voir la section du Wiki Planifier des tâches pour l'ordinateur#Planifier l'exécution régulière d'une tâche : le démon crond.
[modifier] Quel répertoire protéger ?
L'identité du répertoire sauvegardé varie selon que le script sauvliens.sh est lancé par un simple utilisateur ou par root.
S'il est lancé par un utilisateur, c'est le répertoire personnel de l'utilisateur qui est protégé et s'il est lancé par root, c'est /etc qui le sera.
L'identité du répertoire préservé peut cependant être aisément modifiée. La partie du script responsable de ce choix est la suivante :
if [ "`id -un `" != "root" ] ; then # si simple utilisateur on sauve tout le répertoire personnel DIR_A_SAUVER=$HOME else # si root on sauve seulement /etc DIR_A_SAUVER=/etc fi
Il serait facile de modifier cela et, par exemple, si vous souhaitiez restreindre le répertoire protégé, pour l'utilisateur, au répertoire Documents, et pour root, à X11, vous devriez modifier le passage qui précède de telle sorte qu'il corresponde à ceci :
if [ "`id -un `" != "root" ] ; then # si simple utilisateur on sauve seulement le répertoire Documents DIR_A_SAUVER=$HOME/Documents else # si root on sauve seulement /etc/X11 DIR_A_SAUVER=/etc/X11 fi
Toutefois, notez bien que la logique du script sauvliens.sh est de sauvegarder un répertoire par utilisateur. Cela me convient très bien et c'est ce que j'utilise. Mais on pourrait imaginer aussi que certains utilisateurs préfèrent sauvegarder plutôt de la sorte, non pas un unique vaste répertoire, mais un certain ensemble (éventuellement variable au fil du temps) de sous-répertoires. Nous verrons plus bas comment il serait possible d'obtenir cela, en ayant recours non plus à sauvliens.sh mais à un autre script : aSauver.sh.
[modifier] Et si je crée un fichier juste avant d'arrêter le système ?
Imaginons que vous créez un fichier à 21h 01 et que vous arrêtez le système à 21h 03. Eh bien, si vous ne relancez pas votre ordinateur avant que cinq minutes ne s'écoulent... la dernière exécution du script sauvliens.sh par crond ayant eu lieu à 21h 00, donc avant la création du fichier, ce fichier ne serait évidemment pas protégé par la prochaine exécution du script, lancée plus de cinq minutes après sa création, et il resterait donc durablement dans une lamentable situation de vulnérabilité...
Pour éviter cela, il serait approprié de lancer la protection à chaque arrêt du système. Voilà comment il est possible d'obtenir ce résultat.
Arrêter le système, c'est le placer dans le niveau d'exécution 0. Les scripts arrêtés ou lancés à cette occasion le sont grâce à des liens symboliques placés dans le répertoire /etc/rc0.d, qui pointent vers des scripts de démarrage/arrêt de certaines applications stockés dans /etc/init.d. Ceci en tête, voilà ce que nous allons faire.
Nous allons d'abord créer un script particulier, destiné à protéger, à l'arrêt du système, pour chaque utilisateur, les différents répertoires que sauvliens.sh protège toutes les cinq minutes lorsque le système est en état de marche. Ce script s'appelle sauvliens_stop.sh (cliquez sur son nom pour y accéder). Comme pour tous mes scripts, je le place dans /opt, avec un lien symbolique dans /usr/local/bin, répertoire qui figure dans le $PATH des utilisateurs, y compris root. Dans /etc/init.d, nous allons placer un script sauvliens_stop (que je vous laisserai le soin de créer vous-même par copier-coller) qui se réduira à appeler notre sauvliens_stop.sh :
#! /bin/sh # script /etc/init.d/sauvliens_stop /usr/local/bin/sauvliens_stop.sh exit 0
et dans /etc/rc0.d, nous allons créer un lien symbolique qui pointera vers le script de /etc/init.d que nous venons de créer. Dans /etc/rc0.d, les seuls liens qui lancent une application sont pour l'instant - en tout cas dans mon système :
lrwxrwxrwx 1 root root 17 nov 24 16:55 S00killall -> ../init.d/killall* lrwxrwxrwx 1 root root 14 nov 24 16:55 S01halt -> ../init.d/halt*
Je vais d'abord décaler leur « ordre d'entrée en scène », puis créer le nouveau lien par la ligne de commande suivante :
mv S01halt S02halt && mv S00killall S01killall && ln -s ../init.d/sauvliens_stop S00sauvliens_stop
(pour le sens de && voir la section l'enchaînement des commandes). Il serait prudent de refaire une manœuvre équivalente dans le répertoire /etc/rc6.d, afin d'obtenir le même résultat en cas de redémarrage. Voici désormais à quoi ressemblent les liens de démarrage de /etc/rc0.d et /etc/rc6.d :
lrwxrwxrwx 1 root root 24 mar 17 18:56 S00sauvliens_stop -> ../init.d/sauvliens_stop* lrwxrwxrwx 1 root root 17 nov 24 16:55 S01killall -> ../init.d/killall* lrwxrwxrwx 1 root root 14 nov 24 16:55 S02halt -> ../init.d/halt*
N'oubliez pas de rendre les scripts /etc/init.d/sauvliens_stop et /opt/sauvliens_stop.sh exécutables via chmod. Et voilà, votre script sauvliens_stop.sh sera exécuté maintenant à chaque arrêt du système. Le problème des cinq dernières minutes de la session est réglé.
Attention : ce sera à l'administrateur root de mettre à jour, chaque fois que ce sera nécessaire, la liste des répertoires à protéger à l'arrêt pour les différents utilisateurs, en éditant la ligne suivante de sauvliens_stop.sh.
LISTE_REP="/etc:/home/toto"
les répertoires sont séparés par deux-points, pour ajouter le répertoire personnel de julie on devrait écrire :
LISTE_REP="/etc:/home/toto:/home/julie"
[modifier] Et pour protéger un ensemble de sous-répertoires ?
Si vous souhaitez non pas protéger la totalité de votre répertoire personnel, mais plutôt un ensemble de sous-répertoires soigneusement choisi par vous, le système proposé jusqu'ici ne convient pas.
Le script que nous utiliserons sera cette fois aSauver.sh.
Dans ce cas, pour chaque utilisateur, y compris root, dans un certain répertoire (qui sera ici $HOME/Reps_A_Sauver), nous plaçons un lien symbolique (je dis bien symbolique...) vers chacun des répertoires que nous souhaitons protéger. Il sera très facile, par la suite, d'ajouter ou d'enlever un tel lien à n'importe quel moment, pour modifier l'inventaire des sous-répertoires à protéger. Le script inspectera ce répertoire et créera des liens en dur pour tous les fichiers que contiennent les sous-répertoires vers lesquels pointent les liens symboliques. Ces liens en dur seront eux-mêmes placés dans un répertoire des liens en dur qui, dans ce script-ci est $HOME/.sauv (un répertoire qui joue ici le même rôle que $HOME/.sauvliens dans le script sauvliens.sh dont nous avons parlé précédemment).
Ce système est plus souple, c'est la protection à la carte.
Pour régler le célèbre « problème des cinq dernières minutes », il faudra utiliser le script aSauver_stop.sh et procéder à des manœuvres analogues à celles effectuées dans le cas précédent, décrites à la section #Et si je crée un fichier juste avant d'arrêter le système ? et que nous vous laisserons le soin d'implémenter.
Il vous faudra aussi, chaque fois que nécessaire, indiquer, dans le script aSauver_stop.sh, la liste des utilisateurs concernés, root éventuellement compris, dans la ligne consacrée à la variable UTILISATEURS (n'oubliez pas de séparer les noms des utilisateurs par des deux-points).
[modifier] Ne pas oublier l'initialisation et le nettoyage
Lorsqu'ils sont employés sans argument, les scripts sauvliens.sh ou aSauver.sh, selon ce que vous aurez choisi, sont conçus pour être lancés toutes les cinq minutes et traiter uniquement les fichiers qui ont été créés depuis leur précédente exécution. Mais il est, bien sûr, nécessaire de protéger la totalité des fichiers réguliers des répertoires que vous avez décidé de protéger. Pour cela, il est indispensable de lancer avant tout, au démarrage de la protection, celui de ces scripts que vous avez retenu avec l'argument init pour initialiser l'ensemble du dispositif, comme nous l'avons mentionné au début de cette page. Cela créera un lien en dur pour tous les fichiers du ou des répertoire(s) à protéger.
Mais l'argument init sert aussi dans un autre type de cas.
Notre système de protection a pour conséquence que dans le répertoire protégé aucun fichier régulier n'est vraiment effacé ! Tant que le lien en dur est là, le fichier reste présent sur le disque. Il est donc concevable que, de temps en temps, si vous manquez d'espace disque, vous ayez besoin de faire disparaître vraiment tous les fichiers que vous avez effacés et de « vider » pour cela le répertoire des liens. C'est ce que vous pourrez obtenir à tout moment en lançant le script avec l'argument init.
[modifier] Quelques apparentes bizarreries découlant de l'option -mmin de la commande find
Nos quatre scripts se terminent par des appels, essentiels, à la commande find. Un appel de commande comme find . -type f -mmin -5 trouve des fichiers créés dans les cinq minutes qui précèdent. Mais il trouvera aussi des fichiers qui ont été simplement modifiés (mais non créés) pendant cette période. Dans ce cas la partie -exec de la ligne du script recréera donc - inutilement - un lien en dur vers le fichier modifié, il s'agira d'une recréation à vide d'un lien de même nom, vers le même fichier et doué des mêmes propriétés que le lien précédent. Rien de bien grave donc. Lorsqu'on a affaire à un dossier modifié, il en va de même. Un dossier au sein duquel on a créé un nouveau fichier est réputé modifié (son horodatage change, du reste) et ce répertoire sera trouvé par une commande find . -type d -mmin -5. Dans ce cas, le script essaiera de créer une réplique du fichier dans le répertoire contenant les liens en dur (.sauvliens ou .sauv). Mais comme mkdir ne peut pas recréer un répertoire existant, la tentative avortera et vous aurez simplement un message d'erreur du type :
mkdir: Ne peut créer le répertoire `./.sauvliens/./Documents': Le fichier existe.
message qui ne doit pas vous inquiéter du tout...
Les messages d'erreur
Les éventuels messages d'erreur générés par l'exécution de nos scripts seront visibles lorsque vous les lancerez en console, à titre d'essai. Dans leur usage normal, lorsque les scripts seront lancés par le démon crond aucune console ne sera ouverte et les messages n'apparaîtront pas. Toutefois, les messages d'erreur vous seront automatiquement expédiés par courrier électronique, si vous avez pris soin d'activer votre mail local.
Tout cela, qui, encore une fois, est sans gravité, pourrait être évité si l'on pouvait chercher des fichiers ou des répertoires en se fondant uniquement sur leur date de création. Je n'en ai pas trouvé le moyen sous la Mandriva.
[modifier] Et si j'efface 'exprès' un fichier et le recrée ensuite ?
L'option -f de la commande ln.
La commande ln utilisée dans les différents scripts proposés, permet de créer un lien en dur (à condition de ne pas être employée avec l'option -s, qui créerait, elle, un lien symbolique). Par exemple, la commande suivante :
ln /home/toto/Documents/fich1
créera dans votre répertoire de travail un lien en dur, appelé lui aussi fich1, vers le fichier /home/toto/Documents/fich1. Si un fichier fich1 (qui peut être un lien en dur que vous avez créé précédemment) existe déjà dans votre répertoire de travail, le nouveau lien ne sera pas créé et vous obtiendrez simplement un message d'erreur :
ln: `./fich1': fichier existant.
Pour que, dans des cas de genre, l'ancien fichier soit écrasé et que le nouveau lien soit donc tout de même créé, vous pouvez faire usage de l'option -f. La ligne de commande :
ln -f /home/toto/Documents/fich1
écrasera un éventuel fichier fich1 déjà présent dans votre répertoire de travail et créera le lien souhaité vers /home/toto/Documents/fich1. Cette option est présente dans tous les emplois de ln de nos scripts.
Quelle en est la conséquence ? Supposons que vous effaciez un fichier, disons /home/toto/Documents/fichouille, faisant partie de l'ensemble des fichiers protégés par notre dispositif. Si, un peu plus tard, vous décidez de créer, en définitive, une nouvelle version de fichouille, de même nom que l'ancienne et au même endroit, que se passera-t-il ? Quelle version de fichouille sera protégée et récupérable à partir d'un lien en dur de « sauvegarde », l'ancienne version ou la nouvelle ? La réponse est simple : si les appels à ln ne contenaient pas, dans nos scripts, l'option -f, le lien en dur de protection fichouille continuerait à pointer vers l'ancien fichier. Le nouveau fichier resterait non protégé, puisque ln ne pourrait pas créer un nouveau lien pointant vers lui, en écrasant l'ancien lien. Cette situation durerait aussi longtemps que le script protecteur ne serait pas lancé avec l'argument init. Si c'est là ce que vous souhaitez, effacez -f partout dans les scripts... Tels qu'ils sont écrits, avec l'option -f toujours spécifiée pour ln, les scripts assurent, au contraire, qu'un lien en dur sera, dans ce cas, créé vers la nouvelle version de fichouille (tandis que l'ancienne version sera, quant à elle, irrémédiablement perdue cinq minutes tout au plus après la création de la nouvelle version...).
[modifier] Autres scripts de protection contre les effacements accidentels
Dans le livre 100 scripts shell UNIX de Dave Taylor, publié chez Eyrolles, les scripts n° 15 Archiver les fichiers détruits et n° 16 Exploiter l'archive des fichiers détruits constituent une solution alternative à celle proposée dans les sections précédentes de cette page. Leur étude, et celle des commentaires de l'auteur de ces scripts présentés dans l'ouvrage en question, est intéressante pour le lecteur soucieux de ces problèmes de protection contre l'effacement. Les scripts eux-mêmes sont téléchargeables sur le site de l'éditeur.
Le script 15 copie les fichiers effacés par la commande /bin/rm dans un répertoire caché spécifique $HOME/.deleted-files. Le script 16 donne un moyen de restaurer les fichiers effacés.
Nous ne tenterons pas une comparaison approfondie des deux approches. Nous noterons juste ceci (au lecteur de regarder de plus près) :
- les scripts 15 et 16 de Dave Taylor ne traitent pas de façon très satisfaisante les cas d'effacements de fichiers de même nom mais situés dans des répertoires différents, un cas qui ne pose aucun problème pour l'approche des sections précédentes
- en cas d'effacements et de recréations de fichiers de même nom situés dans la même position, le système Taylor conserve tous les fichiers effacés successivement (ce qui peut selon les cas constituer un avantage ou un inconvénient), alors que le système des sections précédentes ne protège que la version la plus récente (ou, si on modifie le script, la version la plus ancienne)
- le système Taylor entièrement centré sur la commande rm ne protège pas les fichiers effacés par d'autres moyens, par exemple, dans une interface comme KDE, par vidage de la corbeille (clic droit sur la corbeille suivi du choix de la fonction de vidage), ou simplement les fichiers effacés par Konqueror, alors que les fichiers effacés de cette façon sont protégés par le système proposé dans les sections précédentes.
Signalons, pour terminer, que le script n° 17 de Dave Taylor aborde la question indépendante, mais qui intéressera peut-être certains lecteurs, de la journalisation des effacements.