Compare commits
16 Commits
e6263c1ae2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 174e43ea19 | |||
| 2949248446 | |||
| 647e1ae4ad | |||
| 3050b6d7c0 | |||
| 03b9505634 | |||
| e30ee21c12 | |||
| e949e4cec9 | |||
| dec199480e | |||
| 802dff942c | |||
| 20fd5f1110 | |||
| 5a42d7a100 | |||
| b11b353171 | |||
| 2c6ecd80a7 | |||
| a646c2f4be | |||
| 479fe9c1f1 | |||
| 2b8690c34b |
@@ -0,0 +1,66 @@
|
|||||||
|
# DEVELOPER.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Workflow de développement
|
||||||
|
|
||||||
|
**Toujours lancer depuis la racine du projet** (vérifié par le Makefile).
|
||||||
|
|
||||||
|
### Ajouter un nouveau script
|
||||||
|
|
||||||
|
1. Placer le script dans `local/bin/<nom>.sh`
|
||||||
|
2. Créer la documentation dans `local/share/doc/scripts-bash/<nom>.1.md` (format man Markdown)
|
||||||
|
3. Lancer `make build` — génère la page man dans `local/share/man/man1/<nom>.1` via Pandoc
|
||||||
|
4. Committer les trois fichiers (`local/bin/`, `local/share/doc/`, `local/share/man/`)
|
||||||
|
5. Pousser
|
||||||
|
|
||||||
|
### Commandes
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make build # Développeur : génère les pages man depuis les .1.md (nécessite Pandoc)
|
||||||
|
make install # Utilisateur : déploie tout dans ~/.local/
|
||||||
|
make uninstall # Supprime les fichiers installés
|
||||||
|
make clean # Supprime les pages man générées localement
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
local/bin/ → scripts déployés dans ~/.local/bin (.sh retiré à l'install)
|
||||||
|
local/share/doc/ → documentation source en Markdown (format man)
|
||||||
|
local/share/man/ → pages man pré-générées via Pandoc (ne pas éditer manuellement)
|
||||||
|
local/share/ytdll/ → config et libs pour le script ytdll
|
||||||
|
ecoleA/ → scripts d'administration pour déploiements école
|
||||||
|
servers/linux/ → scripts serveur Linux
|
||||||
|
```
|
||||||
|
|
||||||
|
### Makefile
|
||||||
|
|
||||||
|
`make install` lit les sources directement avec `$(wildcard ...)` — pas de fichiers de listing intermédiaires. Les scripts `.sh` sont installés sans extension dans `~/.local/bin`. Les autres (PHP, sans extension) sont copiés tels quels.
|
||||||
|
|
||||||
|
`make build` est une cible développeur (nécessite Pandoc). Les pages man générées sont committées dans le dépôt pour que `make install` fonctionne sans Pandoc côté utilisateur.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
Chaque script doit avoir une fiche `local/share/doc/scripts-bash/<nom>.1.md` avec au minimum les sections `# NOM`, `# SYNOPSIS`, `# DESCRIPTION`.
|
||||||
|
|
||||||
|
### Remote Git
|
||||||
|
|
||||||
|
Le remote `origin` utilise SSH (`git@git.abonnel.fr:cedricAbonnel/scripts-bash.git`).
|
||||||
|
Les credentials ne transitent jamais dans l'URL.
|
||||||
|
|
||||||
|
### Signature GPG des releases
|
||||||
|
|
||||||
|
`make install` vérifie la signature GPG du dernier tag avant d'installer.
|
||||||
|
Chaque release doit être taguée et signée :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git tag -s v1.x -m "Release v1.x"
|
||||||
|
git push origin v1.x
|
||||||
|
```
|
||||||
|
|
||||||
|
Pour que les utilisateurs puissent vérifier, ils doivent importer la clé publique du développeur :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gpg --keyserver keys.openpgp.org --recv-keys <ID_CLÉ>
|
||||||
|
```
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
Licence Publique de l'Union européenne v. 1.2
|
||||||
|
EUPL © Union européenne 2007, 2016
|
||||||
|
|
||||||
|
La présente licence publique de l'Union européenne («EUPL») s'applique à toute œuvre (telle que
|
||||||
|
définie ci-dessous) fournie aux conditions de la présente licence. Toute utilisation de l'œuvre autre
|
||||||
|
que celle autorisée en vertu de la présente licence est interdite (dans la mesure où pareille utilisation
|
||||||
|
est couverte par un droit du titulaire des droits d'auteur sur l'œuvre).
|
||||||
|
|
||||||
|
L'œuvre est fournie aux conditions de la présente licence quand le donneur de licence (tel que défini
|
||||||
|
ci-dessous) a placé la mention suivante immédiatement après la déclaration relative au droit d'auteur
|
||||||
|
sur l'œuvre:
|
||||||
|
|
||||||
|
Sous licence EUPL
|
||||||
|
|
||||||
|
ou a exprimé de toute autre manière sa volonté de fournir l'œuvre sous licence EUPL.
|
||||||
|
|
||||||
|
1. Définitions
|
||||||
|
|
||||||
|
Dans la présente licence, on entend par:
|
||||||
|
— «licence», la présente licence,
|
||||||
|
— «œuvre originale», l'œuvre ou le logiciel distribué ou communiqué par le donneur de licence en
|
||||||
|
vertu de la présente licence, disponible sous forme de code source et, le cas échéant, également
|
||||||
|
sous forme de code exécutable,
|
||||||
|
— «œuvres dérivées», les œuvres ou logiciels qui pourraient être créés par le licencié sur la base de
|
||||||
|
l'œuvre originale ou des modifications qui y auraient été apportées. La présente licence ne définit
|
||||||
|
pas le degré de modification ou de dépendance requis par rapport à l'œuvre originale pour qu'une
|
||||||
|
œuvre soit qualifiée d'œuvre dérivée; cette question est réglée par la loi applicable en matière de
|
||||||
|
droit d'auteur dans le pays mentionné à l'article 15,
|
||||||
|
— «œuvre», l'œuvre originale ou ses œuvres dérivées,
|
||||||
|
— «code source», la forme de l'œuvre lisible par l'homme, la plus appropriée pour que des
|
||||||
|
personnes puissent l'examiner et la modifier,
|
||||||
|
— «code exécutable», tout code qui a généralement été compilé et qui est destiné à être interprété
|
||||||
|
comme un programme par un ordinateur,
|
||||||
|
— «donneur de licence», la personne physique ou morale qui distribue ou communique l'œuvre sous
|
||||||
|
licence,
|
||||||
|
— «contributeur(s)», toute personne physique ou morale qui modifie l'œuvre sous licence, ou
|
||||||
|
contribue de toute autre manière à en faire une œuvre dérivée,
|
||||||
|
— «licencié» ou «vous», toute personne physique ou morale qui utilise l'œuvre conformément à la
|
||||||
|
licence,
|
||||||
|
— «distribution» ou «communication», tout acte de vente, don, prêt, location, distribution,
|
||||||
|
communication, transmission ou mise à disposition, en ligne ou hors ligne, de copies de l'œuvre,
|
||||||
|
et tout acte donnant accès à ses fonctions essentielles à toute autre personne physique ou morale.
|
||||||
|
|
||||||
|
2. Portée des droits accordés par la licence
|
||||||
|
|
||||||
|
Le donneur de licence vous concède, pour la durée de la protection de son droit d'auteur sur l'œuvre
|
||||||
|
originale, une licence mondiale, libre de redevances, non exclusive et pouvant faire l'objet de
|
||||||
|
sous-licences, vous permettant de:
|
||||||
|
— utiliser l'œuvre en toutes circonstances et pour tout usage,
|
||||||
|
— reproduire l'œuvre,
|
||||||
|
— modifier l'œuvre et créer des œuvres dérivées sur la base de l'œuvre,
|
||||||
|
— communiquer l'œuvre au public, ce qui inclut le droit de mettre à disposition du public ou
|
||||||
|
d'exposer l'œuvre ou des copies de l'œuvre et d'en effectuer des représentations publiques, le
|
||||||
|
cas échéant,
|
||||||
|
— distribuer l'œuvre ou des copies de celle-ci,
|
||||||
|
— prêter et louer l'œuvre ou des copies de celle-ci,
|
||||||
|
— accorder en sous-licence des droits sur l'œuvre ou sur des copies de celle-ci.
|
||||||
|
|
||||||
|
Ces droits peuvent être exercés sur tout support et format, connu ou encore à inventer, dans la
|
||||||
|
mesure où le droit applicable le permet.
|
||||||
|
|
||||||
|
Dans les pays où des droits moraux s'appliquent, le donneur de licence renonce à son droit d'exercer
|
||||||
|
son droit moral dans la mesure permise par la loi afin que la licence sur les droits patrimoniaux
|
||||||
|
énumérés ci-dessus produise ses effets.
|
||||||
|
|
||||||
|
Le donneur de licence vous concède un droit de brevet non exclusif, libre de toutes redevances, pour
|
||||||
|
toute revendication de brevet qu'il détient, dans la mesure nécessaire à l'exercice des droits qui vous
|
||||||
|
sont concédés sur l'œuvre sous licence.
|
||||||
|
|
||||||
|
3. Communication du code source
|
||||||
|
|
||||||
|
Le donneur de licence fournit l'œuvre sous forme de code source ou de code exécutable. Si l'œuvre
|
||||||
|
est fournie sous forme de code exécutable, le donneur de licence fournit, en plus, une copie lisible
|
||||||
|
par machine du code source de l'œuvre à chaque exemplaire de l'œuvre que le donneur de licence
|
||||||
|
distribue, ou indique, dans un avis mentionné après la déclaration relative au droit d'auteur jointe à
|
||||||
|
l'œuvre, un dépôt où le code source est accessible aisément et gratuitement aussi longtemps que le
|
||||||
|
donneur de licence continue à distribuer ou à communiquer l'œuvre.
|
||||||
|
|
||||||
|
4. Limitations du droit d'auteur
|
||||||
|
|
||||||
|
Les dispositions de la présente licence n'ont pas pour but de priver le licencié des avantages
|
||||||
|
résultant de toute exception ou limitation aux droits exclusifs des titulaires de droits sur l'œuvre,
|
||||||
|
de l'épuisement de ces droits ou d'autres limitations qui s'y appliquent.
|
||||||
|
|
||||||
|
5. Obligations du licencié
|
||||||
|
|
||||||
|
La concession des droits susmentionnés est soumise à des restrictions et à des obligations pour le
|
||||||
|
licencié. Ces obligations sont les suivantes:
|
||||||
|
|
||||||
|
Droit d'attribution: le licencié doit laisser intacts tous les avis relatifs au droit d'auteur, aux brevets
|
||||||
|
ou aux marques, ainsi que tous les avis faisant référence à la licence et à l'exclusion de garanties.
|
||||||
|
Le licencié doit fournir une copie de ces avis et de la licence à chaque exemplaire de l'œuvre qu'il
|
||||||
|
distribue ou communique. Le licencié veille à ce que toute œuvre dérivée soit assortie d'un avis bien
|
||||||
|
visible indiquant que l'œuvre a été modifiée et mentionnant la date de modification.
|
||||||
|
|
||||||
|
Clause copyleft: si le licencié distribue ou communique des copies de l'œuvre originale ou d'œuvres
|
||||||
|
dérivées, cette distribution ou communication est effectuée dans les conditions de la présente licence
|
||||||
|
ou d'une version ultérieure de la présente licence, sauf si l'œuvre originale est expressément
|
||||||
|
distribuée en vertu de la présente version de la licence uniquement. Le licencié (qui devient donneur
|
||||||
|
de licence) ne peut pas, en ce qui concerne l'œuvre ou les œuvres dérivées, offrir ou imposer des
|
||||||
|
conditions supplémentaires qui restreignent ou modifient les conditions de la licence.
|
||||||
|
|
||||||
|
Clause de compatibilité: si le licencié distribue ou communique des œuvres dérivées ou des copies
|
||||||
|
de telles œuvres basées à la fois sur l'œuvre et sur une autre œuvre concédée sous une licence
|
||||||
|
compatible, la distribution ou la communication peut être effectuée dans les conditions de ladite
|
||||||
|
licence compatible. Aux fins de la présente clause, une «licence compatible» est l'une des licences
|
||||||
|
énumérées dans l'appendice de la présente licence. Dans le cas où les obligations du licencié au titre
|
||||||
|
de la licence compatible entrent en conflit avec les obligations du licencié au titre de la présente
|
||||||
|
licence, les premières prévalent.
|
||||||
|
|
||||||
|
Fourniture du code source: lorsqu'il distribue ou communique des copies de l'œuvre, le licencié
|
||||||
|
fournit une copie lisible par machine du code source ou indique un dépôt où ce code est accessible
|
||||||
|
aisément et gratuitement aussi longtemps que le donneur de licence continue à distribuer ou à
|
||||||
|
communiquer l'œuvre.
|
||||||
|
|
||||||
|
Protection des droits: la présente licence ne vous autorise pas à distribuer ou à communiquer
|
||||||
|
l'œuvre d'une manière restreignant ou contrôlant les droits de tiers sur l'œuvre, notamment en ce
|
||||||
|
qui concerne l'exercice de l'un des droits concédés par la présente licence.
|
||||||
|
|
||||||
|
6. Chaîne d'auteurs
|
||||||
|
|
||||||
|
Le donneur de licence initial garantit que les droits d'auteur sur l'œuvre originale concédés en vertu
|
||||||
|
de la présente licence lui appartiennent ou lui ont été donnés en licence, et qu'il a le droit et le
|
||||||
|
pouvoir de concéder la licence.
|
||||||
|
|
||||||
|
Tout contributeur garantit que les droits d'auteur sur les modifications qu'il apporte à l'œuvre lui
|
||||||
|
appartiennent ou lui ont été donnés en licence, et qu'il a le droit et le pouvoir de concéder la licence.
|
||||||
|
|
||||||
|
Chaque fois que vous acceptez la présente licence, le donneur de licence initial et les contributeurs
|
||||||
|
ultérieurs vous concèdent une licence sur leurs contributions à l'œuvre selon les conditions de la
|
||||||
|
présente licence.
|
||||||
|
|
||||||
|
7. Exclusion de garantie
|
||||||
|
|
||||||
|
L'œuvre est un travail en cours, amélioré de manière continue par de nombreux contributeurs. Elle
|
||||||
|
n'est pas une œuvre achevée et peut donc contenir des défauts ou bogues inhérents à ce type de
|
||||||
|
développement.
|
||||||
|
|
||||||
|
Pour cette raison, l'œuvre est fournie sous licence en l'état et sans garanties d'aucune sorte
|
||||||
|
concernant l'œuvre, y compris, sans se limiter à, la valeur marchande, l'adéquation à un objectif
|
||||||
|
particulier, l'absence de défauts ou d'erreurs, l'exactitude, le respect de droits de propriété
|
||||||
|
intellectuelle autres que le droit d'auteur comme prévu à l'article 6 de la présente licence.
|
||||||
|
|
||||||
|
Cette exclusion de garantie est une partie essentielle de la licence et une condition préalable à la
|
||||||
|
concession de tout droit sur l'œuvre.
|
||||||
|
|
||||||
|
8. Exclusion de responsabilité
|
||||||
|
|
||||||
|
Sauf dans les cas de faute intentionnelle ou de dommages causés directement à des personnes
|
||||||
|
physiques, le donneur de licence n'est en aucun cas responsable des dommages, quelle qu'en soit la
|
||||||
|
nature, directs ou indirects, matériels ou moraux, résultant de la licence ou de l'utilisation de l'œuvre,
|
||||||
|
y compris, sans se limiter à, les dommages causés par les atteintes à la réputation, les interruptions
|
||||||
|
de travail, les défaillances ou le mauvais fonctionnement de matériel informatique, les pertes de
|
||||||
|
données ou tout autre préjudice économique, même si le donneur de licence a été informé de la
|
||||||
|
possibilité de tels dommages.
|
||||||
|
|
||||||
|
Cependant, le donneur de licence sera responsable en vertu des dispositions législatives et
|
||||||
|
réglementaires relatives à la responsabilité du fait des produits dans la mesure où celles-ci
|
||||||
|
s'appliquent à l'œuvre.
|
||||||
|
|
||||||
|
9. Accords additionnels
|
||||||
|
|
||||||
|
Lors de la distribution de l'œuvre, vous pouvez choisir de conclure un accord additionnel, définissant
|
||||||
|
des obligations ou des services compatibles avec la présente licence. Toutefois, si vous acceptez des
|
||||||
|
obligations, vous ne pouvez agir qu'en votre nom propre et sous votre seule responsabilité, et non au
|
||||||
|
nom du donneur de licence initial ou de tout autre contributeur, et seulement si vous acceptez
|
||||||
|
d'indemniser, de défendre et de tenir ces contributeurs hors de cause pour tout dommage subi et
|
||||||
|
toute obligation assumée du fait de la garantie ou de la responsabilité additionnelle ainsi acceptée.
|
||||||
|
|
||||||
|
10. Acceptation de la licence
|
||||||
|
|
||||||
|
Vous pouvez exprimer votre accord sur le contenu de la présente licence en cliquant sur l'icône
|
||||||
|
«J'accepte» placée au bas d'une fenêtre affichant le texte de la présente licence ou par toute autre
|
||||||
|
manifestation similaire de votre consentement.
|
||||||
|
|
||||||
|
11. Information du public
|
||||||
|
|
||||||
|
En cas de distribution ou de communication électronique de l'œuvre (par exemple en permettant de la
|
||||||
|
télécharger à distance), le canal de distribution ou le support (par exemple un site internet) doit
|
||||||
|
fournir au public les informations minimales requises par le droit applicable en ce qui concerne le
|
||||||
|
donneur de licence, la licence et la manière dont elle peut être accessible, acceptée, conservée et
|
||||||
|
reproduite par le licencié.
|
||||||
|
|
||||||
|
12. Fin de la licence
|
||||||
|
|
||||||
|
La licence et les droits qu'elle concède prennent automatiquement fin dès que le licencié viole l'une de
|
||||||
|
ses conditions. Cet événement ne met pas fin aux licences des personnes ayant reçu l'œuvre du
|
||||||
|
licencié sous la présente licence, pour autant que ces personnes respectent pleinement la licence.
|
||||||
|
|
||||||
|
13. Divers
|
||||||
|
|
||||||
|
Sans préjudice de l'article 9, la licence représente l'accord complet entre les parties quant à l'œuvre.
|
||||||
|
Si une disposition de la licence est invalide ou inapplicable en vertu du droit applicable, cela n'affecte
|
||||||
|
pas la validité ou l'applicabilité de la licence dans son ensemble. Une telle disposition sera interprétée
|
||||||
|
ou modifiée dans la mesure nécessaire pour la rendre valide et applicable.
|
||||||
|
|
||||||
|
La Commission européenne peut publier d'autres versions linguistiques ou de nouvelles versions de la
|
||||||
|
présente licence ou des versions actualisées de son appendice, dans la mesure où cela s'avère
|
||||||
|
nécessaire et raisonnable, sans réduire la portée des droits accordés par la licence. Les nouvelles
|
||||||
|
versions seront publiées avec un numéro de version distinct.
|
||||||
|
|
||||||
|
Toutes les versions linguistiques de la présente licence, approuvées par la Commission européenne,
|
||||||
|
ont la même valeur. Les parties peuvent se prévaloir de la version linguistique de leur choix.
|
||||||
|
|
||||||
|
14. Juridiction compétente
|
||||||
|
|
||||||
|
Sans préjudice d'un accord spécifique entre les parties:
|
||||||
|
— tout litige résultant de l'interprétation de la présente licence survenant entre les institutions, organes,
|
||||||
|
offices et agences de l'Union européenne, en tant que donneurs de licence, et un licencié, sera
|
||||||
|
soumis à la juridiction de la Cour de justice de l'Union européenne, conformément à l'article 272 du
|
||||||
|
traité sur le fonctionnement de l'Union européenne,
|
||||||
|
— tout litige survenant entre d'autres parties et résultant de l'interprétation de la présente licence sera
|
||||||
|
soumis à la juridiction exclusive du tribunal compétent du lieu où le donneur de licence réside ou
|
||||||
|
exerce son activité principale.
|
||||||
|
|
||||||
|
15. Droit applicable
|
||||||
|
|
||||||
|
Sans préjudice d'un accord spécifique entre les parties:
|
||||||
|
— la présente licence est régie par le droit de l'État membre de l'Union européenne où le donneur de
|
||||||
|
licence réside ou a son siège social ou statutaire,
|
||||||
|
— la présente licence est régie par le droit belge si le donneur de licence ne réside pas et n'a pas son
|
||||||
|
siège social ou statutaire dans un État membre de l'Union européenne.
|
||||||
|
|
||||||
|
Appendice
|
||||||
|
|
||||||
|
Les «licences compatibles» au sens de l'article 5 de l'EUPL sont:
|
||||||
|
— GNU General Public License (GPL) v. 2, v. 3
|
||||||
|
— GNU Affero General Public License (AGPL) v. 3
|
||||||
|
— Open Software License (OSL) v. 2.1, v. 3.0
|
||||||
|
— Eclipse Public License (EPL) v. 1.0
|
||||||
|
— CeCILL v. 2.0, v. 2.1
|
||||||
|
— Mozilla Public Licence (MPL) v. 2
|
||||||
|
— GNU Lesser General Public Licence (LGPL) v. 2.1, v. 2.2
|
||||||
|
— Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) pour les œuvres autres
|
||||||
|
que les logiciels
|
||||||
|
— European Union Public Licence (EUPL) v. 1.1, v. 1.2
|
||||||
|
— Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) ou Strong Reciprocity (LiLiQ-R+)
|
||||||
|
|
||||||
|
La Commission européenne peut actualiser cet appendice pour y inclure des versions ultérieures des
|
||||||
|
licences ci-dessus sans produire de nouvelle version de l'EUPL, dès lors que ces versions prévoient la
|
||||||
|
concession des droits mentionnés à l'article 2 de la présente licence et protègent le code source
|
||||||
|
couvert contre l'appropriation exclusive.
|
||||||
|
|
||||||
|
Tout autre changement ou ajout à cet appendice requiert la production d'une nouvelle version de l'EUPL.
|
||||||
@@ -1,427 +0,0 @@
|
|||||||
Attribution-ShareAlike 4.0 International
|
|
||||||
|
|
||||||
=======================================================================
|
|
||||||
|
|
||||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
|
||||||
does not provide legal services or legal advice. Distribution of
|
|
||||||
Creative Commons public licenses does not create a lawyer-client or
|
|
||||||
other relationship. Creative Commons makes its licenses and related
|
|
||||||
information available on an "as-is" basis. Creative Commons gives no
|
|
||||||
warranties regarding its licenses, any material licensed under their
|
|
||||||
terms and conditions, or any related information. Creative Commons
|
|
||||||
disclaims all liability for damages resulting from their use to the
|
|
||||||
fullest extent possible.
|
|
||||||
|
|
||||||
Using Creative Commons Public Licenses
|
|
||||||
|
|
||||||
Creative Commons public licenses provide a standard set of terms and
|
|
||||||
conditions that creators and other rights holders may use to share
|
|
||||||
original works of authorship and other material subject to copyright
|
|
||||||
and certain other rights specified in the public license below. The
|
|
||||||
following considerations are for informational purposes only, are not
|
|
||||||
exhaustive, and do not form part of our licenses.
|
|
||||||
|
|
||||||
Considerations for licensors: Our public licenses are
|
|
||||||
intended for use by those authorized to give the public
|
|
||||||
permission to use material in ways otherwise restricted by
|
|
||||||
copyright and certain other rights. Our licenses are
|
|
||||||
irrevocable. Licensors should read and understand the terms
|
|
||||||
and conditions of the license they choose before applying it.
|
|
||||||
Licensors should also secure all rights necessary before
|
|
||||||
applying our licenses so that the public can reuse the
|
|
||||||
material as expected. Licensors should clearly mark any
|
|
||||||
material not subject to the license. This includes other CC-
|
|
||||||
licensed material, or material used under an exception or
|
|
||||||
limitation to copyright. More considerations for licensors:
|
|
||||||
wiki.creativecommons.org/Considerations_for_licensors
|
|
||||||
|
|
||||||
Considerations for the public: By using one of our public
|
|
||||||
licenses, a licensor grants the public permission to use the
|
|
||||||
licensed material under specified terms and conditions. If
|
|
||||||
the licensor's permission is not necessary for any reason--for
|
|
||||||
example, because of any applicable exception or limitation to
|
|
||||||
copyright--then that use is not regulated by the license. Our
|
|
||||||
licenses grant only permissions under copyright and certain
|
|
||||||
other rights that a licensor has authority to grant. Use of
|
|
||||||
the licensed material may still be restricted for other
|
|
||||||
reasons, including because others have copyright or other
|
|
||||||
rights in the material. A licensor may make special requests,
|
|
||||||
such as asking that all changes be marked or described.
|
|
||||||
Although not required by our licenses, you are encouraged to
|
|
||||||
respect those requests where reasonable. More_considerations
|
|
||||||
for the public:
|
|
||||||
wiki.creativecommons.org/Considerations_for_licensees
|
|
||||||
|
|
||||||
=======================================================================
|
|
||||||
|
|
||||||
Creative Commons Attribution-ShareAlike 4.0 International Public
|
|
||||||
License
|
|
||||||
|
|
||||||
By exercising the Licensed Rights (defined below), You accept and agree
|
|
||||||
to be bound by the terms and conditions of this Creative Commons
|
|
||||||
Attribution-ShareAlike 4.0 International Public License ("Public
|
|
||||||
License"). To the extent this Public License may be interpreted as a
|
|
||||||
contract, You are granted the Licensed Rights in consideration of Your
|
|
||||||
acceptance of these terms and conditions, and the Licensor grants You
|
|
||||||
such rights in consideration of benefits the Licensor receives from
|
|
||||||
making the Licensed Material available under these terms and
|
|
||||||
conditions.
|
|
||||||
|
|
||||||
|
|
||||||
Section 1 -- Definitions.
|
|
||||||
|
|
||||||
a. Adapted Material means material subject to Copyright and Similar
|
|
||||||
Rights that is derived from or based upon the Licensed Material
|
|
||||||
and in which the Licensed Material is translated, altered,
|
|
||||||
arranged, transformed, or otherwise modified in a manner requiring
|
|
||||||
permission under the Copyright and Similar Rights held by the
|
|
||||||
Licensor. For purposes of this Public License, where the Licensed
|
|
||||||
Material is a musical work, performance, or sound recording,
|
|
||||||
Adapted Material is always produced where the Licensed Material is
|
|
||||||
synched in timed relation with a moving image.
|
|
||||||
|
|
||||||
b. Adapter's License means the license You apply to Your Copyright
|
|
||||||
and Similar Rights in Your contributions to Adapted Material in
|
|
||||||
accordance with the terms and conditions of this Public License.
|
|
||||||
|
|
||||||
c. BY-SA Compatible License means a license listed at
|
|
||||||
creativecommons.org/compatiblelicenses, approved by Creative
|
|
||||||
Commons as essentially the equivalent of this Public License.
|
|
||||||
|
|
||||||
d. Copyright and Similar Rights means copyright and/or similar rights
|
|
||||||
closely related to copyright including, without limitation,
|
|
||||||
performance, broadcast, sound recording, and Sui Generis Database
|
|
||||||
Rights, without regard to how the rights are labeled or
|
|
||||||
categorized. For purposes of this Public License, the rights
|
|
||||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
|
||||||
Rights.
|
|
||||||
|
|
||||||
e. Effective Technological Measures means those measures that, in the
|
|
||||||
absence of proper authority, may not be circumvented under laws
|
|
||||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
|
||||||
Treaty adopted on December 20, 1996, and/or similar international
|
|
||||||
agreements.
|
|
||||||
|
|
||||||
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
|
||||||
any other exception or limitation to Copyright and Similar Rights
|
|
||||||
that applies to Your use of the Licensed Material.
|
|
||||||
|
|
||||||
g. License Elements means the license attributes listed in the name
|
|
||||||
of a Creative Commons Public License. The License Elements of this
|
|
||||||
Public License are Attribution and ShareAlike.
|
|
||||||
|
|
||||||
h. Licensed Material means the artistic or literary work, database,
|
|
||||||
or other material to which the Licensor applied this Public
|
|
||||||
License.
|
|
||||||
|
|
||||||
i. Licensed Rights means the rights granted to You subject to the
|
|
||||||
terms and conditions of this Public License, which are limited to
|
|
||||||
all Copyright and Similar Rights that apply to Your use of the
|
|
||||||
Licensed Material and that the Licensor has authority to license.
|
|
||||||
|
|
||||||
j. Licensor means the individual(s) or entity(ies) granting rights
|
|
||||||
under this Public License.
|
|
||||||
|
|
||||||
k. Share means to provide material to the public by any means or
|
|
||||||
process that requires permission under the Licensed Rights, such
|
|
||||||
as reproduction, public display, public performance, distribution,
|
|
||||||
dissemination, communication, or importation, and to make material
|
|
||||||
available to the public including in ways that members of the
|
|
||||||
public may access the material from a place and at a time
|
|
||||||
individually chosen by them.
|
|
||||||
|
|
||||||
l. Sui Generis Database Rights means rights other than copyright
|
|
||||||
resulting from Directive 96/9/EC of the European Parliament and of
|
|
||||||
the Council of 11 March 1996 on the legal protection of databases,
|
|
||||||
as amended and/or succeeded, as well as other essentially
|
|
||||||
equivalent rights anywhere in the world.
|
|
||||||
|
|
||||||
m. You means the individual or entity exercising the Licensed Rights
|
|
||||||
under this Public License. Your has a corresponding meaning.
|
|
||||||
|
|
||||||
|
|
||||||
Section 2 -- Scope.
|
|
||||||
|
|
||||||
a. License grant.
|
|
||||||
|
|
||||||
1. Subject to the terms and conditions of this Public License,
|
|
||||||
the Licensor hereby grants You a worldwide, royalty-free,
|
|
||||||
non-sublicensable, non-exclusive, irrevocable license to
|
|
||||||
exercise the Licensed Rights in the Licensed Material to:
|
|
||||||
|
|
||||||
a. reproduce and Share the Licensed Material, in whole or
|
|
||||||
in part; and
|
|
||||||
|
|
||||||
b. produce, reproduce, and Share Adapted Material.
|
|
||||||
|
|
||||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
|
||||||
Exceptions and Limitations apply to Your use, this Public
|
|
||||||
License does not apply, and You do not need to comply with
|
|
||||||
its terms and conditions.
|
|
||||||
|
|
||||||
3. Term. The term of this Public License is specified in Section
|
|
||||||
6(a).
|
|
||||||
|
|
||||||
4. Media and formats; technical modifications allowed. The
|
|
||||||
Licensor authorizes You to exercise the Licensed Rights in
|
|
||||||
all media and formats whether now known or hereafter created,
|
|
||||||
and to make technical modifications necessary to do so. The
|
|
||||||
Licensor waives and/or agrees not to assert any right or
|
|
||||||
authority to forbid You from making technical modifications
|
|
||||||
necessary to exercise the Licensed Rights, including
|
|
||||||
technical modifications necessary to circumvent Effective
|
|
||||||
Technological Measures. For purposes of this Public License,
|
|
||||||
simply making modifications authorized by this Section 2(a)
|
|
||||||
(4) never produces Adapted Material.
|
|
||||||
|
|
||||||
5. Downstream recipients.
|
|
||||||
|
|
||||||
a. Offer from the Licensor -- Licensed Material. Every
|
|
||||||
recipient of the Licensed Material automatically
|
|
||||||
receives an offer from the Licensor to exercise the
|
|
||||||
Licensed Rights under the terms and conditions of this
|
|
||||||
Public License.
|
|
||||||
|
|
||||||
b. Additional offer from the Licensor -- Adapted Material.
|
|
||||||
Every recipient of Adapted Material from You
|
|
||||||
automatically receives an offer from the Licensor to
|
|
||||||
exercise the Licensed Rights in the Adapted Material
|
|
||||||
under the conditions of the Adapter's License You apply.
|
|
||||||
|
|
||||||
c. No downstream restrictions. You may not offer or impose
|
|
||||||
any additional or different terms or conditions on, or
|
|
||||||
apply any Effective Technological Measures to, the
|
|
||||||
Licensed Material if doing so restricts exercise of the
|
|
||||||
Licensed Rights by any recipient of the Licensed
|
|
||||||
Material.
|
|
||||||
|
|
||||||
6. No endorsement. Nothing in this Public License constitutes or
|
|
||||||
may be construed as permission to assert or imply that You
|
|
||||||
are, or that Your use of the Licensed Material is, connected
|
|
||||||
with, or sponsored, endorsed, or granted official status by,
|
|
||||||
the Licensor or others designated to receive attribution as
|
|
||||||
provided in Section 3(a)(1)(A)(i).
|
|
||||||
|
|
||||||
b. Other rights.
|
|
||||||
|
|
||||||
1. Moral rights, such as the right of integrity, are not
|
|
||||||
licensed under this Public License, nor are publicity,
|
|
||||||
privacy, and/or other similar personality rights; however, to
|
|
||||||
the extent possible, the Licensor waives and/or agrees not to
|
|
||||||
assert any such rights held by the Licensor to the limited
|
|
||||||
extent necessary to allow You to exercise the Licensed
|
|
||||||
Rights, but not otherwise.
|
|
||||||
|
|
||||||
2. Patent and trademark rights are not licensed under this
|
|
||||||
Public License.
|
|
||||||
|
|
||||||
3. To the extent possible, the Licensor waives any right to
|
|
||||||
collect royalties from You for the exercise of the Licensed
|
|
||||||
Rights, whether directly or through a collecting society
|
|
||||||
under any voluntary or waivable statutory or compulsory
|
|
||||||
licensing scheme. In all other cases the Licensor expressly
|
|
||||||
reserves any right to collect such royalties.
|
|
||||||
|
|
||||||
|
|
||||||
Section 3 -- License Conditions.
|
|
||||||
|
|
||||||
Your exercise of the Licensed Rights is expressly made subject to the
|
|
||||||
following conditions.
|
|
||||||
|
|
||||||
a. Attribution.
|
|
||||||
|
|
||||||
1. If You Share the Licensed Material (including in modified
|
|
||||||
form), You must:
|
|
||||||
|
|
||||||
a. retain the following if it is supplied by the Licensor
|
|
||||||
with the Licensed Material:
|
|
||||||
|
|
||||||
i. identification of the creator(s) of the Licensed
|
|
||||||
Material and any others designated to receive
|
|
||||||
attribution, in any reasonable manner requested by
|
|
||||||
the Licensor (including by pseudonym if
|
|
||||||
designated);
|
|
||||||
|
|
||||||
ii. a copyright notice;
|
|
||||||
|
|
||||||
iii. a notice that refers to this Public License;
|
|
||||||
|
|
||||||
iv. a notice that refers to the disclaimer of
|
|
||||||
warranties;
|
|
||||||
|
|
||||||
v. a URI or hyperlink to the Licensed Material to the
|
|
||||||
extent reasonably practicable;
|
|
||||||
|
|
||||||
b. indicate if You modified the Licensed Material and
|
|
||||||
retain an indication of any previous modifications; and
|
|
||||||
|
|
||||||
c. indicate the Licensed Material is licensed under this
|
|
||||||
Public License, and include the text of, or the URI or
|
|
||||||
hyperlink to, this Public License.
|
|
||||||
|
|
||||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
|
||||||
reasonable manner based on the medium, means, and context in
|
|
||||||
which You Share the Licensed Material. For example, it may be
|
|
||||||
reasonable to satisfy the conditions by providing a URI or
|
|
||||||
hyperlink to a resource that includes the required
|
|
||||||
information.
|
|
||||||
|
|
||||||
3. If requested by the Licensor, You must remove any of the
|
|
||||||
information required by Section 3(a)(1)(A) to the extent
|
|
||||||
reasonably practicable.
|
|
||||||
|
|
||||||
b. ShareAlike.
|
|
||||||
|
|
||||||
In addition to the conditions in Section 3(a), if You Share
|
|
||||||
Adapted Material You produce, the following conditions also apply.
|
|
||||||
|
|
||||||
1. The Adapter's License You apply must be a Creative Commons
|
|
||||||
license with the same License Elements, this version or
|
|
||||||
later, or a BY-SA Compatible License.
|
|
||||||
|
|
||||||
2. You must include the text of, or the URI or hyperlink to, the
|
|
||||||
Adapter's License You apply. You may satisfy this condition
|
|
||||||
in any reasonable manner based on the medium, means, and
|
|
||||||
context in which You Share Adapted Material.
|
|
||||||
|
|
||||||
3. You may not offer or impose any additional or different terms
|
|
||||||
or conditions on, or apply any Effective Technological
|
|
||||||
Measures to, Adapted Material that restrict exercise of the
|
|
||||||
rights granted under the Adapter's License You apply.
|
|
||||||
|
|
||||||
|
|
||||||
Section 4 -- Sui Generis Database Rights.
|
|
||||||
|
|
||||||
Where the Licensed Rights include Sui Generis Database Rights that
|
|
||||||
apply to Your use of the Licensed Material:
|
|
||||||
|
|
||||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
|
||||||
to extract, reuse, reproduce, and Share all or a substantial
|
|
||||||
portion of the contents of the database;
|
|
||||||
|
|
||||||
b. if You include all or a substantial portion of the database
|
|
||||||
contents in a database in which You have Sui Generis Database
|
|
||||||
Rights, then the database in which You have Sui Generis Database
|
|
||||||
Rights (but not its individual contents) is Adapted Material,
|
|
||||||
|
|
||||||
including for purposes of Section 3(b); and
|
|
||||||
c. You must comply with the conditions in Section 3(a) if You Share
|
|
||||||
all or a substantial portion of the contents of the database.
|
|
||||||
|
|
||||||
For the avoidance of doubt, this Section 4 supplements and does not
|
|
||||||
replace Your obligations under this Public License where the Licensed
|
|
||||||
Rights include other Copyright and Similar Rights.
|
|
||||||
|
|
||||||
|
|
||||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
|
||||||
|
|
||||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
|
||||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
|
||||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
|
||||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
|
||||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
|
||||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
|
||||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
|
||||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
|
||||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
|
||||||
|
|
||||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
|
||||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
|
||||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
|
||||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
|
||||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
|
||||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
|
||||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
|
||||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
|
||||||
|
|
||||||
c. The disclaimer of warranties and limitation of liability provided
|
|
||||||
above shall be interpreted in a manner that, to the extent
|
|
||||||
possible, most closely approximates an absolute disclaimer and
|
|
||||||
waiver of all liability.
|
|
||||||
|
|
||||||
|
|
||||||
Section 6 -- Term and Termination.
|
|
||||||
|
|
||||||
a. This Public License applies for the term of the Copyright and
|
|
||||||
Similar Rights licensed here. However, if You fail to comply with
|
|
||||||
this Public License, then Your rights under this Public License
|
|
||||||
terminate automatically.
|
|
||||||
|
|
||||||
b. Where Your right to use the Licensed Material has terminated under
|
|
||||||
Section 6(a), it reinstates:
|
|
||||||
|
|
||||||
1. automatically as of the date the violation is cured, provided
|
|
||||||
it is cured within 30 days of Your discovery of the
|
|
||||||
violation; or
|
|
||||||
|
|
||||||
2. upon express reinstatement by the Licensor.
|
|
||||||
|
|
||||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
|
||||||
right the Licensor may have to seek remedies for Your violations
|
|
||||||
of this Public License.
|
|
||||||
|
|
||||||
c. For the avoidance of doubt, the Licensor may also offer the
|
|
||||||
Licensed Material under separate terms or conditions or stop
|
|
||||||
distributing the Licensed Material at any time; however, doing so
|
|
||||||
will not terminate this Public License.
|
|
||||||
|
|
||||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
|
||||||
License.
|
|
||||||
|
|
||||||
|
|
||||||
Section 7 -- Other Terms and Conditions.
|
|
||||||
|
|
||||||
a. The Licensor shall not be bound by any additional or different
|
|
||||||
terms or conditions communicated by You unless expressly agreed.
|
|
||||||
|
|
||||||
b. Any arrangements, understandings, or agreements regarding the
|
|
||||||
Licensed Material not stated herein are separate from and
|
|
||||||
independent of the terms and conditions of this Public License.
|
|
||||||
|
|
||||||
|
|
||||||
Section 8 -- Interpretation.
|
|
||||||
|
|
||||||
a. For the avoidance of doubt, this Public License does not, and
|
|
||||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
|
||||||
conditions on any use of the Licensed Material that could lawfully
|
|
||||||
be made without permission under this Public License.
|
|
||||||
|
|
||||||
b. To the extent possible, if any provision of this Public License is
|
|
||||||
deemed unenforceable, it shall be automatically reformed to the
|
|
||||||
minimum extent necessary to make it enforceable. If the provision
|
|
||||||
cannot be reformed, it shall be severed from this Public License
|
|
||||||
without affecting the enforceability of the remaining terms and
|
|
||||||
conditions.
|
|
||||||
|
|
||||||
c. No term or condition of this Public License will be waived and no
|
|
||||||
failure to comply consented to unless expressly agreed to by the
|
|
||||||
Licensor.
|
|
||||||
|
|
||||||
d. Nothing in this Public License constitutes or may be interpreted
|
|
||||||
as a limitation upon, or waiver of, any privileges and immunities
|
|
||||||
that apply to the Licensor or You, including from the legal
|
|
||||||
processes of any jurisdiction or authority.
|
|
||||||
|
|
||||||
|
|
||||||
=======================================================================
|
|
||||||
|
|
||||||
Creative Commons is not a party to its public
|
|
||||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
|
||||||
its public licenses to material it publishes and in those instances
|
|
||||||
will be considered the “Licensor.” The text of the Creative Commons
|
|
||||||
public licenses is dedicated to the public domain under the CC0 Public
|
|
||||||
Domain Dedication. Except for the limited purpose of indicating that
|
|
||||||
material is shared under a Creative Commons public license or as
|
|
||||||
otherwise permitted by the Creative Commons policies published at
|
|
||||||
creativecommons.org/policies, Creative Commons does not authorize the
|
|
||||||
use of the trademark "Creative Commons" or any other trademark or logo
|
|
||||||
of Creative Commons without its prior written consent including,
|
|
||||||
without limitation, in connection with any unauthorized modifications
|
|
||||||
to any of its public licenses or any other arrangements,
|
|
||||||
understandings, or agreements concerning use of licensed material. For
|
|
||||||
the avoidance of doubt, this paragraph does not form part of the
|
|
||||||
public licenses.
|
|
||||||
|
|
||||||
Creative Commons may be contacted at creativecommons.org.
|
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
# XDG Base Directory Specification
|
||||||
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
XDG_DATA_HOME ?= $(HOME)/.local/share
|
||||||
|
XDG_BIN_HOME ?= $(HOME)/.local/bin
|
||||||
|
|
||||||
|
INSTALL_BIN := $(XDG_BIN_HOME)
|
||||||
|
INSTALL_MAN := $(XDG_DATA_HOME)/man/man1
|
||||||
|
INSTALL_DOC := $(XDG_DATA_HOME)/doc/scripts-bash
|
||||||
|
INSTALL_YTDLL := $(XDG_DATA_HOME)/ytdll
|
||||||
|
|
||||||
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
# Sources
|
||||||
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
SCRIPTS_SH := $(wildcard local/bin/*.sh)
|
||||||
|
SCRIPTS_OTHER := $(wildcard local/bin/*.php) \
|
||||||
|
$(filter-out $(wildcard local/bin/*.*),$(wildcard local/bin/*))
|
||||||
|
|
||||||
|
DOC_SRC := $(wildcard local/share/doc/scripts-bash/*.md)
|
||||||
|
MAN_PAGES := $(patsubst local/share/doc/scripts-bash/%.md,local/share/man/man1/%,$(DOC_SRC))
|
||||||
|
|
||||||
|
# ──────────────────────────────────────────────────────────────
|
||||||
|
.PHONY: all build install uninstall clean verify
|
||||||
|
|
||||||
|
## Cible par défaut : installe tout dans ~/.local/
|
||||||
|
all: install
|
||||||
|
|
||||||
|
## build : génère les pages man depuis les .md (développeur, nécessite Pandoc)
|
||||||
|
build: $(MAN_PAGES)
|
||||||
|
|
||||||
|
local/share/man/man1/%: local/share/doc/scripts-bash/%.md
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
pandoc -s $< -t man -o $@
|
||||||
|
@echo " MAN $@"
|
||||||
|
|
||||||
|
## verify : vérifie la signature GPG du dernier tag avant d'installer
|
||||||
|
verify:
|
||||||
|
@tag=$$(git describe --tags --abbrev=0 2>/dev/null) || { \
|
||||||
|
echo " GPG Avertissement : aucun tag signé trouvé — intégrité non vérifiée."; \
|
||||||
|
echo " Importez la clé publique du développeur et vérifiez avec : git tag -v <tag>"; \
|
||||||
|
exit 0; \
|
||||||
|
}; \
|
||||||
|
if git verify-tag "$$tag" 2>/dev/null; then \
|
||||||
|
echo " GPG $$tag : signature valide"; \
|
||||||
|
else \
|
||||||
|
echo " GPG Erreur : signature invalide pour le tag $$tag"; \
|
||||||
|
echo " Importez la clé publique du développeur avant d'installer."; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
## install : déploie tout dans ~/.local/ (aucune dépendance externe)
|
||||||
|
install: verify
|
||||||
|
@[ -d "local/bin" ] || { echo "Erreur : lancer depuis la racine du projet scripts-bash"; exit 1; }
|
||||||
|
@mkdir -p "$(INSTALL_BIN)" "$(INSTALL_MAN)" "$(INSTALL_DOC)" "$(INSTALL_YTDLL)/lib"
|
||||||
|
@for f in $(SCRIPTS_SH); do \
|
||||||
|
dest="$(INSTALL_BIN)/$$(basename "$${f%.sh}")"; \
|
||||||
|
install -m 755 "$$f" "$$dest"; \
|
||||||
|
echo " BIN $$dest"; \
|
||||||
|
done
|
||||||
|
@for f in $(SCRIPTS_OTHER); do \
|
||||||
|
dest="$(INSTALL_BIN)/$$(basename "$$f")"; \
|
||||||
|
install -m 755 "$$f" "$$dest"; \
|
||||||
|
echo " BIN $$dest"; \
|
||||||
|
done
|
||||||
|
@for f in $(wildcard local/share/man/man1/*); do \
|
||||||
|
install -m 644 "$$f" "$(INSTALL_MAN)/$$(basename "$$f")"; \
|
||||||
|
echo " MAN $(INSTALL_MAN)/$$(basename "$$f")"; \
|
||||||
|
done
|
||||||
|
@for f in $(wildcard local/share/doc/scripts-bash/*); do \
|
||||||
|
install -m 644 "$$f" "$(INSTALL_DOC)/$$(basename "$$f")"; \
|
||||||
|
echo " DOC $(INSTALL_DOC)/$$(basename "$$f")"; \
|
||||||
|
done
|
||||||
|
@for f in $(wildcard local/share/ytdll/*); do \
|
||||||
|
[ -f "$$f" ] || continue; \
|
||||||
|
install -m 644 "$$f" "$(INSTALL_YTDLL)/$$(basename "$$f")"; \
|
||||||
|
echo " DATA $(INSTALL_YTDLL)/$$(basename "$$f")"; \
|
||||||
|
done
|
||||||
|
@for f in $(wildcard local/share/ytdll/lib/*); do \
|
||||||
|
install -m 644 "$$f" "$(INSTALL_YTDLL)/lib/$$(basename "$$f")"; \
|
||||||
|
echo " DATA $(INSTALL_YTDLL)/lib/$$(basename "$$f")"; \
|
||||||
|
done
|
||||||
|
@path_line='export PATH="$$PATH:$$HOME/.local/bin"'; \
|
||||||
|
if ! grep -qF "$$path_line" ~/.bashrc 2>/dev/null; then \
|
||||||
|
echo "$$path_line" >> ~/.bashrc; \
|
||||||
|
echo " PATH ~/.bashrc ← ~/.local/bin (rechargez votre terminal)"; \
|
||||||
|
fi
|
||||||
|
@manpath_line='export MANPATH="$$(manpath):$$HOME/.local/share/man"'; \
|
||||||
|
if ! grep -qF "$$manpath_line" ~/.bashrc 2>/dev/null; then \
|
||||||
|
echo "$$manpath_line" >> ~/.bashrc; \
|
||||||
|
echo " MANPATH ~/.bashrc ← ~/.local/share/man (rechargez votre terminal)"; \
|
||||||
|
fi
|
||||||
|
@echo ""
|
||||||
|
@echo "Installation terminée."
|
||||||
|
|
||||||
|
## uninstall : supprime les fichiers installés par 'make install'
|
||||||
|
uninstall:
|
||||||
|
@[ -d "local/bin" ] || { echo "Erreur : lancer depuis la racine du projet scripts-bash"; exit 1; }
|
||||||
|
@for f in $(SCRIPTS_SH); do \
|
||||||
|
rm -fv "$(INSTALL_BIN)/$$(basename "$${f%.sh}")"; \
|
||||||
|
done
|
||||||
|
@for f in $(SCRIPTS_OTHER); do \
|
||||||
|
rm -fv "$(INSTALL_BIN)/$$(basename "$$f")"; \
|
||||||
|
done
|
||||||
|
@for f in $(wildcard local/share/man/man1/*); do \
|
||||||
|
rm -fv "$(INSTALL_MAN)/$$(basename "$$f")"; \
|
||||||
|
done
|
||||||
|
@for f in $(wildcard local/share/doc/scripts-bash/*); do \
|
||||||
|
rm -fv "$(INSTALL_DOC)/$$(basename "$$f")"; \
|
||||||
|
done
|
||||||
|
@rm -rfv "$(INSTALL_YTDLL)"
|
||||||
|
@echo "Désinstallation terminée."
|
||||||
|
|
||||||
|
## clean : supprime les pages man générées (dépôt local uniquement)
|
||||||
|
clean:
|
||||||
|
@rm -f $(MAN_PAGES)
|
||||||
|
@echo "Pages man supprimées."
|
||||||
@@ -1,41 +1,68 @@
|
|||||||
# scripts-bash
|
# scripts-bash
|
||||||
|
|
||||||
Quelques scripts Bash
|
Collection de scripts Bash pour Linux Mint / Debian.
|
||||||
|
|
||||||
Le script `install.sh` a été conçu pour automatiser le processus de copie de fichiers depuis un dépôt Git local vers un répertoire local.
|
## Installation
|
||||||
Le script modifie également le chemin d'accès (PATH) de l'utilisateur ainsi que le chemin d'accès de man (MANPATH) de l'utilisateur.
|
|
||||||
|
|
||||||
## Liste des scripts
|
```bash
|
||||||
|
git clone https://git.abonnel.fr/cedricAbonnel/scripts-bash.git
|
||||||
|
cd scripts-bash
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
![[liste des scripts.base]]
|
`make install` vérifie la signature GPG du dernier tag, copie les scripts dans `~/.local/bin`,
|
||||||
|
les pages man dans `~/.local/share/man/man1`, et ajoute `~/.local/bin` au `PATH` dans `~/.bashrc`
|
||||||
|
si nécessaire. Rechargez votre terminal après l'installation.
|
||||||
|
|
||||||
## Utilisation
|
Pour que la vérification GPG fonctionne, importez la clé publique du développeur au préalable :
|
||||||
|
|
||||||
Pour utiliser ces scripts, suivez ces étapes :
|
```bash
|
||||||
|
gpg --keyserver keys.openpgp.org --recv-keys 364BF1DAF2F589EF23A0660EB7B7D1D337AA8AA4
|
||||||
|
```
|
||||||
|
|
||||||
1. Clonez ce dépôt Git.
|
## Scripts
|
||||||
`git clone https://git.abonnel.fr/cedricAbonnel/scripts-bash.git`
|
|
||||||
|
|
||||||
2. Exécutez le script en utilisant la commande `./install.sh`.
|
### Documentés
|
||||||
Le script copiera les fichiers du programme, les pages d'aide et les paramètres dans votre dossier personnel. Il est possible qu'un compte `sudo `soit requis pour l'installation de binaires externes.
|
|
||||||
|
|
||||||
Toutes les opérations et les messages d'erreur sont enregistrés dans un fichier journal (`~/log/a5l-scripts_bash-<date et heure de l'instant>-<PID>.log`) situé dans le répertoire personnel de l'utilisateur. Le journal inclut la date, l'heure et les détails de chaque opération.
|
| Commande | Description | Documentation |
|
||||||
|
|---|---|---|
|
||||||
|
| `castopod_update` | Mise à jour de CASTOPOD | [castopod_update.1.md](local/share/doc/scripts-bash/castopod_update.1.md) |
|
||||||
|
| `convertPDF` | Compresse des fichiers PDF et génère un OCR | [convertPDF.1.md](local/share/doc/scripts-bash/convertPDF.1.md) |
|
||||||
|
| `playlist_gen` | Génère une playlist M3U à partir de fichiers audio | [playlist_gen.1.md](local/share/doc/scripts-bash/playlist_gen.1.md) |
|
||||||
|
| `play_tophaire` | Jingle et annonce de l'heure via espeak-ng | [play_tophoraire.1.md](local/share/doc/scripts-bash/play_tophoraire.1.md) |
|
||||||
|
| `random_music_player` | Lecteur de musique aléatoire en ligne de commande | [random_music_player.1.md](local/share/doc/scripts-bash/random_music_player.1.md) |
|
||||||
|
| `verif-desktop` | Audit des fichiers .desktop — chemins manquants, apps cachées, erreurs de syntaxe | [verif-desktop.1.md](local/share/doc/scripts-bash/verif-desktop.1.md) |
|
||||||
|
|
||||||
Le chemin complet des fichiers copiés est enregistré de manière unique dans le fichier `~/.config/a5l_scripts-bash_uninstall-list`.
|
### Autres scripts
|
||||||
|
|
||||||
|
`check_domain_cert`, `check_sha256`, `check_smart`, `convertMKV`, `generate_playlist_fp`,
|
||||||
|
`mkv_extract`, `png2jpg`, `podcast_convertImage`, `ssh-add-config`, `sshconnect`,
|
||||||
|
`trierPhotos`, `update_bullseye2buster`, `updateall`, `ytdll`
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
Le dossier `local/share/doc` contient la documentation de chaque script.
|
Une fois installé, chaque script documenté dispose d'une page man :
|
||||||
|
|
||||||
Le dossier `local/share/man/man1` contient la documentation de chaque script au format MAN.
|
```bash
|
||||||
|
man castopod_update
|
||||||
|
man verif-desktop
|
||||||
|
# etc.
|
||||||
|
```
|
||||||
|
|
||||||
|
Le dossier [`local/share/doc/`](local/share/doc/scripts-bash/) contient les sources de documentation au format Markdown.
|
||||||
|
|
||||||
## Désinstallation
|
## Désinstallation
|
||||||
|
|
||||||
Le script `uninstall.sh` permet de supprimer tous les fichiers précédemment copiés avec le script `install.sh`, en se basant sur le fichier utilisateur `~/.config/a5l_scripts-bash_uninstall-list`.
|
```bash
|
||||||
|
make uninstall
|
||||||
|
```
|
||||||
|
|
||||||
# Licence
|
## Pour les développeurs
|
||||||
Ce travail est sous licence [Creative Commons Attribution-ShareAlike 4.0 International License][cc-by-sa] par Cédrix.
|
|
||||||
|
|
||||||
|
Voir [DEVELOPER.md](DEVELOPER.md).
|
||||||
|
|
||||||
[cc-by-sa]: http://creativecommons.org/licenses/by-sa/4.0/
|
## Licence
|
||||||
[cc-by-sa-image]: https://licensebuttons.net/l/by-sa/4.0/88x31.png
|
|
||||||
|
Ce projet est distribué sous licence [EUPL v1.2][eupl] (Licence Publique de l'Union européenne) par Cédrix.
|
||||||
|
|
||||||
|
[eupl]: https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
|
||||||
|
|||||||
-255
@@ -1,255 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Script Bash - install.sh
|
|
||||||
# Auteur : Cédric Abonnel
|
|
||||||
|
|
||||||
# Description : Script d'installation des exécutables dans le répertoire '~/.local'"
|
|
||||||
|
|
||||||
# Version 07.07.24
|
|
||||||
# - Ajout du traitement de share/ytdll et share/ytdll/lib
|
|
||||||
|
|
||||||
# Version 23.12.1.3
|
|
||||||
# - Amélioration des logs
|
|
||||||
# - process_deployment_files optmisie les opérations de déployement
|
|
||||||
|
|
||||||
# Version 23.12.1.2
|
|
||||||
# - Fonctionnalité de purge des logs ajoutée.
|
|
||||||
|
|
||||||
# Version 23.12.1.1
|
|
||||||
# - Messages des logs améliorés avec plus de détail avec 'cp'.
|
|
||||||
|
|
||||||
|
|
||||||
# Spécifier le chemin du fichier journal
|
|
||||||
log_dir="$HOME/log"
|
|
||||||
log_file="${log_dir}/a5l-scripts_bash-$(date '+%Y%m%d-%H%M%S')-$$.log"
|
|
||||||
|
|
||||||
# Fonction pour afficher un message d'erreur et quitter le script en cas d'erreur
|
|
||||||
error() {
|
|
||||||
local error_message="$1"
|
|
||||||
log "ERREUR: $error_message"
|
|
||||||
echo "Erreur: $error_message"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Fonction pour enregistrer les messages de journal
|
|
||||||
log() {
|
|
||||||
if [ -n "$1" ]; then
|
|
||||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - $$ - $1" >> "$log_file"
|
|
||||||
echo "$1"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
create_dir() {
|
|
||||||
# S'assurer que le répertoire de destination existe, sinon, le créer
|
|
||||||
log "Tentative de création du dossier $1"
|
|
||||||
if [ ! -d "$1" ]; then
|
|
||||||
mkdir -p "$1" || error "Impossible de créer le répertoire $1"
|
|
||||||
log " _ Le répertoire $1 a été créé."
|
|
||||||
else
|
|
||||||
log " _ Le répertoire $1 existe déjà."
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
add_uninstall() {
|
|
||||||
## Create or update uninstall script
|
|
||||||
|
|
||||||
uninstall_list=$HOME/.config/a5l_scripts-bash_uninstall-list
|
|
||||||
test -f "${uninstall_list}" || touch "${uninstall_list}"
|
|
||||||
|
|
||||||
local fichier_a_supprimer="$1"
|
|
||||||
|
|
||||||
# Vérifier si le fichier de suppression existe déjà dans uninstall_script
|
|
||||||
if ! grep -q "$fichier_a_supprimer" "$uninstall_list"; then
|
|
||||||
# Ajouter le fichier à uninstall_list
|
|
||||||
echo "$fichier_a_supprimer" >> "$uninstall_list"
|
|
||||||
log "- Le fichier '$fichier_a_supprimer' ajouté à la liste de fichiers installés"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
## Fonction de Traitement ##
|
|
||||||
process_deployment_files() {
|
|
||||||
local destination="$1"
|
|
||||||
local source="$2"
|
|
||||||
local file_desc="$3"
|
|
||||||
|
|
||||||
log "### Déploiement des fichiers pour $destination"
|
|
||||||
|
|
||||||
# S'assurer que le répertoire de destination existe, sinon, le créer
|
|
||||||
create_dir "$destination"
|
|
||||||
|
|
||||||
# Copier sélectivement les fichiers du dépôt Git local vers $destination en préservant la structure
|
|
||||||
log "Vérification de l'existence de '$file_desc'"
|
|
||||||
|
|
||||||
# Vérifier si le fichier "$file_desc" existe
|
|
||||||
if [ -e "$file_desc" ]; then
|
|
||||||
# Récupérer des fichiers installés
|
|
||||||
fileslist_local=$(cat "$file_desc")
|
|
||||||
|
|
||||||
# Copie des fichiers listés dans $file_desc
|
|
||||||
log "Copie des fichiers listés dans $file_desc."
|
|
||||||
|
|
||||||
# Copier les fichiers en supprimant les extensions
|
|
||||||
for file in $fileslist_local; do
|
|
||||||
# debut Supprimer l'extension du nom de fichier si c'est un Bash Script
|
|
||||||
file_type=$(file -b "$source/$file")
|
|
||||||
if [[ "$file_type" == *"Bourne-Again shell script"* ]]; then
|
|
||||||
log "$file est un fichier Bash."
|
|
||||||
file_dest="${file%.*}"
|
|
||||||
log "Nom de fichier sans extension : $file_dest"
|
|
||||||
else
|
|
||||||
file_dest="${file}"
|
|
||||||
fi
|
|
||||||
# fin
|
|
||||||
cp -v "$source/$file" "$destination/$file_dest" 2>&1 | while read -r line; do
|
|
||||||
log "- $line"
|
|
||||||
done
|
|
||||||
add_uninstall "$destination/$file_dest"
|
|
||||||
done
|
|
||||||
else
|
|
||||||
error "Le fichier '$file_desc' n'existe pas. Votre dépôt Git local n'est pas complet ou quelque chose s'est mal passé."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Affiche un message de confirmation
|
|
||||||
log "Les fichiers du dépôt Git local ont été copiés vers $destination_dir avec succès."
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
purge_old_logs(){
|
|
||||||
find "$log_dir" -type f -name "a5l-scripts_bash-*.log" -mtime +10 -exec rm {} \;
|
|
||||||
find "$log_dir" -type f -name "a5l-scripts_bash_prep-*.log" -mtime +10 -exec rm {} \;
|
|
||||||
}
|
|
||||||
|
|
||||||
log "Debut du script"
|
|
||||||
|
|
||||||
## Post traitement : log
|
|
||||||
|
|
||||||
# S'assurer que le répertoire de destination existe, sinon, le créer
|
|
||||||
create_dir "${log_dir}"
|
|
||||||
|
|
||||||
# Purger les les logs
|
|
||||||
purge_old_logs
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### .local/share/ytdll ####
|
|
||||||
|
|
||||||
## Declarations ##
|
|
||||||
|
|
||||||
# Spécifier le chemin du répertoire destination
|
|
||||||
destination_dir="$HOME/.local/share/ytdll"
|
|
||||||
|
|
||||||
# Spécifier le chemin du répertoire du dépôt Git local
|
|
||||||
source_dir="local/share/ytdll"
|
|
||||||
|
|
||||||
file_local_desc=.config/files_local-share-ytdll
|
|
||||||
|
|
||||||
## Traitement ##
|
|
||||||
log "## Debut du traitement pour $destination_dir"
|
|
||||||
|
|
||||||
process_deployment_files "$destination_dir" "$source_dir" "$file_local_desc"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### .local/share/ytdll/lib ####
|
|
||||||
|
|
||||||
## Declarations ##
|
|
||||||
|
|
||||||
# Spécifier le chemin du répertoire destination
|
|
||||||
destination_dir="$HOME/.local/share/ytdll/lib"
|
|
||||||
|
|
||||||
# Spécifier le chemin du répertoire du dépôt Git local
|
|
||||||
source_dir="local/share/ytdll/lib"
|
|
||||||
|
|
||||||
file_local_desc=.config/files_local-share-ytdll-lib
|
|
||||||
|
|
||||||
## Traitement ##
|
|
||||||
log "## Debut du traitement pour $destination_dir"
|
|
||||||
|
|
||||||
process_deployment_files "$destination_dir" "$source_dir" "$file_local_desc"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### .local/share/doc ####
|
|
||||||
|
|
||||||
## Declarations ##
|
|
||||||
|
|
||||||
# Spécifier le chemin du répertoire destination
|
|
||||||
destination_dir="$HOME/.local/share/doc"
|
|
||||||
|
|
||||||
# Spécifier le chemin du répertoire du dépôt Git local
|
|
||||||
source_dir="local/share/doc"
|
|
||||||
|
|
||||||
file_local_desc=.config/files_local-share-doc
|
|
||||||
|
|
||||||
## Traitement ##
|
|
||||||
log "## Debut du traitement pour $destination_dir"
|
|
||||||
|
|
||||||
process_deployment_files "$destination_dir" "$source_dir" "$file_local_desc"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### .local/share/man ####
|
|
||||||
|
|
||||||
## Declarations ##
|
|
||||||
|
|
||||||
# Spécifier le chemin du répertoire
|
|
||||||
destination_dir="$HOME/.local/share/man"
|
|
||||||
|
|
||||||
# Spécifier le chemin du répertoire du dépôt Git local
|
|
||||||
source_dir="local/share/man"
|
|
||||||
|
|
||||||
file_local_desc=.config/files_local-share-man
|
|
||||||
|
|
||||||
## Traitement ##
|
|
||||||
log "## Debut du traitement pour $destination_dir"
|
|
||||||
|
|
||||||
log "### Debut du Traitement pour la gestion du PATH avec $destination_dir"
|
|
||||||
# Vérifier si le répertoire destination est déjà dans le PATH
|
|
||||||
if [[ ! ":$(manpath):" == *":$destination_dir:"* ]]; then
|
|
||||||
# Ajouter le répertoire destination au PATH dans le fichier de configuration de session de l'utilisateur
|
|
||||||
echo 'export MANPATH="$(manpath):'"$destination_dir"'"' >> ~/.bashrc
|
|
||||||
source ~/.bashrc
|
|
||||||
log " $destination_dir a été ajouté au MANPATH dans le fichier de configuration de session de l'utilisateur."
|
|
||||||
fi
|
|
||||||
|
|
||||||
process_deployment_files "$destination_dir" "$source_dir" "$file_local_desc"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### .local/bin ####
|
|
||||||
|
|
||||||
## Declarations ##
|
|
||||||
|
|
||||||
# Spécifier le chemin du répertoire
|
|
||||||
destination_dir="$HOME/.local/bin"
|
|
||||||
|
|
||||||
# Spécifier le chemin du répertoire du dépôt Git local
|
|
||||||
source_dir="local/bin"
|
|
||||||
|
|
||||||
file_local_desc=.config/files_local-bin
|
|
||||||
|
|
||||||
## Traitement ##
|
|
||||||
log "## Debut du traitement pour $destination_dir"
|
|
||||||
|
|
||||||
# S'assurer que le répertoire de destination existe, sinon, le créer
|
|
||||||
create_dir "$destination_dir"
|
|
||||||
|
|
||||||
log "### Debut du Traitement pour la gestion du PATH avec $destination_dir"
|
|
||||||
# Vérifier si le répertoire destination est déjà dans le PATH
|
|
||||||
if [[ ! ":$PATH:" == *":$destination_dir:"* ]]; then
|
|
||||||
# Ajouter le répertoire destination au PATH dans le fichier de configuration de session de l'utilisateur
|
|
||||||
echo 'export PATH="$PATH:'"$destination_dir"'"' >> ~/.bashrc
|
|
||||||
source ~/.bashrc
|
|
||||||
log " $destination_dir a été ajouté au PATH dans le fichier de configuration de session de l'utilisateur."
|
|
||||||
fi
|
|
||||||
|
|
||||||
## Traitement ##
|
|
||||||
process_deployment_files "$destination_dir" "$source_dir" "$file_local_desc"
|
|
||||||
|
|
||||||
log "## Fin du script. Bonne continuation."
|
|
||||||
|
|
||||||
@@ -21,7 +21,8 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
#clear
|
#clear
|
||||||
|
|
||||||
logFile=~/$(basename ${0}).log
|
logFile="${XDG_STATE_HOME:-$HOME/.local/state}/scripts-bash/$(basename "${0}").log"
|
||||||
|
mkdir -p "$(dirname "$logFile")"
|
||||||
|
|
||||||
echo -e "\n"
|
echo -e "\n"
|
||||||
echo -e "==> Préparation de l'environnement...\n"|tee $logFile
|
echo -e "==> Préparation de l'environnement...\n"|tee $logFile
|
||||||
@@ -57,7 +58,7 @@ source_dir=$(pwd)
|
|||||||
input_file_type=${param1}
|
input_file_type=${param1}
|
||||||
output_file_type="new${param2}.mkv"
|
output_file_type="new${param2}.mkv"
|
||||||
declare -a mesFichiers
|
declare -a mesFichiers
|
||||||
listFileName=~/rsbConvert_${date_en_cours}.sh
|
listFileName="${XDG_STATE_HOME:-$HOME/.local/state}/scripts-bash/rsbConvert_${date_en_cours}.sh"
|
||||||
|
|
||||||
|
|
||||||
echo -e "Dossier en cours : " |tee -a $logFile
|
echo -e "Dossier en cours : " |tee -a $logFile
|
||||||
@@ -246,7 +247,7 @@ echo -e "==> Traitement des vidéos en cours...\n"|tee -a $logFile
|
|||||||
echo "touch \"${out_file}.processed\"">> ${listFileName}
|
echo "touch \"${out_file}.processed\"">> ${listFileName}
|
||||||
|
|
||||||
echo -e "\n ==> On indique le fichier traité et le résultat dans un log"|tee -a $logFile
|
echo -e "\n ==> On indique le fichier traité et le résultat dans un log"|tee -a $logFile
|
||||||
cmd_exec="echo -e \"\\\"${in_file}\\\" > \\\"${out_file}\\\"\">> ~/rsbConvert.log"
|
cmd_exec="echo -e \"\\\"${in_file}\\\" > \\\"${out_file}\\\"\">> \"${XDG_STATE_HOME:-$HOME/.local/state}/scripts-bash/rsbConvert.log\""
|
||||||
echo ${cmd_exec}>> ${listFileName}
|
echo ${cmd_exec}>> ${listFileName}
|
||||||
|
|
||||||
echo -e "\n ==> Finished \"$out_file\""|tee -a $logFile
|
echo -e "\n ==> Finished \"$out_file\""|tee -a $logFile
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ function message {
|
|||||||
|
|
||||||
clear
|
clear
|
||||||
|
|
||||||
fichierLog=~/convertPDF.log
|
_log_dir="${XDG_STATE_HOME:-$HOME/.local/state}/scripts-bash"
|
||||||
|
mkdir -p "$_log_dir"
|
||||||
|
fichierLog="$_log_dir/convertPDF.log"
|
||||||
fichiersATraiter=fichiersATraiter.lst
|
fichiersATraiter=fichiersATraiter.lst
|
||||||
idLog=$$-${uuidgen}
|
idLog=$$-${uuidgen}
|
||||||
|
|
||||||
|
|||||||
@@ -51,16 +51,16 @@ done
|
|||||||
|
|
||||||
|
|
||||||
# Définition du dossier des paramètres
|
# Définition du dossier des paramètres
|
||||||
CONFIG_DIR=${HOME}/.config/cedrix/generate_playlist
|
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/generate-playlist"
|
||||||
if [ ! -d "$CONFIG_DIR" ]; then
|
if [ ! -d "$CONFIG_DIR" ]; then
|
||||||
mkdir -p ${CONFIG_DIR}
|
mkdir -p ${CONFIG_DIR}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Vérifier si le fichier user-dirs.dirs existe
|
# Vérifier si le fichier user-dirs.dirs existe
|
||||||
if [[ -f ~/.config/user-dirs.dirs ]]; then
|
if [[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" ]]; then
|
||||||
# Charger les variables depuis le fichier user-dirs.dirs
|
# Charger les variables depuis le fichier user-dirs.dirs
|
||||||
source ~/.config/user-dirs.dirs
|
source "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs"
|
||||||
|
|
||||||
# Vérifier si la variable XDG_MUSIC_DIR est définie
|
# Vérifier si la variable XDG_MUSIC_DIR est définie
|
||||||
if [[ -v XDG_MUSIC_DIR ]]; then
|
if [[ -v XDG_MUSIC_DIR ]]; then
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
## Read config file or create/update
|
## Read config file or create/update
|
||||||
config_filename=~/.config/$(basename "${0}")
|
config_filename="${XDG_CONFIG_HOME:-$HOME/.config}/$(basename "${0}")"
|
||||||
test -f "${config_filename}" && . "${config_filename}" || echo "# Fichier de configuration créé $(date +%c)" | tee "${config_filename}"
|
test -f "${config_filename}" && . "${config_filename}" || echo "# Fichier de configuration créé $(date +%c)" | tee "${config_filename}"
|
||||||
|
|
||||||
### edit directory path music background
|
### edit directory path music background
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
trap 'exit 130' INT
|
trap 'exit 130' INT
|
||||||
|
|
||||||
## Read config file or create/update
|
## Read config file or create/update
|
||||||
config_filename=~/.config/$(basename ${0})
|
config_filename="${XDG_CONFIG_HOME:-$HOME/.config}/$(basename "${0}")"
|
||||||
test -f ${config_filename} && . ${config_filename} || echo "# Fichier de configuration créé $(date +%c)" | tee ${config_filename}
|
test -f ${config_filename} && . ${config_filename} || echo "# Fichier de configuration créé $(date +%c)" | tee ${config_filename}
|
||||||
|
|
||||||
### edit directory path music background
|
### edit directory path music background
|
||||||
|
|||||||
+39
-29
@@ -1,50 +1,60 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# 1. Liste des hosts
|
mapfile -t ALL_HOSTS < <(
|
||||||
mapfile -t ALL_HOSTS < <(grep -riI "^Host " ~/.ssh/config ~/.ssh/config.d/ ~/.ssh/include/ 2>/dev/null | awk '{print $2}' | grep -v '*' | sort -u)
|
grep -hriI "^Host " ~/.ssh/config ~/.ssh/config.d/ ~/.ssh/include/ 2>/dev/null \
|
||||||
|
| awk '{print $2}' \
|
||||||
|
| grep -v '\*' \
|
||||||
|
| sort -u
|
||||||
|
)
|
||||||
|
|
||||||
|
TOTAL=${#ALL_HOSTS[@]}
|
||||||
|
|
||||||
check_host() {
|
check_host() {
|
||||||
local host=$1
|
local host=$1
|
||||||
local info=$(ssh -G "$host")
|
local info addr port user
|
||||||
local addr=$(echo "$info" | awk '/^hostname / {print $2}')
|
info=$(ssh -G "$host" 2>/dev/null)
|
||||||
local port=$(echo "$info" | awk '/^port / {print $2}')
|
addr=$(awk '/^hostname / {print $2}' <<< "$info")
|
||||||
|
port=$(awk '/^port / {print $2}' <<< "$info")
|
||||||
|
user=$(awk '/^user / {print $2}' <<< "$info")
|
||||||
|
|
||||||
# Test de port TCP
|
|
||||||
if (timeout 0.7s bash -c "cat < /dev/null > /dev/tcp/$addr/$port") 2>/dev/null; then
|
if (timeout 0.7s bash -c "cat < /dev/null > /dev/tcp/$addr/$port") 2>/dev/null; then
|
||||||
# On utilise "|" comme délimiteur interne
|
printf "\033[32m[ ON ]\033[0m|ON|%-22s|%s@%s\n" "$host" "$user" "$addr"
|
||||||
printf "[ ON ]|%s\n" "$host"
|
|
||||||
else
|
else
|
||||||
printf "[ OFF ]|%s\n" "$host"
|
printf "\033[31m[ OFF ]\033[0m|OFF|%-22s|%s@%s\n" "$host" "$user" "$addr"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
export -f check_host
|
export -f check_host
|
||||||
echo "Vérification des serveurs..."
|
|
||||||
|
|
||||||
# 2. Scan parallèle
|
printf "Vérification de %d serveurs...\n" "$TOTAL"
|
||||||
STATE_LIST=$(printf "%s\n" "${ALL_HOSTS[@]}" | xargs -I {} -P 10 bash -c 'check_host "{}"')
|
|
||||||
|
|
||||||
# 3. Interface FZF
|
# Scan parallèle — ON affiché en premier, puis tri alphabétique
|
||||||
# On demande à fzf d'afficher les colonnes proprement
|
STATE_LIST=$(
|
||||||
choice=$(echo "$STATE_LIST" | fzf --height 40% --reverse \
|
printf "%s\n" "${ALL_HOSTS[@]}" \
|
||||||
--delimiter="\|" \
|
| xargs -I {} -P 20 bash -c 'check_host "{}"' \
|
||||||
--with-nth=1,2 \
|
| sort -t'|' -k2,2r -k3,3
|
||||||
--header "Tapez 'OFF' pour les serveurs HS | 'ON' pour les actifs")
|
)
|
||||||
|
|
||||||
|
choice=$(echo "$STATE_LIST" | fzf \
|
||||||
|
--ansi \
|
||||||
|
--height 70% \
|
||||||
|
--reverse \
|
||||||
|
--delimiter="|" \
|
||||||
|
--with-nth=1,3,4 \
|
||||||
|
--header "Entrée: connexion | ESC: annuler | Filtre: ON / OFF / nom" \
|
||||||
|
--preview 'host=$(echo {} | cut -d"|" -f3 | tr -d " "); ssh -G "$host" 2>/dev/null | grep -E "^(hostname|user|port|identityfile|compression) " | column -t' \
|
||||||
|
--preview-window=right:45%:wrap)
|
||||||
|
|
||||||
# 4. Connexion propre
|
|
||||||
if [ -n "$choice" ]; then
|
if [ -n "$choice" ]; then
|
||||||
# On extrait le nom de l'hôte en utilisant le délimiteur "|"
|
status=$(echo "$choice" | cut -d'|' -f2)
|
||||||
host_to_connect=$(echo "$choice" | cut -d'|' -f2)
|
host_to_connect=$(echo "$choice" | cut -d'|' -f3 | tr -d '[:space:]')
|
||||||
|
|
||||||
# Nettoyage radical des caractères invisibles ou espaces restants
|
if [[ "$status" == "ON" ]]; then
|
||||||
host_to_connect=$(echo "$host_to_connect" | tr -d '[:space:]')
|
|
||||||
|
|
||||||
if [[ "$choice" == *"[ ON ]"* ]]; then
|
|
||||||
clear
|
clear
|
||||||
ssh "$host_to_connect"
|
exec ssh "$host_to_connect"
|
||||||
else
|
else
|
||||||
echo -e "\033[0;31m⚠️ Le serveur $host_to_connect semble OFFLINE.\033[0m"
|
printf "\033[0;31m⚠ Le serveur '%s' semble OFFLINE.\033[0m\n" "$host_to_connect"
|
||||||
read -p "Tenter quand même la connexion ? (y/n) " confirm
|
read -rp "Tenter quand même la connexion ? (y/n) : " confirm
|
||||||
[[ $confirm == [yY] ]] && ssh "$host_to_connect"
|
[[ $confirm == [yY] ]] && exec ssh "$host_to_connect"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/php
|
#!/usr/bin/php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
$log_directory = getenv('HOME') . '/logs';
|
$log_directory = (getenv('XDG_STATE_HOME') ?: getenv('HOME') . '/.local/state') . '/scripts-bash';
|
||||||
|
|
||||||
// Vérification et création du répertoire de journalisation
|
// Vérification et création du répertoire de journalisation
|
||||||
if (!is_dir($log_directory)) {
|
if (!is_dir($log_directory)) {
|
||||||
|
|||||||
+12
-7
@@ -12,6 +12,12 @@ NC='\033[0m' # No Color
|
|||||||
|
|
||||||
# Mise à jour des machines présentes dans .ssh/config avec choix d'ignorer certaines.
|
# Mise à jour des machines présentes dans .ssh/config avec choix d'ignorer certaines.
|
||||||
|
|
||||||
|
# Chemins XDG
|
||||||
|
UPDATEALL_HOSTS="${XDG_CONFIG_HOME:-$HOME/.config}/updateall/hosts"
|
||||||
|
UPDATEALL_CUSTOM_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/updateall.d"
|
||||||
|
UPDATEALL_STATS="${XDG_STATE_HOME:-$HOME/.local/state}/updateall/stats"
|
||||||
|
mkdir -p "$(dirname "$UPDATEALL_HOSTS")" "$(dirname "$UPDATEALL_STATS")"
|
||||||
|
|
||||||
# fonction run_ssh et run_scp avec timeout + options
|
# fonction run_ssh et run_scp avec timeout + options
|
||||||
SSH_OPTS="-o ConnectTimeout=5 -o BatchMode=yes -o StrictHostKeyChecking=accept-new"
|
SSH_OPTS="-o ConnectTimeout=5 -o BatchMode=yes -o StrictHostKeyChecking=accept-new"
|
||||||
SSH_TIMEOUT="5"
|
SSH_TIMEOUT="5"
|
||||||
@@ -141,8 +147,7 @@ EOF
|
|||||||
now=$(date '+%Y-%m-%d %H:%M:%S')
|
now=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
# Fichier de stats
|
# Fichier de stats
|
||||||
stats_file="$HOME/.config/updateall-stats"
|
stats_file="$UPDATEALL_STATS"
|
||||||
mkdir -p "$(dirname "$stats_file")"
|
|
||||||
|
|
||||||
# Ajouter l’en-tête si le fichier est vide
|
# Ajouter l’en-tête si le fichier est vide
|
||||||
if [ ! -s "$stats_file" ]; then
|
if [ ! -s "$stats_file" ]; then
|
||||||
@@ -259,9 +264,9 @@ confirm_update() {
|
|||||||
local machine="$1"
|
local machine="$1"
|
||||||
read -p " - Executer la mise à jour pour $machine ? (o/n) " choice
|
read -p " - Executer la mise à jour pour $machine ? (o/n) " choice
|
||||||
if [ "$choice" = "o" ]; then
|
if [ "$choice" = "o" ]; then
|
||||||
echo "$machine 1" >> ~/.config/updateall-hosts
|
echo "$machine 1" >> "$UPDATEALL_HOSTS"
|
||||||
else
|
else
|
||||||
echo "$machine 0" >> ~/.config/updateall-hosts
|
echo "$machine 0" >> "$UPDATEALL_HOSTS"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -285,7 +290,7 @@ check_host() {
|
|||||||
|
|
||||||
run_custom_script() {
|
run_custom_script() {
|
||||||
local machine="$1"
|
local machine="$1"
|
||||||
local custom_script="$HOME/.config/updateall.d/$machine"
|
local custom_script="$UPDATEALL_CUSTOM_DIR/$machine"
|
||||||
|
|
||||||
if [ -f "$custom_script" ]; then
|
if [ -f "$custom_script" ]; then
|
||||||
echo -e " - Exécution du script spécifique pour ${GREEN}$machine${NC}"
|
echo -e " - Exécution du script spécifique pour ${GREEN}$machine${NC}"
|
||||||
@@ -328,7 +333,7 @@ current=0
|
|||||||
|
|
||||||
for machine in "${machines[@]}"; do
|
for machine in "${machines[@]}"; do
|
||||||
|
|
||||||
# Vérification si le nom de machine est présent dans le fichier .config/updateall-hosts
|
# Vérification si le nom de machine est présent dans $UPDATEALL_HOSTS
|
||||||
|
|
||||||
echo -e "\n"
|
echo -e "\n"
|
||||||
((current++))
|
((current++))
|
||||||
@@ -364,7 +369,7 @@ for machine in "${machines[@]}"; do
|
|||||||
matched=1
|
matched=1
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done < ~/.config/updateall-hosts
|
done < "$UPDATEALL_HOSTS"
|
||||||
|
|
||||||
if [ "$matched" != "1" ]; then
|
if [ "$matched" != "1" ]; then
|
||||||
check_host "$machine"
|
check_host "$machine"
|
||||||
|
|||||||
Executable
+130
@@ -0,0 +1,130 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Audit des fichiers .desktop : chemins manquants, apps cachées, erreurs de syntaxe
|
||||||
|
|
||||||
|
DIRS=(
|
||||||
|
"$HOME/.local/share/applications"
|
||||||
|
"/usr/share/applications"
|
||||||
|
)
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
YEL='\033[0;33m'
|
||||||
|
GRN='\033[0;32m'
|
||||||
|
BLU='\033[0;34m'
|
||||||
|
RST='\033[0m'
|
||||||
|
|
||||||
|
ok=0
|
||||||
|
warn=0
|
||||||
|
err=0
|
||||||
|
|
||||||
|
check_file() {
|
||||||
|
local f="$1"
|
||||||
|
local name
|
||||||
|
name=$(basename "$f")
|
||||||
|
local issues=()
|
||||||
|
local hints=()
|
||||||
|
|
||||||
|
# Ignorer les fichiers qui ne sont pas des Application affichables
|
||||||
|
local type
|
||||||
|
type=$(grep -m1 "^Type=" "$f" 2>/dev/null | cut -d= -f2-)
|
||||||
|
[[ "$type" != "Application" ]] && return
|
||||||
|
|
||||||
|
# Détecter si c'est un gestionnaire d'URL ou un fichier système (NoDisplay=true y est normal)
|
||||||
|
local is_url_handler=false
|
||||||
|
grep -q "^MimeType=.*x-scheme-handler" "$f" 2>/dev/null && is_url_handler=true
|
||||||
|
|
||||||
|
local is_user_dir=false
|
||||||
|
[[ "$f" == "$HOME/.local/share/applications/"* ]] && is_user_dir=true
|
||||||
|
|
||||||
|
# NoDisplay ou Hidden : signaler uniquement dans le dossier utilisateur et si pas gestionnaire d'URL
|
||||||
|
local nodisplay hidden
|
||||||
|
nodisplay=$(grep -m1 "^NoDisplay=" "$f" | cut -d= -f2-)
|
||||||
|
hidden=$(grep -m1 "^Hidden=" "$f" | cut -d= -f2-)
|
||||||
|
if [[ "$is_user_dir" == true && "$is_url_handler" == false ]]; then
|
||||||
|
[[ "$nodisplay" == "true" ]] && issues+=("caché (NoDisplay=true) — n'apparaît pas dans le menu")
|
||||||
|
[[ "$hidden" == "true" ]] && issues+=("caché (Hidden=true) — n'apparaît pas dans le menu")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Exec : extraire le premier token (sans %F %u etc.)
|
||||||
|
local exec_line exec_bin
|
||||||
|
exec_line=$(grep -m1 "^Exec=" "$f" | cut -d= -f2-)
|
||||||
|
# Retirer les guillemets englobants éventuels et les arguments %x
|
||||||
|
exec_bin=$(echo "$exec_line" | awk '{print $1}' | tr -d '"' | sed 's/%[a-zA-Z]$//')
|
||||||
|
|
||||||
|
if [[ -z "$exec_bin" ]]; then
|
||||||
|
issues+=("Exec manquant")
|
||||||
|
elif [[ "$exec_bin" == /* ]]; then
|
||||||
|
# Chemin absolu
|
||||||
|
if [[ ! -f "$exec_bin" ]]; then
|
||||||
|
issues+=("exécutable introuvable : $exec_bin")
|
||||||
|
elif [[ ! -x "$exec_bin" ]]; then
|
||||||
|
issues+=("exécutable non exécutable : $exec_bin")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Commande dans le PATH (ignorer les wrappers shell)
|
||||||
|
if [[ "$exec_bin" != "sh" && "$exec_bin" != "bash" && "$exec_bin" != "env" ]]; then
|
||||||
|
if ! command -v "$exec_bin" &>/dev/null; then
|
||||||
|
issues+=("commande introuvable dans PATH : $exec_bin")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Icône (chemin absolu uniquement — les noms de thème sont difficiles à vérifier)
|
||||||
|
local icon
|
||||||
|
icon=$(grep -m1 "^Icon=" "$f" | cut -d= -f2-)
|
||||||
|
if [[ "$icon" == /* && ! -f "$icon" ]]; then
|
||||||
|
hints+=("icône introuvable : $icon")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validation syntaxique (desktop-file-validate)
|
||||||
|
if command -v desktop-file-validate &>/dev/null; then
|
||||||
|
local syntax_out
|
||||||
|
syntax_out=$(desktop-file-validate "$f" 2>&1 | grep -v "^$")
|
||||||
|
while IFS= read -r line; do
|
||||||
|
[[ -z "$line" ]] && continue
|
||||||
|
if echo "$line" | grep -q "error:"; then
|
||||||
|
issues+=("syntaxe : ${line#*error: }")
|
||||||
|
elif echo "$line" | grep -q "warning:"; then
|
||||||
|
hints+=("syntaxe : ${line#*warning: }")
|
||||||
|
fi
|
||||||
|
done <<< "$syntax_out"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Affichage
|
||||||
|
local max_hints=3
|
||||||
|
if [[ ${#issues[@]} -gt 0 ]]; then
|
||||||
|
echo -e "${RED}✗ $name${RST}"
|
||||||
|
for i in "${issues[@]}"; do
|
||||||
|
echo -e " ${RED}→ $i${RST}"
|
||||||
|
done
|
||||||
|
local shown=0
|
||||||
|
for h in "${hints[@]}"; do
|
||||||
|
(( shown >= max_hints )) && { echo -e " ${YEL}~ … (${#hints[@]} avertissements au total)${RST}"; break; }
|
||||||
|
echo -e " ${YEL}~ $h${RST}"
|
||||||
|
(( shown++ ))
|
||||||
|
done
|
||||||
|
(( err++ ))
|
||||||
|
elif [[ ${#hints[@]} -gt 0 ]]; then
|
||||||
|
echo -e "${YEL}~ $name${RST}"
|
||||||
|
local shown=0
|
||||||
|
for h in "${hints[@]}"; do
|
||||||
|
(( shown >= max_hints )) && { echo -e " ${YEL}~ … (${#hints[@]} avertissements au total)${RST}"; break; }
|
||||||
|
echo -e " ${YEL}~ $h${RST}"
|
||||||
|
(( shown++ ))
|
||||||
|
done
|
||||||
|
(( warn++ ))
|
||||||
|
else
|
||||||
|
echo -e "${GRN}✓ $name${RST}"
|
||||||
|
(( ok++ ))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
for dir in "${DIRS[@]}"; do
|
||||||
|
[[ -d "$dir" ]] || continue
|
||||||
|
echo -e "\n${BLU}=== $dir ===${RST}"
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
check_file "$f"
|
||||||
|
done < <(find "$dir" -maxdepth 1 -name "*.desktop" -print0 | sort -z)
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "Résultat : ${GRN}$ok OK${RST} ${YEL}$warn avertissements${RST} ${RED}$err erreurs${RST}"
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- scripts
|
||||||
|
nom: verif-desktop
|
||||||
|
description: Audit des fichiers .desktop — chemins manquants, apps cachées, erreurs de syntaxe
|
||||||
|
---
|
||||||
|
|
||||||
|
# NOM
|
||||||
|
|
||||||
|
verif-desktop - Audit des fichiers .desktop de Linux Mint
|
||||||
|
|
||||||
|
# SYNOPSIS
|
||||||
|
|
||||||
|
verif-desktop
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
|
Vérifie l'ensemble des fichiers `.desktop` présents dans `~/.local/share/applications/` et `/usr/share/applications/`.
|
||||||
|
|
||||||
|
Pour chaque fichier, le script contrôle :
|
||||||
|
|
||||||
|
- **Exécutable manquant** : le chemin absolu dans `Exec=` n'existe pas sur le disque
|
||||||
|
- **Exécutable non exécutable** : le fichier existe mais n'a pas le bit `+x`
|
||||||
|
- **Commande introuvable** : la commande dans `Exec=` n'est pas dans le `$PATH`
|
||||||
|
- **App cachée** : `NoDisplay=true` ou `Hidden=true` dans le dossier utilisateur (l'app n'apparaît pas dans le menu)
|
||||||
|
- **Icône manquante** : `Icon=` pointe vers un chemin absolu inexistant
|
||||||
|
- **Erreurs de syntaxe** : signalées par `desktop-file-validate` (catégories invalides, clés dépréciées…)
|
||||||
|
|
||||||
|
Les gestionnaires d'URL (`MimeType=x-scheme-handler/...`) et les fichiers système sont traités différemment : `NoDisplay=true` y est attendu et n'est pas signalé comme erreur.
|
||||||
|
|
||||||
|
# COMPATIBILITÉ
|
||||||
|
|
||||||
|
Linux Mint (Cinnamon). Nécessite `desktop-file-utils` pour la validation syntaxique :
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo apt install desktop-file-utils
|
||||||
|
```
|
||||||
|
|
||||||
|
# EXEMPLES
|
||||||
|
|
||||||
|
Lancer l'audit complet :
|
||||||
|
```
|
||||||
|
verif-desktop
|
||||||
|
```
|
||||||
|
|
||||||
|
# CODES DE RETOUR
|
||||||
|
|
||||||
|
- `✓` vert — fichier valide
|
||||||
|
- `~` jaune — avertissement non bloquant
|
||||||
|
- `✗` rouge — erreur : l'application ne fonctionnera pas ou n'apparaîtra pas dans le menu
|
||||||
|
|
||||||
|
# VERSIONS
|
||||||
|
|
||||||
|
-26.05.1
|
||||||
|
: Version originale
|
||||||
|
|
||||||
|
# AUTEURS
|
||||||
|
|
||||||
|
Cédric Abonnel - \<canl.sb2023@acemail.fr>
|
||||||
|
|
||||||
|
# RAPPORT D'ERREURS
|
||||||
|
|
||||||
|
Pour signaler des erreurs ou des problèmes :
|
||||||
|
https://git.abonnel.fr/cedricAbonnel/scripts-bash
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
.\" Automatically generated by Pandoc 3.1.3
|
||||||
|
.\"
|
||||||
|
.\" Define V font for inline verbatim, using C font in formats
|
||||||
|
.\" that render this, and otherwise B font.
|
||||||
|
.ie "\f[CB]x\f[]"x" \{\
|
||||||
|
. ftr V B
|
||||||
|
. ftr VI BI
|
||||||
|
. ftr VB B
|
||||||
|
. ftr VBI BI
|
||||||
|
.\}
|
||||||
|
.el \{\
|
||||||
|
. ftr V CR
|
||||||
|
. ftr VI CI
|
||||||
|
. ftr VB CB
|
||||||
|
. ftr VBI CBI
|
||||||
|
.\}
|
||||||
|
.TH "" "" "" "" ""
|
||||||
|
.hy
|
||||||
|
.SH NOM
|
||||||
|
.PP
|
||||||
|
verif-desktop - Audit des fichiers .desktop de Linux Mint
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.PP
|
||||||
|
verif-desktop
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.PP
|
||||||
|
Vérifie l\[cq]ensemble des fichiers \f[V].desktop\f[R] présents dans
|
||||||
|
\f[V]\[ti]/.local/share/applications/\f[R] et
|
||||||
|
\f[V]/usr/share/applications/\f[R].
|
||||||
|
.PP
|
||||||
|
Pour chaque fichier, le script contrôle :
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]Exécutable manquant\f[R] : le chemin absolu dans \f[V]Exec=\f[R]
|
||||||
|
n\[cq]existe pas sur le disque
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]Exécutable non exécutable\f[R] : le fichier existe mais n\[cq]a pas
|
||||||
|
le bit \f[V]+x\f[R]
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]Commande introuvable\f[R] : la commande dans \f[V]Exec=\f[R]
|
||||||
|
n\[cq]est pas dans le \f[V]$PATH\f[R]
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]App cachée\f[R] : \f[V]NoDisplay=true\f[R] ou \f[V]Hidden=true\f[R]
|
||||||
|
dans le dossier utilisateur (l\[cq]app n\[cq]apparaît pas dans le menu)
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]Icône manquante\f[R] : \f[V]Icon=\f[R] pointe vers un chemin absolu
|
||||||
|
inexistant
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]Erreurs de syntaxe\f[R] : signalées par
|
||||||
|
\f[V]desktop-file-validate\f[R] (catégories invalides, clés
|
||||||
|
dépréciées\&...)
|
||||||
|
.PP
|
||||||
|
Les gestionnaires d\[cq]URL (\f[V]MimeType=x-scheme-handler/...\f[R]) et
|
||||||
|
les fichiers système sont traités différemment :
|
||||||
|
\f[V]NoDisplay=true\f[R] y est attendu et n\[cq]est pas signalé comme
|
||||||
|
erreur.
|
||||||
|
.SH COMPATIBILITÉ
|
||||||
|
.PP
|
||||||
|
Linux Mint (Cinnamon).
|
||||||
|
Nécessite \f[V]desktop-file-utils\f[R] pour la validation syntaxique :
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
sudo apt install desktop-file-utils
|
||||||
|
\f[R]
|
||||||
|
.fi
|
||||||
|
.SH EXEMPLES
|
||||||
|
.PP
|
||||||
|
Lancer l\[cq]audit complet : \f[V]verif-desktop\f[R]
|
||||||
|
.SH CODES DE RETOUR
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[V]✓\f[R] vert \[em] fichier valide
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[V]\[ti]\f[R] jaune \[em] avertissement non bloquant
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[V]✗\f[R] rouge \[em] erreur : l\[cq]application ne fonctionnera pas
|
||||||
|
ou n\[cq]apparaîtra pas dans le menu
|
||||||
|
.SH VERSIONS
|
||||||
|
.TP
|
||||||
|
-26.05.1
|
||||||
|
Version originale
|
||||||
|
.SH AUTEURS
|
||||||
|
.PP
|
||||||
|
Cédric Abonnel - <canl.sb2023\[at]acemail.fr>
|
||||||
|
.SH RAPPORT D\[cq]ERREURS
|
||||||
|
.PP
|
||||||
|
Pour signaler des erreurs ou des problèmes :
|
||||||
|
https://git.abonnel.fr/cedricAbonnel/scripts-bash
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Script Bash - prep.sh
|
|
||||||
# Auteur : Cédric Abonnel
|
|
||||||
|
|
||||||
# Description : Prépare les fichiers de DOC et listing.
|
|
||||||
|
|
||||||
# Version 07.07.24
|
|
||||||
# - Ajout du traitement de ytdll
|
|
||||||
|
|
||||||
# Version 23.12.14
|
|
||||||
# - Modification du traitement des résumés des DOC. La fonctionnalité n'est pas encore accessible.
|
|
||||||
|
|
||||||
|
|
||||||
# Spécifier le chemin du fichier journal
|
|
||||||
log_dir="$HOME/log"
|
|
||||||
log_file="${log_dir}/a5l-scripts_bash_prep-$(date '+%Y%m%d-%H%M%S')-$$.log"
|
|
||||||
|
|
||||||
# Fonction pour afficher un message d'erreur et quitter le script en cas d'erreur
|
|
||||||
error() {
|
|
||||||
local error_message="$1"
|
|
||||||
log "ERREUR: $error_message"
|
|
||||||
echo "Erreur: $error_message"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Fonction pour enregistrer les messages de journal
|
|
||||||
log() {
|
|
||||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - $$ - $1" >> "$log_file"
|
|
||||||
echo "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
create_dir() {
|
|
||||||
# S'assurer que le répertoire de destination existe, sinon, le créer
|
|
||||||
log "Tentative de création du dossier $1"
|
|
||||||
if [ ! -d "$1" ]; then
|
|
||||||
mkdir -p "$1" || error "Impossible de créer le répertoire $1"
|
|
||||||
log " _ Le répertoire $1 a été créé."
|
|
||||||
else
|
|
||||||
log " _ Le répertoire $1 existe déjà."
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
log "Lister les fichiers présents dans local/bin"
|
|
||||||
ls local/bin/ -c1 >.config/files_local-bin
|
|
||||||
|
|
||||||
|
|
||||||
########
|
|
||||||
# 1. Lister des fichiers dans local/share/doc
|
|
||||||
# 2. Générer les fichiers man dans local/share/man
|
|
||||||
# 3. Lister des fichiers dans local/share/man
|
|
||||||
# 4. Lister des fichiers dans local/share/ytdll et share/ytdll/lib
|
|
||||||
|
|
||||||
# Spécifier le chemin du répertoire du dépôt Git local
|
|
||||||
source_dir="local/share/doc"
|
|
||||||
|
|
||||||
# Spécifier le chemin du répertoire
|
|
||||||
destination_dir="local/share/man"
|
|
||||||
|
|
||||||
create_dir "$destination_dir"
|
|
||||||
|
|
||||||
log "Lister les fichiers présents dans local/share/doc"
|
|
||||||
ls "$source_dir/" -c1 >.config/files_local-share-doc
|
|
||||||
|
|
||||||
log "Creer les pages MAN"
|
|
||||||
|
|
||||||
file_local_desc=.config/files_local-share-doc
|
|
||||||
|
|
||||||
# Répertoire local/share/man
|
|
||||||
## Vérifier si Pandoc est installé
|
|
||||||
if ! command -v pandoc &> /dev/null; then
|
|
||||||
log "Pandoc n'est pas installé."
|
|
||||||
|
|
||||||
# Vérifier la distribution pour utiliser le gestionnaire de paquets approprié
|
|
||||||
if [ -x "$(command -v dnf)" ]; then
|
|
||||||
log "Installation de Pandoc via DNF (Red Hat)..."
|
|
||||||
sudo dnf install -y pandoc
|
|
||||||
elif [ -x "$(command -v yum)" ]; then
|
|
||||||
log "Installation de Pandoc via YUM (Red Hat)..."
|
|
||||||
sudo dnf install -y pandoc
|
|
||||||
elif [ -x "$(command -v apt)" ]; then
|
|
||||||
log "Installation de Pandoc via APT (Debian)..."
|
|
||||||
sudo apt update && sudo apt install -y pandoc
|
|
||||||
else
|
|
||||||
error "Le gestionnaire de paquets n'est pas pris en charge."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Vérifier à nouveau si Pandoc est installé
|
|
||||||
if ! command -v pandoc &> /dev/null; then
|
|
||||||
error "L'installation de Pandoc a échoué."
|
|
||||||
else
|
|
||||||
log "Pandoc a été installé avec succès."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
log " Traitement des fichiers à copier dans $destination_dir"
|
|
||||||
# Génération des fihciers man
|
|
||||||
log " Vérifier si le fichier $file_local_desc existe"
|
|
||||||
if [ -e "$file_local_desc" ]; then
|
|
||||||
log " Récupérer des fichiers installés"
|
|
||||||
fileslist_local=$(cat $file_local_desc)
|
|
||||||
|
|
||||||
log " Créer la page man"
|
|
||||||
for file in $fileslist_local; do
|
|
||||||
new_name="${file%.*}" # Supprimer l'extension md
|
|
||||||
if [ -f "$source_dir/$file" ]; then
|
|
||||||
pandoc -s "$source_dir/$file" -t man -o "$destination_dir/$new_name" || error "Impossible de créer la page 'man' $destination_dir/$new_name depuis $source_dir/$file"
|
|
||||||
log " Creation de la page MAN $destination_dir/$new_name depuis $source_dir/$file"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
else
|
|
||||||
error " Le fichier $file_local_desc est introuvable."
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Lister les fichiers présents dans local/share/man"
|
|
||||||
ls local/share/man/ -c1 >.config/files_local-share-man
|
|
||||||
|
|
||||||
log "Lister les fichiers présents dans local/share/ytdll"
|
|
||||||
ls local/share/ytdll/ -c1 >.config/files_local-share-ytdll
|
|
||||||
|
|
||||||
log "Lister les fichiers présents dans local/share/ytdll/lib"
|
|
||||||
ls local/share/ytdll/lib/ -c1 >.config/files_local-share-ytdll-lib
|
|
||||||
|
|
||||||
########
|
|
||||||
# Résumé des DOC
|
|
||||||
|
|
||||||
|
|
||||||
for fichier in local/share/doc/*.md; do
|
|
||||||
echo "Résumé pour $fichier :"
|
|
||||||
description_found=0
|
|
||||||
empty_line_encountered=false
|
|
||||||
description_started=0
|
|
||||||
|
|
||||||
while IFS= read -r ligne; do
|
|
||||||
if [ "$description_found" -eq 1 ] && [ "$description_started" -eq 1 ] && [ -n "$ligne" ]; then
|
|
||||||
echo "$ligne"
|
|
||||||
elif [ "$description_found" -eq 1 ] && [ "$description_started" -eq 0 ] && [ -n "$ligne" ]; then
|
|
||||||
echo "$ligne"
|
|
||||||
description_started=1
|
|
||||||
elif [ "$description_found" -eq 1 ] && [ "$description_started" -eq 1 ] && [ ! -n "$ligne" ]; then
|
|
||||||
break
|
|
||||||
elif [ "$ligne" = "# DESCRIPTION" ]; then
|
|
||||||
description_found=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
done < "$fichier"
|
|
||||||
|
|
||||||
echo "..."
|
|
||||||
done
|
|
||||||
|
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
#!/usr/bin/env php
|
#!/usr/bin/env php
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Audit de dérive des configurations PHP
|
* Nettoyeur de surcharge de configuration PHP
|
||||||
|
* Supprime les entrées locales identiques aux originales.
|
||||||
* Copyright (C) 2026 Cédric Abonnel
|
* Copyright (C) 2026 Cédric Abonnel
|
||||||
* License: GNU Affero General Public License v3
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// --- Initialisation & Sécurité ---
|
|
||||||
|
|
||||||
if (posix_getuid() !== 0) {
|
if (posix_getuid() !== 0) {
|
||||||
fwrite(STDERR, "Ce script doit être exécuté en root.\n");
|
fwrite(STDERR, "Ce script doit être exécuté en root.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -16,89 +14,76 @@ if (posix_getuid() !== 0) {
|
|||||||
const CONF_DIR = '/opt/monitoring/conf';
|
const CONF_DIR = '/opt/monitoring/conf';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extrait les clés d'un fichier de configuration PHP (tableau return [])
|
* Logique d'affichage
|
||||||
* sans exécuter le fichier pour éviter les effets de bord, via Regex.
|
|
||||||
*/
|
*/
|
||||||
function extract_keys($file) {
|
function log_clean($level, $msg) {
|
||||||
$content = file_get_contents($file);
|
$color = ['info' => '34', 'notice' => '32', 'warn' => '33', 'err' => '31'][$level] ?? '37';
|
||||||
// On cherche les patterns : 'KEY' => ou "KEY" =>
|
echo sprintf("\e[%sm[%s]\e[0m %s\n", $color, strtoupper($level), $msg);
|
||||||
preg_match_all('/[\'"]([A-Z0-9_]+)[\'"]\s*=>/i', $content, $matches);
|
|
||||||
$keys = $matches[1] ?? [];
|
|
||||||
sort($keys);
|
|
||||||
return array_unique($keys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logique de logging
|
* Nettoie un fichier local en comparant ses valeurs avec la base
|
||||||
*/
|
*/
|
||||||
function log_audit($level, $event, $msg) {
|
function clean_local_config($base_file, $local_file) {
|
||||||
echo sprintf("[%s] %s: %s\n", strtoupper($level), $event, $msg);
|
// On inclut les fichiers pour récupérer les tableaux de config
|
||||||
}
|
$base_cfg = include $base_file;
|
||||||
|
$local_cfg = include $local_file;
|
||||||
|
|
||||||
function check_config_drift() {
|
if (!is_array($base_cfg) || !is_array($local_cfg)) {
|
||||||
$found_issue = false;
|
return false;
|
||||||
$reviewed_files = 0;
|
|
||||||
$files_requiring_action = 0;
|
|
||||||
|
|
||||||
log_audit('info', 'audit_start', "Début de l'audit des configurations PHP");
|
|
||||||
|
|
||||||
// On cherche les fichiers .php qui ne sont pas des .local.php
|
|
||||||
$base_files = glob(CONF_DIR . '/*.php');
|
|
||||||
$base_files = array_filter($base_files, function($f) {
|
|
||||||
return !str_ends_with($f, '.local.php');
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach ($base_files as $base_conf) {
|
|
||||||
$reviewed_files++;
|
|
||||||
$base_name = basename($base_conf);
|
|
||||||
$local_conf = str_replace('.php', '.local.php', $base_conf);
|
|
||||||
$local_name = basename($local_conf);
|
|
||||||
|
|
||||||
// 1. Si le fichier local n'existe pas
|
|
||||||
if (!file_exists($local_conf)) {
|
|
||||||
if (copy($base_conf, $local_conf)) {
|
|
||||||
chmod($local_conf, 0600);
|
|
||||||
log_audit('notice', 'audit_missing_local', "Le fichier $local_name a été créé par copie de $base_name");
|
|
||||||
} else {
|
|
||||||
log_audit('error', 'audit_create_local_failed', "Impossible de créer $local_name");
|
|
||||||
$found_issue = true;
|
|
||||||
$files_requiring_action++;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Comparaison des clés
|
$new_local_cfg = $local_cfg;
|
||||||
$keys_base = extract_keys($base_conf);
|
$removed_keys = [];
|
||||||
$keys_local = extract_keys($local_conf);
|
|
||||||
|
|
||||||
$missing = array_diff($keys_base, $keys_local); // Présent dans base mais pas local
|
foreach ($local_cfg as $key => $value) {
|
||||||
$obsolete = array_diff($keys_local, $keys_base); // Présent dans local mais plus dans base
|
// Si la clé existe en base ET que la valeur est strictement identique
|
||||||
|
if (array_key_exists($key, $base_cfg) && $base_cfg[$key] === $value) {
|
||||||
if (!empty($missing) || !empty($obsolete)) {
|
unset($new_local_cfg[$key]);
|
||||||
$found_issue = true;
|
$removed_keys[] = $key;
|
||||||
$files_requiring_action++;
|
|
||||||
|
|
||||||
log_audit('warning', 'audit_file_requires_action', "Vérification requise pour $local_name");
|
|
||||||
|
|
||||||
if (!empty($missing)) {
|
|
||||||
log_audit('warning', 'audit_keys_missing', "Options absentes de $local_name : " . implode(', ', $missing));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($obsolete)) {
|
|
||||||
log_audit('info', 'audit_keys_obsolete', "Options obsolètes ou personnalisées dans $local_name : " . implode(', ', $obsolete));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log_audit('info', 'audit_file_ok', "Le fichier $local_name est synchronisé avec $base_name");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Résumé final
|
if (empty($removed_keys)) {
|
||||||
if (!$found_issue) {
|
log_clean('info', basename($local_file) . " est déjà optimisé.");
|
||||||
log_audit('info', 'audit_success', "Toutes les configurations sont à jour ($reviewed_files fichiers vérifiés)");
|
return true;
|
||||||
} else {
|
|
||||||
log_audit('warning', 'audit_requires_action', "Action requise sur $files_requiring_action fichier(s) sur $reviewed_files");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reconstruction du fichier PHP proprement
|
||||||
|
$content = "<?php\n/**\n * Configuration locale personnalisée\n * Généré par l'audit de nettoyage\n */\n\nreturn [\n";
|
||||||
|
foreach ($new_local_cfg as $key => $value) {
|
||||||
|
$val_export = var_export($value, true);
|
||||||
|
$content .= " '$key' => $val_export,\n";
|
||||||
|
}
|
||||||
|
$content .= "];\n";
|
||||||
|
|
||||||
|
if (file_put_contents($local_file, $content)) {
|
||||||
|
log_clean('notice', basename($local_file) . " nettoyé. Clés supprimées (identiques à la base) : " . implode(', ', $removed_keys));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Main ---
|
// --- Main ---
|
||||||
check_config_drift();
|
|
||||||
|
log_clean('info', "Début de l'optimisation des configurations locales...");
|
||||||
|
|
||||||
|
$base_files = glob(CONF_DIR . '/*.php');
|
||||||
|
foreach ($base_files as $base_conf) {
|
||||||
|
// On ignore les fichiers .local.php et .conf.local.php
|
||||||
|
if (str_contains($base_conf, '.local.')) continue;
|
||||||
|
|
||||||
|
// Détermination du nom du fichier local correspondant
|
||||||
|
// Gère tes deux formats : monitoring.local.conf.php et alert-engine.conf.local.php
|
||||||
|
$local_conf = str_replace('.conf.php', '.conf.local.php', $base_conf);
|
||||||
|
if (!file_exists($local_conf)) {
|
||||||
|
$local_conf = str_replace('.php', '.local.php', $base_conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists($local_conf)) {
|
||||||
|
clean_local_config($base_conf, $local_conf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_clean('info', "Optimisation terminée.");
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Copyright (C) 2026 Cédric Abonnel
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
# Fichiers d'état
|
|
||||||
ALERT_STATE_FILE="${MONITORING_STATE_DIR}/alert-engine.offset"
|
|
||||||
ALERT_DEDUP_FILE="${MONITORING_STATE_DIR}/alert-engine.dedup"
|
|
||||||
|
|
||||||
# Activation des canaux
|
|
||||||
ALERT_NTFY_ENABLED="true"
|
|
||||||
ALERT_MAIL_ENABLED="true"
|
|
||||||
|
|
||||||
# Mail
|
|
||||||
ALERT_MAIL_BIN="/usr/sbin/sendmail"
|
|
||||||
ALERT_MAIL_SUBJECT_PREFIX="[monitoring]"
|
|
||||||
|
|
||||||
# ntfy
|
|
||||||
NTFY_SERVER="https://ntfy.sh"
|
|
||||||
NTFY_TOPIC="TPOSOB84sBJ6HTZ7"
|
|
||||||
NTFY_TOKEN=""
|
|
||||||
|
|
||||||
# Déduplication en secondes
|
|
||||||
ALERT_DEDUP_WINDOW=3600
|
|
||||||
|
|
||||||
# Événements à ignorer
|
|
||||||
ALERT_IGNORE_EVENTS="update_not_needed alert_sent_ntfy alert_sent_mail"
|
|
||||||
|
|
||||||
# Règles par défaut selon le niveau
|
|
||||||
ALERT_DEFAULT_CHANNELS_WARNING="ntfy"
|
|
||||||
ALERT_DEFAULT_CHANNELS_ERROR="ntfy,mail"
|
|
||||||
ALERT_DEFAULT_CHANNELS_CRITICAL="ntfy,mail"
|
|
||||||
|
|
||||||
# Règles spécifiques par événement
|
|
||||||
ALERT_RULE_disk_usage_high="ntfy"
|
|
||||||
ALERT_RULE_disk_usage_critical="ntfy,mail"
|
|
||||||
ALERT_RULE_check_failed="ntfy,mail"
|
|
||||||
ALERT_RULE_internal_error="ntfy,mail"
|
|
||||||
|
|
||||||
ALERT_RULE_update_hash_unavailable="ntfy"
|
|
||||||
ALERT_RULE_update_download_failed="ntfy,mail"
|
|
||||||
ALERT_RULE_update_hash_mismatch="ntfy,mail"
|
|
||||||
ALERT_RULE_manifest_download_failed="ntfy,mail"
|
|
||||||
ALERT_RULE_manifest_invalid="ntfy,mail"
|
|
||||||
ALERT_RULE_update_finished_with_errors="ntfy,mail"
|
|
||||||
|
|
||||||
# Optionnel : certains événements peuvent être forcés en ntfy uniquement
|
|
||||||
# ALERT_RULE_disk_ok=""
|
|
||||||
# ALERT_RULE_update_finished=""
|
|
||||||
|
|
||||||
# Optionnel : URL ouverte quand on clique sur la notif ntfy
|
|
||||||
NTFY_CLICK_URL=""
|
|
||||||
|
|
||||||
# Optionnel : tags par niveau pour ntfy
|
|
||||||
NTFY_TAGS_WARNING="warning"
|
|
||||||
NTFY_TAGS_ERROR="warning,rotating_light"
|
|
||||||
NTFY_TAGS_CRITICAL="skull,warning"
|
|
||||||
@@ -1,352 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Copyright (C) 2026 Cédric Abonnel
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
set -u
|
|
||||||
|
|
||||||
SCRIPT_NAME="$(basename "$0")"
|
|
||||||
SCRIPT_PATH="$(readlink -f "$0" 2>/dev/null || realpath "$0" 2>/dev/null || echo "$0")"
|
|
||||||
|
|
||||||
# shellcheck source=/opt/monitoring/lib/monitoring-lib.sh
|
|
||||||
. /opt/monitoring/lib/monitoring-lib.sh || exit 3
|
|
||||||
|
|
||||||
load_conf_if_exists "/opt/monitoring/conf/alert-engine.conf"
|
|
||||||
load_conf_if_exists "/opt/monitoring/conf/alert-engine.local.conf"
|
|
||||||
|
|
||||||
lock_or_exit "alert-engine"
|
|
||||||
require_cmd awk sed grep date tail stat cut tr
|
|
||||||
|
|
||||||
LOG_SOURCE="${LOG_FILE:-/var/log/monitoring/events.jsonl}"
|
|
||||||
STATE_FILE="${ALERT_STATE_FILE:-/var/lib/monitoring/alert-engine.offset}"
|
|
||||||
DEDUP_FILE="${ALERT_DEDUP_FILE:-/var/lib/monitoring/alert-engine.dedup}"
|
|
||||||
|
|
||||||
mkdir -p "$(dirname "$STATE_FILE")" "$(dirname "$DEDUP_FILE")" || fail_internal "Impossible de créer les répertoires d'état"
|
|
||||||
touch "$STATE_FILE" "$DEDUP_FILE" || fail_internal "Impossible d'initialiser les fichiers d'état"
|
|
||||||
|
|
||||||
json_get() {
|
|
||||||
local key="$1"
|
|
||||||
local line="$2"
|
|
||||||
|
|
||||||
printf '%s\n' "$line" \
|
|
||||||
| sed -n "s/.*\"${key}\":\"\([^\"]*\)\".*/\1/p" \
|
|
||||||
| head -n1
|
|
||||||
}
|
|
||||||
|
|
||||||
json_get_number() {
|
|
||||||
local key="$1"
|
|
||||||
local line="$2"
|
|
||||||
|
|
||||||
printf '%s\n' "$line" \
|
|
||||||
| sed -n "s/.*\"${key}\":\([0-9][0-9]*\).*/\1/p" \
|
|
||||||
| head -n1
|
|
||||||
}
|
|
||||||
|
|
||||||
get_last_offset() {
|
|
||||||
local offset
|
|
||||||
offset="$(cat "$STATE_FILE" 2>/dev/null || true)"
|
|
||||||
if [[ "$offset" =~ ^[0-9]+$ ]]; then
|
|
||||||
printf '%s\n' "$offset"
|
|
||||||
else
|
|
||||||
printf '0\n'
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
set_last_offset() {
|
|
||||||
printf '%s\n' "$1" > "$STATE_FILE"
|
|
||||||
}
|
|
||||||
|
|
||||||
current_log_size() {
|
|
||||||
stat -c '%s' "$LOG_SOURCE" 2>/dev/null || printf '0\n'
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup_dedup_file() {
|
|
||||||
local now window tmp
|
|
||||||
now="$(date +%s)"
|
|
||||||
window="${ALERT_DEDUP_WINDOW:-3600}"
|
|
||||||
tmp="$(mktemp "${MONITORING_STATE_DIR}/alert-engine.dedup.XXXXXX")" || return 0
|
|
||||||
|
|
||||||
awk -F'|' -v now="$now" -v window="$window" '
|
|
||||||
NF >= 2 {
|
|
||||||
if ((now - $2) <= window) print $0
|
|
||||||
}
|
|
||||||
' "$DEDUP_FILE" > "$tmp" 2>/dev/null || true
|
|
||||||
|
|
||||||
mv -f "$tmp" "$DEDUP_FILE" 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
dedup_key() {
|
|
||||||
local host="$1"
|
|
||||||
local app="$2"
|
|
||||||
local level="$3"
|
|
||||||
local event="$4"
|
|
||||||
printf '%s|%s|%s|%s\n' "$host" "$app" "$level" "$event"
|
|
||||||
}
|
|
||||||
|
|
||||||
should_notify_dedup() {
|
|
||||||
local key="$1"
|
|
||||||
local now window found_ts
|
|
||||||
now="$(date +%s)"
|
|
||||||
window="${ALERT_DEDUP_WINDOW:-3600}"
|
|
||||||
|
|
||||||
found_ts="$(awk -F'|' -v k="$key" '
|
|
||||||
$1 "|" $3 "|" $4 "|" $5 == k {print $2}
|
|
||||||
' "$DEDUP_FILE" | tail -n1)"
|
|
||||||
|
|
||||||
if [[ "$found_ts" =~ ^[0-9]+$ ]]; then
|
|
||||||
if [ $((now - found_ts)) -lt "$window" ]; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
save_dedup_entry() {
|
|
||||||
local host="$1"
|
|
||||||
local app="$2"
|
|
||||||
local level="$3"
|
|
||||||
local event="$4"
|
|
||||||
local now
|
|
||||||
now="$(date +%s)"
|
|
||||||
printf '%s|%s|%s|%s|%s\n' "$host" "$now" "$app" "$level" "$event" >> "$DEDUP_FILE"
|
|
||||||
}
|
|
||||||
|
|
||||||
event_is_ignored() {
|
|
||||||
local event="$1" ignored
|
|
||||||
for ignored in ${ALERT_IGNORE_EVENTS:-}; do
|
|
||||||
[ "$ignored" = "$event" ] && return 0
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
channels_for_event() {
|
|
||||||
local level="$1"
|
|
||||||
local event="$2"
|
|
||||||
local varname value
|
|
||||||
|
|
||||||
varname="ALERT_RULE_${event}"
|
|
||||||
value="${!varname:-}"
|
|
||||||
|
|
||||||
if [ -n "$value" ]; then
|
|
||||||
printf '%s\n' "$value"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$level" in
|
|
||||||
WARNING)
|
|
||||||
printf '%s\n' "${ALERT_DEFAULT_CHANNELS_WARNING:-ntfy}"
|
|
||||||
;;
|
|
||||||
ERROR)
|
|
||||||
printf '%s\n' "${ALERT_DEFAULT_CHANNELS_ERROR:-ntfy,mail}"
|
|
||||||
;;
|
|
||||||
CRITICAL)
|
|
||||||
printf '%s\n' "${ALERT_DEFAULT_CHANNELS_CRITICAL:-ntfy,mail}"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
printf '\n'
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
tags_for_level() {
|
|
||||||
case "$1" in
|
|
||||||
WARNING) printf '%s\n' "${NTFY_TAGS_WARNING:-warning}" ;;
|
|
||||||
ERROR) printf '%s\n' "${NTFY_TAGS_ERROR:-warning,rotating_light}" ;;
|
|
||||||
CRITICAL) printf '%s\n' "${NTFY_TAGS_CRITICAL:-skull,warning}" ;;
|
|
||||||
*) printf '\n' ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
send_ntfy() {
|
|
||||||
|
|
||||||
local title="$1"
|
|
||||||
local body="$2"
|
|
||||||
local priority="$3"
|
|
||||||
|
|
||||||
[ "${ALERT_NTFY_ENABLED:-true}" = "true" ] || return 0
|
|
||||||
[ -n "${NTFY_SERVER:-}" ] || return 1
|
|
||||||
[ -n "${NTFY_TOPIC:-}" ] || return 1
|
|
||||||
|
|
||||||
local url="${NTFY_SERVER%/}/${NTFY_TOPIC}"
|
|
||||||
|
|
||||||
local curl_args=(
|
|
||||||
-fsS
|
|
||||||
-X POST
|
|
||||||
-H "Title: ${title}"
|
|
||||||
-H "Priority: ${priority}"
|
|
||||||
-H "Tags: warning"
|
|
||||||
-d "$body"
|
|
||||||
)
|
|
||||||
|
|
||||||
# topic protégé
|
|
||||||
if [ -n "${NTFY_TOKEN:-}" ]; then
|
|
||||||
curl_args+=(-H "Authorization: Bearer ${NTFY_TOKEN}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
curl "${curl_args[@]}" "$url" >/dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
send_mail() {
|
|
||||||
local subject="$1"
|
|
||||||
local body="$2"
|
|
||||||
|
|
||||||
[ "${ALERT_MAIL_ENABLED:-true}" = "true" ] || return 0
|
|
||||||
[ -n "${DEST:-}" ] || return 1
|
|
||||||
[ -x "${ALERT_MAIL_BIN:-/usr/sbin/sendmail}" ] || return 1
|
|
||||||
|
|
||||||
{
|
|
||||||
printf 'To: %s\n' "${DEST}"
|
|
||||||
printf 'Subject: %s %s\n' "${ALERT_MAIL_SUBJECT_PREFIX:-[monitoring]}" "$subject"
|
|
||||||
printf 'Content-Type: text/plain; charset=UTF-8\n'
|
|
||||||
printf '\n'
|
|
||||||
printf '%s\n' "$body"
|
|
||||||
} | "${ALERT_MAIL_BIN:-/usr/sbin/sendmail}" -t
|
|
||||||
}
|
|
||||||
|
|
||||||
priority_for_level() {
|
|
||||||
case "$1" in
|
|
||||||
CRITICAL) printf 'urgent\n' ;;
|
|
||||||
ERROR) printf 'high\n' ;;
|
|
||||||
WARNING) printf 'default\n' ;;
|
|
||||||
*) printf 'default\n' ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
build_title() {
|
|
||||||
local host="$1"
|
|
||||||
local app="$2"
|
|
||||||
local level="$3"
|
|
||||||
local event="$4"
|
|
||||||
printf '%s [%s] %s %s\n' "$host" "$app" "$level" "$event"
|
|
||||||
}
|
|
||||||
|
|
||||||
build_body() {
|
|
||||||
local ts="$1"
|
|
||||||
local host="$2"
|
|
||||||
local app="$3"
|
|
||||||
local level="$4"
|
|
||||||
local event="$5"
|
|
||||||
local message="$6"
|
|
||||||
local line="$7"
|
|
||||||
|
|
||||||
cat <<EOF
|
|
||||||
Date: $ts
|
|
||||||
Hôte: $host
|
|
||||||
Script: $app
|
|
||||||
Niveau: $level
|
|
||||||
Événement: $event
|
|
||||||
|
|
||||||
Message:
|
|
||||||
$message
|
|
||||||
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
process_line() {
|
|
||||||
|
|
||||||
local line="$1"
|
|
||||||
local ts host app level event message channels title body prio ch key
|
|
||||||
|
|
||||||
ts="$(json_get "ts" "$line")"
|
|
||||||
host="$(json_get "host" "$line")"
|
|
||||||
app="$(json_get "app" "$line")"
|
|
||||||
level="$(json_get "level" "$line")"
|
|
||||||
event="$(json_get "event" "$line")"
|
|
||||||
message="$(json_get "message" "$line")"
|
|
||||||
|
|
||||||
local tags
|
|
||||||
tags="$(tags_for_level "$level")"
|
|
||||||
|
|
||||||
[ -n "$level" ] || return 0
|
|
||||||
[ -n "$event" ] || return 0
|
|
||||||
|
|
||||||
case "$level" in
|
|
||||||
DEBUG|INFO|NOTICE)
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if event_is_ignored "$event"; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
key="$(dedup_key "$host" "$app" "$level" "$event")"
|
|
||||||
if ! should_notify_dedup "$key"; then
|
|
||||||
log_debug "alert_suppressed_dedup" "Alerte supprimée par déduplication" \
|
|
||||||
"event=$event" "level=$level" "host=$host" "app=$app"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
channels="$(channels_for_event "$level" "$event")"
|
|
||||||
[ -n "$channels" ] || return 0
|
|
||||||
|
|
||||||
title="$(build_title "$host" "$app" "$level" "$event")"
|
|
||||||
body="$(build_body "$ts" "$host" "$app" "$level" "$event" "$message" "$line")"
|
|
||||||
prio="$(priority_for_level "$level")"
|
|
||||||
|
|
||||||
IFS=',' read -r -a channel_array <<< "$channels"
|
|
||||||
for ch in "${channel_array[@]}"; do
|
|
||||||
case "$ch" in
|
|
||||||
ntfy)
|
|
||||||
if send_ntfy "$title" "$body" "$prio" "$tags"; then
|
|
||||||
log_info "alert_sent_ntfy" "Notification ntfy envoyée" \
|
|
||||||
"event=$event" "level=$level" "host=$host" "app=$app"
|
|
||||||
else
|
|
||||||
log_error "alert_ntfy_failed" "Échec d'envoi ntfy" \
|
|
||||||
"event=$event" "level=$level" "host=$host" "app=$app"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
mail)
|
|
||||||
if send_mail "$title" "$body"; then
|
|
||||||
log_info "alert_sent_mail" "Mail d'alerte envoyé" \
|
|
||||||
"event=$event" "level=$level" "host=$host" "app=$app"
|
|
||||||
else
|
|
||||||
log_error "alert_mail_failed" "Échec d'envoi mail" \
|
|
||||||
"event=$event" "level=$level" "host=$host" "app=$app"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
save_dedup_entry "$host" "$app" "$level" "$event"
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
local last_offset log_size
|
|
||||||
last_offset="$(get_last_offset)"
|
|
||||||
log_size="$(current_log_size)"
|
|
||||||
|
|
||||||
if [ ! -f "$LOG_SOURCE" ]; then
|
|
||||||
log_notice "alert_log_missing" "Fichier de log absent, rien à traiter" "file=$LOG_SOURCE"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$last_offset" -gt "$log_size" ]; then
|
|
||||||
log_notice "alert_offset_reset" "Offset réinitialisé après rotation ou troncature du log" \
|
|
||||||
"old_offset=$last_offset" "new_offset=0"
|
|
||||||
last_offset=0
|
|
||||||
fi
|
|
||||||
|
|
||||||
cleanup_dedup_file
|
|
||||||
|
|
||||||
tail -c +$((last_offset + 1)) "$LOG_SOURCE" | while IFS= read -r line; do
|
|
||||||
[ -n "$line" ] || continue
|
|
||||||
process_line "$line"
|
|
||||||
done
|
|
||||||
|
|
||||||
set_last_offset "$log_size"
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
||||||
exit_with_status
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Copyright (C) 2026 Cédric Abonnel
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
MONITORING_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
MONITORING_BASE_DIR="$(cd "${MONITORING_LIB_DIR}/.." && pwd)"
|
|
||||||
MONITORING_CONF_DIR="${MONITORING_BASE_DIR}/conf"
|
|
||||||
|
|
||||||
# Chargement config globale
|
|
||||||
if [ -f "${MONITORING_CONF_DIR}/monitoring.conf" ]; then
|
|
||||||
# shellcheck source=/dev/null
|
|
||||||
. "${MONITORING_CONF_DIR}/monitoring.conf"
|
|
||||||
fi
|
|
||||||
|
|
||||||
SCRIPT_NAME="${SCRIPT_NAME:-$(basename "$0")}"
|
|
||||||
SCRIPT_PATH="${SCRIPT_PATH:-$(readlink -f "$0" 2>/dev/null || realpath "$0" 2>/dev/null || echo "$0")}"
|
|
||||||
|
|
||||||
STATUS_OK=0
|
|
||||||
STATUS_WARNING=1
|
|
||||||
STATUS_ERROR=2
|
|
||||||
STATUS_INTERNAL=3
|
|
||||||
|
|
||||||
CURRENT_STATUS=$STATUS_OK
|
|
||||||
|
|
||||||
LOG_LEVEL=${LOG_LEVEL:-INFO}
|
|
||||||
|
|
||||||
json_escape() {
|
|
||||||
local s="${1:-}"
|
|
||||||
s="${s//\\/\\\\}"
|
|
||||||
s="${s//\"/\\\"}"
|
|
||||||
s="${s//$'\n'/\\n}"
|
|
||||||
s="${s//$'\r'/\\r}"
|
|
||||||
s="${s//$'\t'/\\t}"
|
|
||||||
printf '%s' "$s"
|
|
||||||
}
|
|
||||||
|
|
||||||
log_event() {
|
|
||||||
local level="$1"
|
|
||||||
local event="$2"
|
|
||||||
local message="$3"
|
|
||||||
shift 3
|
|
||||||
|
|
||||||
local ts extra key value kv host
|
|
||||||
ts="$(date --iso-8601=seconds)"
|
|
||||||
|
|
||||||
# Détection dynamique du hostname si HOSTNAME_FQDN n'est pas défini
|
|
||||||
# On utilise 'hostname -f' pour le nom complet ou 'hostname' en secours
|
|
||||||
host="${HOSTNAME_FQDN:-$(hostname -f 2>/dev/null || hostname)}"
|
|
||||||
|
|
||||||
extra=""
|
|
||||||
|
|
||||||
for kv in "$@"; do
|
|
||||||
key="${kv%%=*}"
|
|
||||||
value="${kv#*=}"
|
|
||||||
extra="${extra},\"$(json_escape "$key")\":\"$(json_escape "$value")\""
|
|
||||||
done
|
|
||||||
|
|
||||||
# Utilisation de la variable 'host' détectée ci-dessus
|
|
||||||
printf '{"ts":"%s","host":"%s","app":"%s","level":"%s","event":"%s","message":"%s"%s}\n' \
|
|
||||||
"$(json_escape "$ts")" \
|
|
||||||
"$(json_escape "$host")" \
|
|
||||||
"$(json_escape "$SCRIPT_NAME")" \
|
|
||||||
"$(json_escape "$level")" \
|
|
||||||
"$(json_escape "$event")" \
|
|
||||||
"$(json_escape "$message")" \
|
|
||||||
"$extra" >> "${LOG_FILE:-/var/log/monitoring/events.jsonl}"
|
|
||||||
}
|
|
||||||
|
|
||||||
set_status() {
|
|
||||||
local new_status="$1"
|
|
||||||
if [ "$new_status" -gt "$CURRENT_STATUS" ]; then
|
|
||||||
CURRENT_STATUS="$new_status"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug() { log_event "DEBUG" "$@"; }
|
|
||||||
log_info() { log_event "INFO" "$@"; }
|
|
||||||
log_notice() { log_event "NOTICE" "$@"; }
|
|
||||||
log_warning() { log_event "WARNING" "$@"; set_status "$STATUS_WARNING"; }
|
|
||||||
log_error() { log_event "ERROR" "$@"; set_status "$STATUS_ERROR"; }
|
|
||||||
log_critical() { log_event "CRITICAL" "$@"; set_status "$STATUS_ERROR"; }
|
|
||||||
|
|
||||||
fail_internal() {
|
|
||||||
log_event "ERROR" "internal_error" "$1"
|
|
||||||
exit "$STATUS_INTERNAL"
|
|
||||||
}
|
|
||||||
|
|
||||||
exit_with_status() {
|
|
||||||
exit "$CURRENT_STATUS"
|
|
||||||
}
|
|
||||||
|
|
||||||
require_cmd() {
|
|
||||||
local cmd
|
|
||||||
for cmd in "$@"; do
|
|
||||||
command -v "$cmd" >/dev/null 2>&1 || fail_internal "Commande requise absente: $cmd"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
load_conf_if_exists() {
|
|
||||||
local conf="$1"
|
|
||||||
[ -f "$conf" ] && . "$conf"
|
|
||||||
}
|
|
||||||
|
|
||||||
lock_or_exit() {
|
|
||||||
local lock_name="${1:-$SCRIPT_NAME}"
|
|
||||||
local lock_file="${MONITORING_LOCK_DIR:-/var/lock/monitoring}/${lock_name}.lock"
|
|
||||||
|
|
||||||
exec 9>"$lock_file" || fail_internal "Impossible d'ouvrir le lock $lock_file"
|
|
||||||
flock -n 9 || {
|
|
||||||
log_notice "already_running" "Une autre instance est déjà en cours" "lock=$lock_file"
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
threshold_level() {
|
|
||||||
local value="$1"
|
|
||||||
local warning="$2"
|
|
||||||
local critical="$3"
|
|
||||||
|
|
||||||
if [ "$value" -ge "$critical" ]; then
|
|
||||||
printf 'CRITICAL'
|
|
||||||
elif [ "$value" -ge "$warning" ]; then
|
|
||||||
printf 'WARNING'
|
|
||||||
else
|
|
||||||
printf 'INFO'
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
safe_mv() {
|
|
||||||
local src="$1"
|
|
||||||
local dst="$2"
|
|
||||||
mv -f "$src" "$dst" || fail_internal "Échec du déplacement de $src vers $dst"
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_parent_dir() {
|
|
||||||
local file="$1"
|
|
||||||
mkdir -p "$(dirname "$file")" || fail_internal "Impossible de créer le répertoire parent de $file"
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Copyright (C) 2026 Cédric Abonnel
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
set -u
|
|
||||||
|
|
||||||
SCRIPT_NAME="$(basename "$0")"
|
|
||||||
. /opt/monitoring/lib/monitoring-lib.sh || exit 3
|
|
||||||
|
|
||||||
# On s'assure d'avoir les permissions root
|
|
||||||
if [ "${EUID}" -ne 0 ]; then
|
|
||||||
echo "Ce script doit être exécuté en root." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
extract_keys() {
|
|
||||||
local file="$1"
|
|
||||||
grep -E '^[A-Za-z_][A-Za-z0-9_]*=' "$file" | cut -d'=' -f1 | sort -u
|
|
||||||
}
|
|
||||||
|
|
||||||
check_config_drift() {
|
|
||||||
local conf_dir="/opt/monitoring/conf"
|
|
||||||
local base_conf local_conf
|
|
||||||
local found_issue=false
|
|
||||||
local reviewed_files=0
|
|
||||||
local files_requiring_action=0
|
|
||||||
|
|
||||||
log_info "audit_start" "Début de l'audit des configurations locales"
|
|
||||||
|
|
||||||
while IFS= read -r base_conf; do
|
|
||||||
reviewed_files=$((reviewed_files + 1))
|
|
||||||
|
|
||||||
local_conf="${base_conf%.conf}.local.conf"
|
|
||||||
local file_name local_file_name
|
|
||||||
file_name="$(basename "$base_conf")"
|
|
||||||
local_file_name="$(basename "$local_conf")"
|
|
||||||
|
|
||||||
if [ ! -f "$local_conf" ]; then
|
|
||||||
cp "$base_conf" "$local_conf" || {
|
|
||||||
log_error "audit_create_local_failed" \
|
|
||||||
"Impossible de créer ${local_file_name} à partir de ${file_name}"
|
|
||||||
found_issue=true
|
|
||||||
files_requiring_action=$((files_requiring_action + 1))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
chmod 600 "$local_conf" 2>/dev/null || true
|
|
||||||
|
|
||||||
log_notice "audit_missing_local" \
|
|
||||||
"Le fichier ${local_file_name} n'existait pas ; il a été créé par copie de ${file_name}"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
local tmp_base tmp_local
|
|
||||||
tmp_base="$(mktemp)" || fail_internal "mktemp a échoué"
|
|
||||||
tmp_local="$(mktemp)" || fail_internal "mktemp a échoué"
|
|
||||||
|
|
||||||
extract_keys "$base_conf" > "$tmp_base"
|
|
||||||
extract_keys "$local_conf" > "$tmp_local"
|
|
||||||
|
|
||||||
local missing obsolete
|
|
||||||
missing="$(comm -23 "$tmp_base" "$tmp_local" | xargs)"
|
|
||||||
obsolete="$(comm -13 "$tmp_base" "$tmp_local" | xargs)"
|
|
||||||
|
|
||||||
if [ -n "$missing" ] || [ -n "$obsolete" ]; then
|
|
||||||
found_issue=true
|
|
||||||
files_requiring_action=$((files_requiring_action + 1))
|
|
||||||
|
|
||||||
log_warning "audit_file_requires_action" \
|
|
||||||
"Le fichier ${local_file_name} nécessite une vérification"
|
|
||||||
|
|
||||||
if [ -n "$missing" ]; then
|
|
||||||
log_warning "audit_keys_missing" \
|
|
||||||
"Dans ${local_file_name}, options disponibles dans ${file_name} mais absentes du local : ${missing}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$obsolete" ]; then
|
|
||||||
log_info "audit_keys_obsolete" \
|
|
||||||
"Dans ${local_file_name}, options présentes uniquement dans le local et à vérifier ou supprimer : ${obsolete}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
log_info "audit_file_ok" \
|
|
||||||
"Le fichier ${local_file_name} contient les mêmes options que ${file_name}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f "$tmp_base" "$tmp_local"
|
|
||||||
done < <(find "$conf_dir" -maxdepth 1 -type f -name "*.conf" ! -name "*.local.conf" | sort)
|
|
||||||
|
|
||||||
if [ "$found_issue" = false ]; then
|
|
||||||
log_info "audit_success" \
|
|
||||||
"Toutes les configurations locales sont à jour (${reviewed_files} fichier(s) vérifié(s))"
|
|
||||||
else
|
|
||||||
log_warning "audit_requires_action" \
|
|
||||||
"Certaines configurations locales doivent être mises à jour (${files_requiring_action} fichier(s) à vérifier sur ${reviewed_files})"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
lock_or_exit "monitoring-audit"
|
|
||||||
check_config_drift
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
||||||
exit_with_status
|
|
||||||
@@ -1,247 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Copyright (C) 2026 Cédric Abonnel
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# Moteur de mise à jour des programmes et fichiers connexes
|
|
||||||
|
|
||||||
set -u
|
|
||||||
|
|
||||||
SCRIPT_NAME="$(basename "$0")"
|
|
||||||
SCRIPT_PATH="$(readlink -f "$0" 2>/dev/null || realpath "$0" 2>/dev/null || echo "$0")"
|
|
||||||
|
|
||||||
# shellcheck source=/opt/monitoring/lib/monitoring-lib.sh
|
|
||||||
. /opt/monitoring/lib/monitoring-lib.sh || exit 3
|
|
||||||
|
|
||||||
load_conf_if_exists "/opt/monitoring/conf/autoupdate.conf"
|
|
||||||
load_conf_if_exists "/opt/monitoring/conf/autoupdate.local.conf"
|
|
||||||
|
|
||||||
# Définir les variables par défaut si elles ne sont pas dans les fichiers .conf
|
|
||||||
UPDATE_TMP_DIR="${UPDATE_TMP_DIR:-/tmp/monitoring-update}"
|
|
||||||
UPDATE_TIMEOUT_CONNECT="${UPDATE_TIMEOUT_CONNECT:-3}"
|
|
||||||
UPDATE_TIMEOUT_TOTAL="${UPDATE_TIMEOUT_TOTAL:-15}"
|
|
||||||
UPDATE_MANIFEST_URL="${UPDATE_MANIFEST_URL:-}"
|
|
||||||
UPDATE_BASE_URL="${UPDATE_BASE_URL:-}"
|
|
||||||
|
|
||||||
lock_or_exit "monitoring-update"
|
|
||||||
require_cmd curl sha256sum awk mktemp chmod dirname mv rm grep sed sort comm cut tr find
|
|
||||||
|
|
||||||
[ "${UPDATE_ENABLED:-true}" = "true" ] || {
|
|
||||||
log_notice "update_disabled" "Mise à jour désactivée par configuration"
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
mkdir -p "${UPDATE_TMP_DIR:-/tmp/monitoring-update}" || fail_internal "Impossible de créer le répertoire temporaire"
|
|
||||||
|
|
||||||
TMP_MANIFEST="$(mktemp "${UPDATE_TMP_DIR}/manifest.XXXXXX")" || fail_internal "mktemp a échoué"
|
|
||||||
TMP_LOCAL_LIST="$(mktemp "${UPDATE_TMP_DIR}/local.XXXXXX")" || fail_internal "mktemp a échoué"
|
|
||||||
TMP_REMOTE_LIST="$(mktemp "${UPDATE_TMP_DIR}/remote.XXXXXX")" || fail_internal "mktemp a échoué"
|
|
||||||
|
|
||||||
cleanup() {
|
|
||||||
rm -f "$TMP_MANIFEST" "$TMP_LOCAL_LIST" "$TMP_REMOTE_LIST"
|
|
||||||
}
|
|
||||||
trap cleanup EXIT
|
|
||||||
|
|
||||||
fetch_manifest() {
|
|
||||||
if ! curl -fsS \
|
|
||||||
--connect-timeout "${UPDATE_TIMEOUT_CONNECT:-3}" \
|
|
||||||
--max-time "${UPDATE_TIMEOUT_TOTAL:-15}" \
|
|
||||||
"${UPDATE_MANIFEST_URL}" \
|
|
||||||
-o "$TMP_MANIFEST"; then
|
|
||||||
log_error "manifest_download_failed" \
|
|
||||||
"Impossible de télécharger le manifeste" \
|
|
||||||
"url=${UPDATE_MANIFEST_URL}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! awk '
|
|
||||||
NF == 3 &&
|
|
||||||
$1 ~ /^[0-9a-fA-F]{64}$/ &&
|
|
||||||
$2 ~ /^(644|755)$/ &&
|
|
||||||
$3 ~ /^(bin|lib|conf)\/[A-Za-z0-9._\/-]+$/ &&
|
|
||||||
$3 !~ /\.\./
|
|
||||||
' "$TMP_MANIFEST" >/dev/null; then
|
|
||||||
log_error "manifest_invalid" \
|
|
||||||
"Le manifeste distant est invalide" \
|
|
||||||
"url=${UPDATE_MANIFEST_URL}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_info "manifest_downloaded" "Manifeste téléchargé" "url=${UPDATE_MANIFEST_URL}"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
list_remote_files() {
|
|
||||||
awk '{print $3}' "$TMP_MANIFEST" | sort -u > "$TMP_REMOTE_LIST"
|
|
||||||
}
|
|
||||||
|
|
||||||
list_local_files() {
|
|
||||||
find "${MONITORING_BASE_DIR}/bin" "${MONITORING_BASE_DIR}/lib" "${MONITORING_BASE_DIR}/conf" \
|
|
||||||
-type f 2>/dev/null \
|
|
||||||
| sed "s#^${MONITORING_BASE_DIR}/##" \
|
|
||||||
| sort -u > "$TMP_LOCAL_LIST"
|
|
||||||
}
|
|
||||||
|
|
||||||
apply_mode() {
|
|
||||||
local mode="$1"
|
|
||||||
local file="$2"
|
|
||||||
|
|
||||||
case "$mode" in
|
|
||||||
755) chmod 755 "$file" ;;
|
|
||||||
644) chmod 644 "$file" ;;
|
|
||||||
*) fail_internal "Mode non supporté: $mode" ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
update_one_file() {
|
|
||||||
local expected_hash="$1"
|
|
||||||
local mode="$2"
|
|
||||||
local rel_path="$3"
|
|
||||||
|
|
||||||
local local_file="${MONITORING_BASE_DIR}/${rel_path}"
|
|
||||||
local remote_file="${UPDATE_BASE_URL}/${rel_path}"
|
|
||||||
local tmp_file local_hash downloaded_hash
|
|
||||||
|
|
||||||
tmp_file="$(mktemp "${UPDATE_TMP_DIR}/$(basename "$rel_path").XXXXXX")" || fail_internal "mktemp a échoué"
|
|
||||||
|
|
||||||
if [ -f "$local_file" ]; then
|
|
||||||
local_hash="$(sha256sum "$local_file" | awk '{print $1}')"
|
|
||||||
else
|
|
||||||
local_hash=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$local_hash" = "$expected_hash" ]; then
|
|
||||||
log_debug "update_not_needed" "Fichier déjà à jour" "file=$rel_path"
|
|
||||||
rm -f "$tmp_file"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! curl -fsS \
|
|
||||||
--connect-timeout "${UPDATE_TIMEOUT_CONNECT:-3}" \
|
|
||||||
--max-time "${UPDATE_TIMEOUT_TOTAL:-15}" \
|
|
||||||
"$remote_file" \
|
|
||||||
-o "$tmp_file"; then
|
|
||||||
log_error "update_download_failed" \
|
|
||||||
"Téléchargement impossible" \
|
|
||||||
"file=$rel_path" "url=$remote_file"
|
|
||||||
rm -f "$tmp_file"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
downloaded_hash="$(sha256sum "$tmp_file" | awk '{print $1}')"
|
|
||||||
if [ "$downloaded_hash" != "$expected_hash" ]; then
|
|
||||||
log_error "update_hash_mismatch" \
|
|
||||||
"Hash téléchargé invalide" \
|
|
||||||
"file=$rel_path" "expected=$expected_hash" "got=$downloaded_hash"
|
|
||||||
rm -f "$tmp_file"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
ensure_parent_dir "$local_file"
|
|
||||||
apply_mode "$mode" "$tmp_file"
|
|
||||||
safe_mv "$tmp_file" "$local_file"
|
|
||||||
|
|
||||||
if [ -z "$local_hash" ]; then
|
|
||||||
log_notice "file_created" \
|
|
||||||
"Fichier créé depuis le manifeste" \
|
|
||||||
"file=$rel_path" "mode=$mode" "hash=$expected_hash"
|
|
||||||
else
|
|
||||||
log_notice "update_applied" \
|
|
||||||
"Mise à jour appliquée" \
|
|
||||||
"file=$rel_path" "mode=$mode" "old_hash=$local_hash" "new_hash=$expected_hash"
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
delete_extra_local_files() {
|
|
||||||
[ "${UPDATE_ALLOW_DELETE:-false}" = "true" ] || return 0
|
|
||||||
|
|
||||||
comm -23 "$TMP_LOCAL_LIST" "$TMP_REMOTE_LIST" | while IFS= read -r rel_path; do
|
|
||||||
[ -n "$rel_path" ] || continue
|
|
||||||
|
|
||||||
# Protection globale de TOUS les fichiers .local.conf
|
|
||||||
if [[ "$rel_path" == *.local.conf ]]; then
|
|
||||||
log_notice "delete_skipped" \
|
|
||||||
"Fichier local protégé (ignoré)" \
|
|
||||||
"file=$rel_path"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Sécurité supplémentaire pour ne pas supprimer les répertoires vitaux
|
|
||||||
rm -f "${MONITORING_BASE_DIR}/${rel_path}" \
|
|
||||||
&& log_notice "file_deleted" \
|
|
||||||
"Fichier obsolète supprimé" \
|
|
||||||
"file=$rel_path" \
|
|
||||||
|| log_error "delete_failed" \
|
|
||||||
"Échec suppression" \
|
|
||||||
"file=$rel_path"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
run_local_conf_sync() {
|
|
||||||
|
|
||||||
local sync_script="${MONITORING_BASE_DIR}/bin/sync-local-confs.sh"
|
|
||||||
|
|
||||||
if [ -x "$sync_script" ]; then
|
|
||||||
log_info "local_conf_sync_start" \
|
|
||||||
"Synchronisation des fichiers .local.conf"
|
|
||||||
|
|
||||||
if "$sync_script"; then
|
|
||||||
log_info "local_conf_sync_done" \
|
|
||||||
"Synchronisation terminée"
|
|
||||||
else
|
|
||||||
log_warning "local_conf_sync_failed" \
|
|
||||||
"La synchronisation des .local.conf a échoué"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
log_notice "local_conf_sync_missing" \
|
|
||||||
"Script de synchronisation absent" \
|
|
||||||
"script=$sync_script"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
local total=0 updated_or_checked=0 failed=0
|
|
||||||
local hash mode path
|
|
||||||
|
|
||||||
fetch_manifest || exit 2
|
|
||||||
list_remote_files
|
|
||||||
list_local_files
|
|
||||||
|
|
||||||
while read -r hash mode path; do
|
|
||||||
[ -n "${hash:-}" ] || continue
|
|
||||||
total=$((total + 1))
|
|
||||||
|
|
||||||
if update_one_file "$hash" "$mode" "$path"; then
|
|
||||||
updated_or_checked=$((updated_or_checked + 1))
|
|
||||||
else
|
|
||||||
failed=$((failed + 1))
|
|
||||||
fi
|
|
||||||
done < "$TMP_MANIFEST"
|
|
||||||
|
|
||||||
delete_extra_local_files
|
|
||||||
|
|
||||||
run_local_conf_sync
|
|
||||||
|
|
||||||
if [ "$failed" -gt 0 ]; then
|
|
||||||
log_warning "update_finished_with_errors" \
|
|
||||||
"Mise à jour terminée avec erreurs" \
|
|
||||||
"total=$total" "updated_or_checked=$updated_or_checked" "failed=$failed"
|
|
||||||
else
|
|
||||||
log_info "update_finished" \
|
|
||||||
"Mise à jour terminée" \
|
|
||||||
"total=$total" "updated_or_checked=$updated_or_checked" "failed=0"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
||||||
exit_with_status
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Configuration globale par défaut - NE PAS ÉDITER (Utilisez .local.conf)
|
|
||||||
|
|
||||||
MONITORING_BASE="/opt/monitoring"
|
|
||||||
MONITORING_LOG_DIR="/var/log/monitoring"
|
|
||||||
MONITORING_STATE_DIR="/var/lib/monitoring"
|
|
||||||
MONITORING_LOCK_DIR="/var/lock/monitoring"
|
|
||||||
|
|
||||||
LOG_FILE="${MONITORING_LOG_DIR}/events.jsonl"
|
|
||||||
|
|
||||||
HOSTNAME_FQDN="$(hostname -f 2>/dev/null || hostname)"
|
|
||||||
|
|
||||||
DEST="root"
|
|
||||||
|
|
||||||
NTFY_SERVER="nfy.sh"
|
|
||||||
NTFY_TOPIC="TPOSOB84sBJ6HTZ7"
|
|
||||||
NTFY_TOKEN=""
|
|
||||||
|
|
||||||
UPDATE_ENABLED="true"
|
|
||||||
UPDATE_BASE_URL="https://git.abonnel.fr/cedricAbonnel/scripts-bash/raw/branch/main/servers/linux/monitoring"
|
|
||||||
UPDATE_MANIFEST_URL="${UPDATE_BASE_URL}/manifest.txt"
|
|
||||||
UPDATE_TIMEOUT_CONNECT=3
|
|
||||||
UPDATE_TIMEOUT_TOTAL=15
|
|
||||||
UPDATE_TMP_DIR="/tmp/monitoring-update"
|
|
||||||
UPDATE_ALLOW_DELETE="false"
|
|
||||||
|
|
||||||
mkdir -p "$MONITORING_LOG_DIR" "$MONITORING_STATE_DIR" "$MONITORING_LOCK_DIR" 2>/dev/null || true
|
|
||||||
@@ -1,208 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Copyright (C) 2026 Cédric Abonnel
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# lit le fichier log
|
|
||||||
|
|
||||||
set -u
|
|
||||||
|
|
||||||
SCRIPT_NAME="$(basename "$0")"
|
|
||||||
SCRIPT_PATH="$(readlink -f "$0" 2>/dev/null || realpath "$0" 2>/dev/null || echo "$0")"
|
|
||||||
|
|
||||||
# shellcheck source=/opt/monitoring/lib/monitoring-lib.sh
|
|
||||||
. /opt/monitoring/lib/monitoring-lib.sh || exit 3
|
|
||||||
|
|
||||||
load_conf_if_exists "/opt/monitoring/conf/autoupdate.conf"
|
|
||||||
|
|
||||||
lock_or_exit "monitoring-update"
|
|
||||||
require_cmd curl sha256sum awk mktemp chmod dirname mv rm grep sed sort comm cut tr
|
|
||||||
|
|
||||||
[ "${UPDATE_ENABLED:-true}" = "true" ] || {
|
|
||||||
log_notice "update_disabled" "Mise à jour désactivée par configuration"
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
mkdir -p "${UPDATE_TMP_DIR:-/tmp/monitoring-update}" || fail_internal "Impossible de créer le répertoire temporaire"
|
|
||||||
|
|
||||||
TMP_MANIFEST="$(mktemp "${UPDATE_TMP_DIR}/manifest.XXXXXX")" || fail_internal "mktemp a échoué"
|
|
||||||
TMP_LOCAL_LIST="$(mktemp "${UPDATE_TMP_DIR}/local.XXXXXX")" || fail_internal "mktemp a échoué"
|
|
||||||
TMP_REMOTE_LIST="$(mktemp "${UPDATE_TMP_DIR}/remote.XXXXXX")" || fail_internal "mktemp a échoué"
|
|
||||||
|
|
||||||
cleanup() {
|
|
||||||
rm -f "$TMP_MANIFEST" "$TMP_LOCAL_LIST" "$TMP_REMOTE_LIST"
|
|
||||||
}
|
|
||||||
trap cleanup EXIT
|
|
||||||
|
|
||||||
fetch_manifest() {
|
|
||||||
if ! curl -fsS \
|
|
||||||
--connect-timeout "${UPDATE_TIMEOUT_CONNECT:-3}" \
|
|
||||||
--max-time "${UPDATE_TIMEOUT_TOTAL:-15}" \
|
|
||||||
"${UPDATE_MANIFEST_URL}" \
|
|
||||||
-o "$TMP_MANIFEST"; then
|
|
||||||
log_error "manifest_download_failed" "Impossible de télécharger le manifeste" "url=${UPDATE_MANIFEST_URL}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! awk '
|
|
||||||
NF == 3 &&
|
|
||||||
$1 ~ /^[0-9a-fA-F]{64}$/ &&
|
|
||||||
$2 ~ /^(644|755)$/ &&
|
|
||||||
$3 ~ /^(bin|lib|conf)\/[A-Za-z0-9._\/-]+$/ &&
|
|
||||||
$3 !~ /\.\./
|
|
||||||
' "$TMP_MANIFEST" >/dev/null; then
|
|
||||||
log_error "manifest_invalid" "Le manifeste distant est invalide" "url=${UPDATE_MANIFEST_URL}"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log_info "manifest_downloaded" "Manifeste téléchargé" "url=${UPDATE_MANIFEST_URL}"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
list_remote_files() {
|
|
||||||
awk '{print $3}' "$TMP_MANIFEST" | sort -u > "$TMP_REMOTE_LIST"
|
|
||||||
}
|
|
||||||
|
|
||||||
list_local_files() {
|
|
||||||
find "${MONITORING_BASE_DIR}/bin" "${MONITORING_BASE_DIR}/lib" "${MONITORING_BASE_DIR}/conf" \
|
|
||||||
-type f 2>/dev/null \
|
|
||||||
| sed "s#^${MONITORING_BASE_DIR}/##" \
|
|
||||||
| sort -u > "$TMP_LOCAL_LIST"
|
|
||||||
}
|
|
||||||
|
|
||||||
apply_mode() {
|
|
||||||
local mode="$1"
|
|
||||||
local file="$2"
|
|
||||||
|
|
||||||
case "$mode" in
|
|
||||||
755) chmod 755 "$file" ;;
|
|
||||||
644) chmod 644 "$file" ;;
|
|
||||||
*) fail_internal "Mode non supporté: $mode" ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
update_one_file() {
|
|
||||||
local expected_hash="$1"
|
|
||||||
local mode="$2"
|
|
||||||
local rel_path="$3"
|
|
||||||
|
|
||||||
local local_file="${MONITORING_BASE_DIR}/${rel_path}"
|
|
||||||
local remote_file="${UPDATE_BASE_URL}/${rel_path}"
|
|
||||||
local tmp_file local_hash downloaded_hash
|
|
||||||
|
|
||||||
tmp_file="$(mktemp "${UPDATE_TMP_DIR}/$(basename "$rel_path").XXXXXX")" || fail_internal "mktemp a échoué"
|
|
||||||
|
|
||||||
if [ -f "$local_file" ]; then
|
|
||||||
local_hash="$(sha256sum "$local_file" | awk '{print $1}')"
|
|
||||||
else
|
|
||||||
local_hash=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$local_hash" = "$expected_hash" ]; then
|
|
||||||
log_debug "update_not_needed" "Fichier déjà à jour" "file=$rel_path"
|
|
||||||
rm -f "$tmp_file"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! curl -fsS \
|
|
||||||
--connect-timeout "${UPDATE_TIMEOUT_CONNECT:-3}" \
|
|
||||||
--max-time "${UPDATE_TIMEOUT_TOTAL:-15}" \
|
|
||||||
"$remote_file" \
|
|
||||||
-o "$tmp_file"; then
|
|
||||||
log_error "update_download_failed" "Téléchargement impossible" "file=$rel_path" "url=$remote_file"
|
|
||||||
rm -f "$tmp_file"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
downloaded_hash="$(sha256sum "$tmp_file" | awk '{print $1}')"
|
|
||||||
if [ "$downloaded_hash" != "$expected_hash" ]; then
|
|
||||||
log_error "update_hash_mismatch" "Hash téléchargé invalide" \
|
|
||||||
"file=$rel_path" "expected=$expected_hash" "got=$downloaded_hash"
|
|
||||||
rm -f "$tmp_file"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
ensure_parent_dir "$local_file"
|
|
||||||
apply_mode "$mode" "$tmp_file"
|
|
||||||
safe_mv "$tmp_file" "$local_file"
|
|
||||||
|
|
||||||
if [ -z "$local_hash" ]; then
|
|
||||||
log_notice "file_created" "Fichier créé depuis le manifeste" \
|
|
||||||
"file=$rel_path" "mode=$mode" "hash=$expected_hash"
|
|
||||||
else
|
|
||||||
log_notice "update_applied" "Mise à jour appliquée" \
|
|
||||||
"file=$rel_path" "mode=$mode" "old_hash=$local_hash" "new_hash=$expected_hash"
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
delete_extra_local_files() {
|
|
||||||
|
|
||||||
[ "${UPDATE_ALLOW_DELETE:-false}" = "true" ] || return 0
|
|
||||||
|
|
||||||
comm -23 "$TMP_LOCAL_LIST" "$TMP_REMOTE_LIST" | while IFS= read -r rel_path; do
|
|
||||||
|
|
||||||
[ -n "$rel_path" ] || continue
|
|
||||||
|
|
||||||
case "$rel_path" in
|
|
||||||
conf/autoupdate.conf|conf/alert-engine.local.conf)
|
|
||||||
log_notice "delete_skipped" \
|
|
||||||
"Suppression ignorée pour fichier local protégé" \
|
|
||||||
"file=$rel_path"
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
rm -f "${MONITORING_BASE_DIR}/${rel_path}" \
|
|
||||||
&& log_notice "file_deleted" \
|
|
||||||
"Fichier supprimé car absent du manifeste" \
|
|
||||||
"file=$rel_path" \
|
|
||||||
|| log_error "delete_failed" \
|
|
||||||
"Impossible de supprimer fichier local" \
|
|
||||||
"file=$rel_path"
|
|
||||||
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
local total=0 updated=0 failed=0 hash mode path
|
|
||||||
|
|
||||||
fetch_manifest || exit 2
|
|
||||||
list_remote_files
|
|
||||||
list_local_files
|
|
||||||
|
|
||||||
while read -r hash mode path; do
|
|
||||||
[ -n "${hash:-}" ] || continue
|
|
||||||
total=$((total + 1))
|
|
||||||
|
|
||||||
if update_one_file "$hash" "$mode" "$path"; then
|
|
||||||
updated=$((updated + 1))
|
|
||||||
else
|
|
||||||
failed=$((failed + 1))
|
|
||||||
fi
|
|
||||||
done < "$TMP_MANIFEST"
|
|
||||||
|
|
||||||
delete_extra_local_files
|
|
||||||
|
|
||||||
if [ "$failed" -gt 0 ]; then
|
|
||||||
log_warning "update_finished_with_errors" \
|
|
||||||
"Mise à jour terminée avec erreurs" \
|
|
||||||
"total=$total" "updated_or_checked=$updated" "failed=$failed"
|
|
||||||
else
|
|
||||||
log_info "update_finished" \
|
|
||||||
"Mise à jour terminée" \
|
|
||||||
"total=$total" "updated_or_checked=$updated" "failed=0"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
||||||
exit_with_status
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Chemin du fichier uninstall-list
|
|
||||||
uninstall_list_file=$HOME/.config/a5l_scripts-bash_uninstall-list
|
|
||||||
|
|
||||||
# Vérifie si le fichier uninstall-list existe
|
|
||||||
if [ -e $uninstall_list_file ]; then
|
|
||||||
# Parcourt le fichier ligne par ligne
|
|
||||||
while IFS= read -r file; do
|
|
||||||
if [ -e "$file" ]; then
|
|
||||||
# Supprime le fichier
|
|
||||||
rm -v "$file"
|
|
||||||
fi
|
|
||||||
done < "$uninstall_list_file"
|
|
||||||
|
|
||||||
rm -v "$uninstall_list_file"
|
|
||||||
else
|
|
||||||
echo "Le fichier $uninstall_list_file n'existe pas."
|
|
||||||
fi
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user