Utilisez /boot/cmdline.txt pour créer un script de premier démarrage


11

De nombreuses questions ont été posées sur la façon de trouver mon Pi sur mon réseau . D'autres - y compris moi-même - ont des problèmes qui prennent du temps tout en essayant de déployer un lot de nouveaux Pi.

Bien que la création d'images personnalisées puisse être une solution à ces problèmes, je me demande s'il existe d'autres solutions.

Avec (uniquement) le /bootrépertoire ouvert pour l'accès sur les machines normales (Win / OSX), serait-il possible d'utiliser /boot/cmdline.txtpour diriger du texte vers un script bash, l'exécuter et le supprimer ensuite?


1
Cette question est en cours de discussion sur Meta . J'aimerais entendre votre opinion, si possible. Merci.
Thomas Weller

Réponses:


6

J'ai créé une version légèrement modifiée de Raspberian-light qui répond à ce besoin - il exécute votre script /boot/firstboot.sh personnalisé au premier démarrage:

https://github.com/nmcclain/raspberian-firstboot


Merci! 4 ans après OP il y a enfin une bonne solution. Pas particulièrement sorcier pour le construire vous-même, mais vous êtes là pendant de nombreuses heures chaque fois qu'il y a une nouvelle version. À mon humble avis, cela devrait être ajouté au firmware principal.
EDP

3

Pour ceux qui préfèrent une solution impliquant uniquement des scripts déposés dans la partition de démarrage FAT32 , voici comment procéder. [ Modifier: Les fichiers sont maintenant disponibles dans un projet pi-boot-script .]

Comme mentionné dans d'autres réponses, il implique les arguments de ligne de commande avec lesquels le noyau Linux est démarré. Ces arguments se trouvent dans /boot/cmdline.txt .

J'ai testé cela sur Raspbian Buster (v10.1) 2019-09-26. Il fonctionne sur une carte SD nouvellement flashée ou sur l' image disque .img téléchargée , que vous pouvez ensuite flasher sur n'importe quel nombre de cartes SD.

1. Modifiez les arguments du noyau

Ouvrez le fichier texte /boot/cmdline.txt , supprimez-en une init=partie et ajoutez-le à la fin de la ligne:

init=/bin/bash -c "mount -t proc proc /proc; mount -t sysfs sys /sys; mount /boot; source /boot/unattended"

Le dernier mot de cette ligne est le nom d'un script à exécuter par le noyau comme premier processus (PID = 1) au lieu de / sbin / init . La page d'aide kernel-arguments indique uniquement les arguments sans .être passés à l'exécutable init, vous ne pouvez donc pas appeler le script unattended.sh ou des choses de ce genre.

2. Mettez le script sur la partition de démarrage

Enregistrez les éléments suivants dans la partition de démarrage sous / sans assistance (le nom que vous avez mis dans la ligne de commande):

# 1. MAKING THE SYSTEM WORK. DO NOT REMOVE
mount -t tmpfs tmp /run
mkdir -p /run/systemd
mount / -o remount,rw
sed -i 's| init=.*||' /boot/cmdline.txt

# 2. THE USEFUL PART OF THE SCRIPT
# Example:
[[ -d /boot/payload/home/pi ]] && sudo -u pi cp --preserve=timestamps -r\
 /boot/payload/home/pi /home/ && rm -rf /boot/payload/home/pi              # A
