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
|
||||
|
||||
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.
|
||||
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.
|
||||
## Installation
|
||||
|
||||
## 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.
|
||||
`git clone https://git.abonnel.fr/cedricAbonnel/scripts-bash.git`
|
||||
## Scripts
|
||||
|
||||
2. Exécutez le script en utilisant la commande `./install.sh`.
|
||||
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.
|
||||
### Documentés
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
Ce travail est sous licence [Creative Commons Attribution-ShareAlike 4.0 International License][cc-by-sa] par Cédrix.
|
||||
## Pour les développeurs
|
||||
|
||||
Voir [DEVELOPER.md](DEVELOPER.md).
|
||||
|
||||
[cc-by-sa]: http://creativecommons.org/licenses/by-sa/4.0/
|
||||
[cc-by-sa-image]: https://licensebuttons.net/l/by-sa/4.0/88x31.png
|
||||
## Licence
|
||||
|
||||
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
|
||||
|
||||
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 "==> Préparation de l'environnement...\n"|tee $logFile
|
||||
@@ -57,7 +58,7 @@ source_dir=$(pwd)
|
||||
input_file_type=${param1}
|
||||
output_file_type="new${param2}.mkv"
|
||||
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
|
||||
@@ -246,7 +247,7 @@ echo -e "==> Traitement des vidéos en cours...\n"|tee -a $logFile
|
||||
echo "touch \"${out_file}.processed\"">> ${listFileName}
|
||||
|
||||
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 -e "\n ==> Finished \"$out_file\""|tee -a $logFile
|
||||
|
||||
@@ -25,7 +25,9 @@ function message {
|
||||
|
||||
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
|
||||
idLog=$$-${uuidgen}
|
||||
|
||||
|
||||
@@ -51,16 +51,16 @@ done
|
||||
|
||||
|
||||
# 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
|
||||
mkdir -p ${CONFIG_DIR}
|
||||
fi
|
||||
|
||||
|
||||
# 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
|
||||
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
|
||||
if [[ -v XDG_MUSIC_DIR ]]; then
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
## 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}"
|
||||
|
||||
### edit directory path music background
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
trap 'exit 130' INT
|
||||
|
||||
## 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}
|
||||
|
||||
### edit directory path music background
|
||||
|
||||
+39
-29
@@ -1,50 +1,60 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 1. Liste des 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)
|
||||
mapfile -t ALL_HOSTS < <(
|
||||
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() {
|
||||
local host=$1
|
||||
local info=$(ssh -G "$host")
|
||||
local addr=$(echo "$info" | awk '/^hostname / {print $2}')
|
||||
local port=$(echo "$info" | awk '/^port / {print $2}')
|
||||
local info addr port user
|
||||
info=$(ssh -G "$host" 2>/dev/null)
|
||||
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
|
||||
# On utilise "|" comme délimiteur interne
|
||||
printf "[ ON ]|%s\n" "$host"
|
||||
printf "\033[32m[ ON ]\033[0m|ON|%-22s|%s@%s\n" "$host" "$user" "$addr"
|
||||
else
|
||||
printf "[ OFF ]|%s\n" "$host"
|
||||
printf "\033[31m[ OFF ]\033[0m|OFF|%-22s|%s@%s\n" "$host" "$user" "$addr"
|
||||
fi
|
||||
}
|
||||
|
||||
export -f check_host
|
||||
echo "Vérification des serveurs..."
|
||||
|
||||
# 2. Scan parallèle
|
||||
STATE_LIST=$(printf "%s\n" "${ALL_HOSTS[@]}" | xargs -I {} -P 10 bash -c 'check_host "{}"')
|
||||
printf "Vérification de %d serveurs...\n" "$TOTAL"
|
||||
|
||||
# 3. Interface FZF
|
||||
# On demande à fzf d'afficher les colonnes proprement
|
||||
choice=$(echo "$STATE_LIST" | fzf --height 40% --reverse \
|
||||
--delimiter="\|" \
|
||||
--with-nth=1,2 \
|
||||
--header "Tapez 'OFF' pour les serveurs HS | 'ON' pour les actifs")
|
||||
# Scan parallèle — ON affiché en premier, puis tri alphabétique
|
||||
STATE_LIST=$(
|
||||
printf "%s\n" "${ALL_HOSTS[@]}" \
|
||||
| xargs -I {} -P 20 bash -c 'check_host "{}"' \
|
||||
| sort -t'|' -k2,2r -k3,3
|
||||
)
|
||||
|
||||
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
|
||||
# On extrait le nom de l'hôte en utilisant le délimiteur "|"
|
||||
host_to_connect=$(echo "$choice" | cut -d'|' -f2)
|
||||
|
||||
# Nettoyage radical des caractères invisibles ou espaces restants
|
||||
host_to_connect=$(echo "$host_to_connect" | tr -d '[:space:]')
|
||||
status=$(echo "$choice" | cut -d'|' -f2)
|
||||
host_to_connect=$(echo "$choice" | cut -d'|' -f3 | tr -d '[:space:]')
|
||||
|
||||
if [[ "$choice" == *"[ ON ]"* ]]; then
|
||||
if [[ "$status" == "ON" ]]; then
|
||||
clear
|
||||
ssh "$host_to_connect"
|
||||
exec ssh "$host_to_connect"
|
||||
else
|
||||
echo -e "\033[0;31m⚠️ Le serveur $host_to_connect semble OFFLINE.\033[0m"
|
||||
read -p "Tenter quand même la connexion ? (y/n) " confirm
|
||||
[[ $confirm == [yY] ]] && ssh "$host_to_connect"
|
||||
printf "\033[0;31m⚠ Le serveur '%s' semble OFFLINE.\033[0m\n" "$host_to_connect"
|
||||
read -rp "Tenter quand même la connexion ? (y/n) : " confirm
|
||||
[[ $confirm == [yY] ]] && exec ssh "$host_to_connect"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/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
|
||||
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.
|
||||
|
||||
# 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
|
||||
SSH_OPTS="-o ConnectTimeout=5 -o BatchMode=yes -o StrictHostKeyChecking=accept-new"
|
||||
SSH_TIMEOUT="5"
|
||||
@@ -141,8 +147,7 @@ EOF
|
||||
now=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
# Fichier de stats
|
||||
stats_file="$HOME/.config/updateall-stats"
|
||||
mkdir -p "$(dirname "$stats_file")"
|
||||
stats_file="$UPDATEALL_STATS"
|
||||
|
||||
# Ajouter l’en-tête si le fichier est vide
|
||||
if [ ! -s "$stats_file" ]; then
|
||||
@@ -259,9 +264,9 @@ confirm_update() {
|
||||
local machine="$1"
|
||||
read -p " - Executer la mise à jour pour $machine ? (o/n) " choice
|
||||
if [ "$choice" = "o" ]; then
|
||||
echo "$machine 1" >> ~/.config/updateall-hosts
|
||||
echo "$machine 1" >> "$UPDATEALL_HOSTS"
|
||||
else
|
||||
echo "$machine 0" >> ~/.config/updateall-hosts
|
||||
echo "$machine 0" >> "$UPDATEALL_HOSTS"
|
||||
continue
|
||||
fi
|
||||
}
|
||||
@@ -285,7 +290,7 @@ check_host() {
|
||||
|
||||
run_custom_script() {
|
||||
local machine="$1"
|
||||
local custom_script="$HOME/.config/updateall.d/$machine"
|
||||
local custom_script="$UPDATEALL_CUSTOM_DIR/$machine"
|
||||
|
||||
if [ -f "$custom_script" ]; then
|
||||
echo -e " - Exécution du script spécifique pour ${GREEN}$machine${NC}"
|
||||
@@ -328,7 +333,7 @@ current=0
|
||||
|
||||
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"
|
||||
((current++))
|
||||
@@ -364,7 +369,7 @@ for machine in "${machines[@]}"; do
|
||||
matched=1
|
||||
break
|
||||
fi
|
||||
done < ~/.config/updateall-hosts
|
||||
done < "$UPDATEALL_HOSTS"
|
||||
|
||||
if [ "$matched" != "1" ]; then
|
||||
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
|
||||
<?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
|
||||
* License: GNU Affero General Public License v3
|
||||
*/
|
||||
|
||||
// --- Initialisation & Sécurité ---
|
||||
|
||||
if (posix_getuid() !== 0) {
|
||||
fwrite(STDERR, "Ce script doit être exécuté en root.\n");
|
||||
exit(1);
|
||||
@@ -16,89 +14,76 @@ if (posix_getuid() !== 0) {
|
||||
const CONF_DIR = '/opt/monitoring/conf';
|
||||
|
||||
/**
|
||||
* Extrait les clés d'un fichier de configuration PHP (tableau return [])
|
||||
* sans exécuter le fichier pour éviter les effets de bord, via Regex.
|
||||
* Logique d'affichage
|
||||
*/
|
||||
function extract_keys($file) {
|
||||
$content = file_get_contents($file);
|
||||
// On cherche les patterns : 'KEY' => ou "KEY" =>
|
||||
preg_match_all('/[\'"]([A-Z0-9_]+)[\'"]\s*=>/i', $content, $matches);
|
||||
$keys = $matches[1] ?? [];
|
||||
sort($keys);
|
||||
return array_unique($keys);
|
||||
function log_clean($level, $msg) {
|
||||
$color = ['info' => '34', 'notice' => '32', 'warn' => '33', 'err' => '31'][$level] ?? '37';
|
||||
echo sprintf("\e[%sm[%s]\e[0m %s\n", $color, strtoupper($level), $msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logique de logging
|
||||
* Nettoie un fichier local en comparant ses valeurs avec la base
|
||||
*/
|
||||
function log_audit($level, $event, $msg) {
|
||||
echo sprintf("[%s] %s: %s\n", strtoupper($level), $event, $msg);
|
||||
}
|
||||
function clean_local_config($base_file, $local_file) {
|
||||
// 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() {
|
||||
$found_issue = false;
|
||||
$reviewed_files = 0;
|
||||
$files_requiring_action = 0;
|
||||
if (!is_array($base_cfg) || !is_array($local_cfg)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
log_audit('info', 'audit_start', "Début de l'audit des configurations PHP");
|
||||
$new_local_cfg = $local_cfg;
|
||||
$removed_keys = [];
|
||||
|
||||
// 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
|
||||
$keys_base = extract_keys($base_conf);
|
||||
$keys_local = extract_keys($local_conf);
|
||||
|
||||
$missing = array_diff($keys_base, $keys_local); // Présent dans base mais pas local
|
||||
$obsolete = array_diff($keys_local, $keys_base); // Présent dans local mais plus dans base
|
||||
|
||||
if (!empty($missing) || !empty($obsolete)) {
|
||||
$found_issue = true;
|
||||
$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");
|
||||
foreach ($local_cfg as $key => $value) {
|
||||
// Si la clé existe en base ET que la valeur est strictement identique
|
||||
if (array_key_exists($key, $base_cfg) && $base_cfg[$key] === $value) {
|
||||
unset($new_local_cfg[$key]);
|
||||
$removed_keys[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
// Résumé final
|
||||
if (!$found_issue) {
|
||||
log_audit('info', 'audit_success', "Toutes les configurations sont à jour ($reviewed_files fichiers vérifiés)");
|
||||
} else {
|
||||
log_audit('warning', 'audit_requires_action', "Action requise sur $files_requiring_action fichier(s) sur $reviewed_files");
|
||||
if (empty($removed_keys)) {
|
||||
log_clean('info', basename($local_file) . " est déjà optimisé.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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 ---
|
||||
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