[[ -d /boot/payload ]] && cp --preserve=timestamps -r /boot/payload/* /\
 && rm -rf /boot/payload                                                   # B
ln -s /lib/systemd/system/one-time-script.service\
 /etc/systemd/system/multi-user.target.wants/                              # C

# 3. CLEANING UP AND REBOOTING
sync
umount /boot
mount / -o remount,ro
sync
echo 1 > /proc/sys/kernel/sysrq
echo b > /proc/sysrq-trigger
sleep 5

Ce script fait une préparation nécessaire (chapitre 1), puis tout ce que vous voulez faire (2) et ensuite nettoyer et redémarrer (3). Remplacez le truc sous 2 par les commandes que vous souhaitez exécuter.

Pour certaines tâches de configuration, vous avez probablement besoin d'un démarrage normal pour faire apparaître la mise en réseau et d'autres services, de sorte que l'exemple de cette version (expliqué ci-dessous) ne prépare qu'un bon script à exécuter lorsque le Pi redémarre.

3. Mettez tous les autres fichiers dont votre script a besoin sur la partition de démarrage

...évidemment.

Exemple

Avec mon script, j'ai mis un dossier payload / sur la partition de démarrage, qui contient les fichiers que je veux déplacer vers la partition Linux. Dans le script sans surveillance ci-dessus,

  • la ligne A déplace les fichiers dans le répertoire de l'utilisateur pi. Par exemple, la charge utile / home / pi / .bashrc est déplacée dans le système de fichiers racine en tant que /home/pi/.bashrc ;
  • la ligne B déplace les fichiers appartenant à root dans la partition Linux, y compris payload / usr / local / bin / one-time-script.sh qui devient /usr/local/bin/one-time-script.sh , et similaire pour payload / lib / systemd / system / one-time-script.service ;
  • la ligne C crée alors un lien symbolique vers ce dernier fichier, donc mon script de configuration one-time-script.sh est exécuté au prochain démarrage.

Ce script fait diverses personnalisations que j'aime: il crée et formate une autre partition FAT32 et l'ajoute à / etc / fstab pour que l'utilisateur pi puisse y écrire (pour les journaux d'application, etc.); redimensionne la partition ext4 et le système de fichiers pour le reste de la carte SD; modifie les paramètres régionaux, le fuseau horaire, le nom d'hôte (basé sur le numéro de série du processeur), le pays WiFi; définit le réseau WiFi et la phrase secrète; active SSH; résout un problème de paramètres de langue pour les sessions SSH; configure le démarrage dans une console sans connexion automatique; écrit certaines données sur le système dans un fichier sur la partition de démarrage; et bien sûr, il supprime ce lien symbolique pour qu'il ne s'exécute plus au démarrage.

La plupart des utilisateurs trouveront cela inutile et préfèrent utiliser PiBakery , pi-init2 ou une image ext4 personnalisée, qui sont d'excellentes solutions. Je préfère cela car je peux le comprendre et je n'ai pas besoin d'exécuter d'autres logiciels. Et cela fonctionne aussi: avec le fichier .img dans lequel j'ai mis mes scripts, flasher une carte SD + la mettre dans un Pi + la laisser s'exécuter pour se configurer prend 6 minutes.

Source J'ai trouvé l'idée d'un script comme init=argument du noyau, et les mountcommandes nécessaires pour le faire fonctionner, dans le script init_resize.sh qui s'exécute par défaut pour redimensionner la partition Linux.


2

Vous POUVEZ faire exécuter du code en jouant avec la ligne de commande du noyau. La méthode la plus évidente consiste à remplacer init par autre chose. L'application la plus courante consiste à lancer un shell très tôt dans le processus de démarrage, généralement parce que vous devez réparer quelque chose ou parce que tout le reste est très mal cassé, par exemple:

init=/bin/bash

Gardez à l'esprit qu'à ce stade du processus de démarrage, les systèmes de fichiers sont toujours montés en lecture seule. De plus, il y a tout un tas de choses qui ne fonctionnent pas correctement. Parce que vous n'avez pas de véritable init en cours d'exécution, l'arrêt et le redémarrage ne fonctionneront pas. Vous devez remonter manuellement le système de fichiers racine en lecture seule et appeler reboot -fpour redémarrer, par exemple.

Je n'ai aucune idée si vous pouvez passer des arguments à bash de cette manière. Je n'ai jamais essayé. En théorie, si vous pouvez passer -cà bash, vous pouvez dire à ce processus bash de faire quoi que ce soit. Mais cela pourrait se transformer en un argument assez long, et je ne sais pas si le noyau permettrait de telles choses.

Deuxième chose que vous pouvez faire. Vous pouvez copier un ramfs initial (initramfs) dans le système de fichiers et configurer le chargeur de démarrage pour l'utiliser dans config.txt. Il y a plusieurs façons d'obtenir des scripts dans un initramfs pour faire des choses spéciales. Vous devrez cependant préparer un initramfs spécial à cet effet (voir initramfs-tools (8)), donc je ne suis pas sûr que ce soit une meilleure solution qu'une image personnalisée.

Vous pouvez inclure le script dans / boot (j'ai ri de votre suggestion à propos des machines "normales", mais ce serait le bit auquel vous pouvez accéder à partir de ces machines) et essayez de le lancer en utilisant la ligne d'initialisation du noyau, mais les fichiers sur les systèmes de fichiers dos ne sont pas n'est pas exécutable, sauf si vous le faites pour l'ensemble du système de fichiers.

Si c'était moi, je ferais une image personnalisée qui utilise DHCP pour configurer le réseau et qui contient un script personnalisé qui s'exécute au démarrage. Ce script recherche un fichier spécifique qui agit comme indicateur. Si le fichier existe, ne faites rien. Sinon, configurez les choses, puis créez le fichier indicateur.

Votre script de configuration pourrait même tirer la vraie chose d'un serveur http. Cela signifie que vous n'avez pas à créer une nouvelle image si vous devez modifier quelque chose.

Cela devrait être la solution la moins stressante.

Une dernière possibilité, mais vous devrez le faire sur une machine "non régulière" :-) Vous pouvez monter le système de fichiers ext4 sur un périphérique en boucle et y copier des fichiers sans l'écrire d'abord sur sdcard. Pour une image Raspbian Jessie standard, ce serait quelque chose comme ceci:

sudo losetup /dev/loop0 /tmp/gw.img -o 62914560
sudo mount /dev/loop0 /mnt
sudo cp /my/superduper/script.sh /mnt
sudo umount /dev/loop0
sudo fsck -f /dev/loop0 # This is optional
sudo losetup -d /dev/loop0

J'aime faire un fsck forcé sur mes systèmes de fichiers avant de faire des images. Définit le nombre de montages à zéro au premier démarrage :-)

EDIT : Après plusieurs mois et plus d'expérience. Vous voulez regarder u-boot. Remplacez le chargeur de démarrage par u-boot. Cela peut être fait à partir d'une "machine ordinaire". Une fois que vous avez u-boot en place, vous pouvez soit démarrer en réseau une distribution à partir de laquelle vous pouvez facilement flasher la carte sd, soit théoriquement flasher la carte directement, bien que je ne sache pas à quel point ce serait difficile.

Essentiellement, u-boot apporte un démarrage réseau au Raspberry Pi, quelque chose qu'il ne prend pas en charge seul.


Ok, le système de fichiers est en lecture seule à ce stade. Et alors init=script & init? Le script s'exécuterait en arrière-plan pendant que init démarre normalement. Le script aurait besoin d'une vérification de condition au début et par exemple continuer lorsque init a terminé son travail.
Thomas Weller

1
Utiliser & pour fonder quelque chose est une chose shell. Sauf si vous dites au noyau d'exécuter une commande spécifique dans un shell (par exemple: bash -c "une commande et une autre commande") qui ne fonctionnera pas, et je pense déjà que c'est une mauvaise idée. Mais j'ai étendu ma réponse et ajouté l'option u-boot, quelque chose que j'ai découvert récemment.
izak

1
Je viens d'essayer ;-) Non, ça ne marche vraiment pas
Thomas Weller

1

Je ne recommanderais pas de toucher quoi que ce soit dans la zone de démarrage (autre que config.txt), sauf si vous avez une compréhension détaillée de ce que font ces choses. cmdline.txtn'est pas conçu pour exécuter les choses lorsque le RPi démarre. Il est utilisé pour passer des paramètres au noyau Linux au démarrage.

Je suggère de le faire tout au long de SSH. Un script sur votre bureau pourrait pousser un programme bash / python / java / c / quel que soit vers le RPi, l'exécuter, puis le supprimer une fois terminé. Ajoutez du filetage au script sur votre bureau et vous pouvez l'envoyer à autant d'appareils que vous le souhaitez en même temps.


1
C'est ainsi que nous procédons actuellement, mais je cherche une solution plus simple.
EDP

1
Lire: exécutez la configuration initiée par le client plutôt que par le serveur
EDP

@EDP: il n'y a aucun moyen d'obtenir ce que vous voulez simplement en modifiant la position de démarrage. Vous pouvez écrire un script qui extrait le fichier d'un serveur au premier démarrage du RPi, puis demander à ce programme de supprimer le script de démarrage. Cela vous obligerait à utiliser une image personnalisée.
Jacobm001

1
"Un script sur votre bureau" - Quel script sur mon bureau? Au premier démarrage, il n'y a pas de script sur le bureau. "Faire tout cela via SSH" - au premier démarrage, le Pi peut ne pas avoir les bons paramètres Ethernet ou WLAN.
Thomas Weller

Vous n'avez même pas besoin d'enfiler le projet de tissu. IIRC son seul renouvellement est SSH
Steve Robillard

1

Sans doute, si vous êtes d'accord avec la modification de l'image pour exécuter automatiquement un script au premier démarrage, vous pouvez simplement modifier l'image comme le ferait votre script, puis enregistrer cette carte SD dans un fichier image et l'utiliser pour flasher Cartes SD que vous allez utiliser avec de nouveaux RPis. Par exemple, si vous voulez que tous vos RPis aient une certaine entrée /etc/fstab, vous pouvez simplement vous modifier /etc/fstabau lieu d'écrire un script qui effectue la modification.

Si vous avez absolument besoin d'actions scriptées (par exemple, si chaque image doit être modifiée d'une manière différente), vous pouvez déplacer votre /etc/rc.localvers /etc/rc.baket mettre un script dans /etc/rc.locallequel se remplace /etc/rc.bakdans la dernière commande. Ce script peut effectuer lui-même les premières actions de démarrage, ou il peut appeler un script particulier à partir de la /bootpartition si vous préférez.

Il est possible d'effectuer une exécution automatique en touchant uniquement la /bootpartition, en fournissant une image ramdisk de démarrage spéciale au noyau comme décrit ici . Cette image contiendrait les scripts pour modifier la partition racine, puis s'auto-supprimer config.txt. Je ne sais pas si cela en vaut la peine.


-2

Vous voudrez peut-être regarder mon projet Nard qui a une solution à votre problème:

1) Chaque carte SD peut se voir attribuer un ID unique avec un PC Windows ordinaire comme décrit ici:
http://www.arbetsmyra.dyndns.org/nard/#devsettingsid

2) Allumez tous vos Pis

3) Si possible, désactivez le pare-feu du PC

4) Ouvrez une fenêtre d'invite DOS et envoyez une requête ping à l'adresse de diffusion du sous-réseau

5) Répertoriez la table ARP avec la commande Windows "arp -a". Dans la liste, vous trouverez les adresses MAC et IP de tous les Raspberry Pi à proximité.

6) Connectez-vous à chaque appareil avec telnet (généralement également disponible sous Windows). La phrase de bienvenue affichera l'ID attribué à l'étape 1.


Peut-être que ma description initiale n'était pas assez claire. Je ne recherche pas particulièrement un moyen d'identifier les Pi. Je l'ai déjà couvert. Ce que je recherche, c'est d'exécuter une ou plusieurs commandes bash en modifiant le fichier /boot/cmdline.txt. Tout cela sans avoir besoin de se connecter via ssh - même une fois.
EDP

Vous ne pourrez probablement pas «cingler l'adresse de diffusion du sous-réseau», les attaques Smurf sont généralement empêchées.
CrackerJack9
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.