Files
LinuxEmbarque/tp4.md
2024-11-21 15:20:46 +01:00

21 KiB
Raw Permalink Blame History

Travail pratique 4

Objectif

Au TP dernier on a configuré compilé et uploadé un kernel linux sur notre carte Sama5d3Xplained. Le but de ce tp est de mettre en place un rootfs très simple avec busybox et mettre en place un mini serveur web et en general avoir un linux qui puisse être utilisé.

Mise en place du serveur NFS

mkdir nfsroot à la racine du repertoire tp dans ma machine de developpement.

sudo chmod 777 nfsroot/ pour permettre à tout le monde d'y accèder et le modifier.

sudo apt install nfs-kernel-server

Pour configurer notre serveur nfs pour avoir comme root notre nouveau repertoire

sudo vim /etc/exports

Et on y ajoute la ligne

/home/moi/tp/nfsroot *(rw,sync,no_subtree_check)

Ensuite pour démarrer le serveur nfs c'est

sudo systemctl start nfs-kernel-server.service

Mais comme je suis sur MacOS c'est pas exactement la même chose mais très ressemblant.

Il y a deja un serveur NFS intègré et il suffit donc de le configurer.

sudo nfsd enable

sudo vim /etc/exports

/Users/rohmermaxime/nfsroot 127.0.0.1 -alldirs -mapall=nobody
/Users/rohmermaxime/nfsroot 192.168.144.100 -alldirs -mapall=nobody`

sudo nfsd checkexports pour verifier que notre fichier export est conforme

sudo nfsd restart

Et normalement ca devrait suffire "Inshallah" comme disent certains

On peut essayer depuis une VM linux de monter le fs pour voir si ca marche

sudo mount -t nfs 192.168.144.12:/Users/rohmermaxime/nfsroot ./test/

Et ca marche ! On peut le faire sur la board maintenant

[Q1] Donnez le contenu de la variable denvironnement U-Boot permettant à votre noyau linux de monter le rootfs depuis votre répertoire nfsroot.

root =/dev/nfs ip = targetip:::::targetif nfsroot = serverip : rootfs , v3 rw Ca c'est la commande que l'on peut voir dans notre cours de base

Il faut le mettre dans setenv bootargs comme ca notre kernel peut l'executer au démarrage.

On peut donc créér notre commande de la sorte

setenv bootargs root=/dev/nfs ip=192.168.144.100:::::eth0 nfsroot=192.168.144.12:/Users/rohmermaxime/nfsroot, v3 rw

bootargs est la variable qui contient les arguments qui sont ajoutés au démarrage du kernel. root est l'endroit ou est monté notre nouveau fs ip et eth0 sont les informations reseau de notre board tandis que nfsroot contient les infos du serveur nfs

V3 force d'utiliser le protocole nfs v3 ce qui est demandé dans le cours car une version plus récente pourrait ne pas fonctionner.

Avec cette commande on peut faire un saveenv et relancer le boot et on a toujours un kernel panic mais pas le même !

[Q2] : Pourquoi le noyau crash-t-il (lisez les messages du noyau) et comment résoudre ce problème ?

Le panic d'avant c'était :

---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,253) ]---

Et maintenant c'est

---[ end Kernel panic - not syncing: No working init found.  Try passing init= option to kernel. See Linux Documentation/admin-guide/init.rst for guidance. ]---

J'en déduis donc qu'il a réussi à monter le rootfs mais qu'il essaie de trouver un fichier init dedans pour lancer l'os. La comme ca je dirais qu'il faut ajouter un fichier init et on pourra continuer.

Système de fichiers racine avec Busybox

git clone https://github.com/mirror/busybox.git

git checkout 1_36_1 res : HEAD is now at 1a64f6a20 Bump version to 1.36.1

On a maintenant la bonne version de busybox sur notre machine de cross compilation

on va loader la configuration defconfig donc

make mrproper make defconfig

Ca va nous charger la configuration par défaut pour gagner du temps.

Ensuite on veut désactiver plusieurs options donc

make menuconfig

J'ai trouvé comment enlever les deux options History saving et enable compatibility for full blown desktops mais je n'ai pas trouvé "Support infiniband HW"

J'ai fait un search avec / sous "infiniband" mais aucun match et sous "HW" mais aucun résultat qui ressemble. J'éspère que ca ne posera pas de problème.

J'ai retiré le "hush" dans shells

J'ai tout viré dans

  • Print utilities
  • Mail utilities
  • Runit utilities

"Choose which shell is aliased to sh name" est bien set à ash

mais

"Choose which shell is aliased to bash name" pointait sur none alors je l'ai changé pour pointer sur ash aussi

dans Settings → Installation Options on peut mettre le chemin d'installation. J'ai mis le chemin vers le repertoire tftp qui me permettras de recuperer sur ma machine principale et pour l'envoyer sur la board. Un poil plus haut on voit une option Build static binary que on doit mettre à oui dans un premier temps.

ensuite make install -j

A la fin de la compilation on a ce message

--------------------------------------------------
You will probably need to make your busybox binary
setuid root to ensure all configured applets will
work properly.
--------------------------------------------------

Je le garde de côté au cas ou

Après avoir transfèré tous les fichiers dans le repertoire nfs on peut voir ce que ca donne :

ls -a
.	..	bin	linuxrc	sbin	usr

Ca commence à ressembler un petit peu à un système de fichiers linux.

Maintenant quand j'essaie de lancer la board il boot le kernel, je ne vois pas de kernel panic mais à la place j'ai ce message à l'infini

can't open /dev/tty2: No such file or directory
can't open /dev/tty3: No such file or directory
can't open /dev/tty4: No such file or directory
can't open /dev/tty3: No such file or directory
can't open /dev/tty4: No such file or directory
can't open /dev/tty4: No such file or directory
can't open /dev/tty2: No such file or directory
can't open /dev/tty3: No such file or directory
can't open /dev/tty2: No such file or directory
can't open /dev/tty4: No such file or directory
can't open /dev/tty3: No such file or directory

Et la led bleue de la board fait du morse avec deux pulsations puis pause le tout en boucle aussi

Et j'avoue je sais pas pourquoi. Je vois dans le cours que il peut y avoir un problème quand le repertoire /dev n'existe pas alors je vais le créer dans nfsroot et on va voir si ca change quelque chose.

ET C'EST BON !! Comment je suis refais c'est une folie ca marche enfin.

VFS: Mounted root (nfs filesystem) on device 0:14.
devtmpfs: mounted
Freeing unused kernel image (initmem) memory: 1024K
Run /sbin/init as init process
can't run '/etc/init.d/rcS': No such file or directory

Please press Enter to activate this console.
~ # ls
bin      dev      linuxrc  sbin     usr

On a enfin un Linux qui tourne sur notre board avec lequel on peut interragir avec un invite de commande dont on a l'habitude je suis trop content.

Configuration du système et démarrage

[Q3] : Donnez le contenu de votre fichier inittab et de chaque fichier se trouvant dans le répertoire /etc/init.d/ de votre rootfs.

Dans nfsroot mkdir etc cd etc vim inittab

::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh

mkdir init.d cd init.d vim rcS

#!/bin/sh
# Start all init scripts in /etc/init.d
# executing them in numeric order.

for i in /etc/init.d/S??*; do
    case "$i" in
        *.sh)
            # Source shell script for speed.
            . "$i"
            ;;
        *)
            # No .sh extension, so fork subprocess.
            "$i" start
            ;;
    esac
done

sudo chmod 777 rcS

C'est pas ouf de mettre autant d'autorisation mais je ne veux pas avoir le moindre problème donc je mets ca temporairement. Ca sera remis à des autorisations plus normales plus tard.

De ce que j'ai compris chaque service qui commence par S dans le repertoire init.d sera executé et c'est dans l'ordre alphabetique juste par ce que la recherche par nom qui commencent par S se fait dans cet ordre.

Par convention un service qui commence par 'K' sont desactivés

Je n'ai encore aucun service dans init.d je ne comprends pas vraiment la question car sur ma board ce repertoire n'existait même pas encore mais je peux essayer d'en ajouter un.

#!/bin/ash
echo "The best distrib ever"

le fichier ci dessus sera renommé S1.sh. En toute logique ca devrait être executé en premier.

On peut redémarrer notre kernel pour voir

Run /sbin/init as init process
Bad inittab entry at line 1
Bad inittab entry at line 2

Ca c'est par ce que il y avait des espaces dans le chemin du inittab. Après avoir règlé ca on a cette erreur

VFS: Mounted root (nfs filesystem) on device 0:14.
devtmpfs: mounted
Freeing unused kernel image (initmem) memory: 1024K
Run /sbin/init as init process
can't run '/etc/init.d/rcS': Permission denied

C'est bizarre par ce que j'avais mis les autorisations full sur rcS...

Je vais essayer avec la commande

chmod +x rcS

Mais non toujours impossible de run le rcS J'ai essayé en donnant les autorisations sur le repertoire au dessus etc... mais rien n'y fait

Après recherches il semble que ca soit ma config nfs qui soit à blâmer, voici la nouvelle (rappel je suis sur macos donc la config est pas la même que sur ubuntu)

/Users/rohmermaxime/nfsroot 127.0.0.1 -alldirs -maproot=0
/Users/rohmermaxime/nfsroot 192.168.144.100 -alldirs -maproot=0
/Users/rohmermaxime/nfsroot 192.168.64.7 -alldirs -maproot=0

J'ai changé le -mapall=nobody en -maproot=0

sudo nfsd restart

Mais toujours pas alors je vais tenter

-mapall=0

Mais toujours pas...

J'ai même essayé de chmod -R 777 tout nfsroot mais rien n'y fait.

Mais c'est bizarre par ce que je peux executer S1.sh depuis la board sans problème...

~ # sh /etc/init.d/S1.sh
The best distrib ever

Bon en fait c'est par ce que le fichier rcS avait un espace dans le /bin/sh... yes... mais maintenant que le script est corrigé voila le resultat :

VFS: Mounted root (nfs filesystem) on device 0:14.
devtmpfs: mounted
Freeing unused kernel image (initmem) memory: 1024K
Run /sbin/init as init process
The best distrib ever
~ #

On voit bien que notre fichier service a bien été executé au démarrage :)

[Q4] : Que se produit-il lorsque vous exécutez la commande ps ?

~ # ps
  PID USER       VSZ STAT COMMAND
ps: can't open '/proc': No such file or directory

mkdir proc mkdir sys

~ # ps
  PID USER       VSZ STAT COMMAND

En allant inspecter /sys et /proc on ne voit rien. Je ne sais pas si c'est normal mais en même temps on a pas lancé de processus donc j'imagine que oui.

J'ai changé le fichier inittab pour qu'il ressemble à ca :

::sysinit:/etc/init.d/rcS

# Mount proc and sysfs
::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -t sysfs sysfs /sys

::respawn:-/bin/sh

Grâce à ca on peut refaire la commande ps et voila le resultat :

~ # ps
  PID USER       VSZ STAT COMMAND
    1 0         1484 S    init
    2 0            0 SW   [kthreadd]
    3 0            0 SW   [pool_workqueue_]
    4 0            0 IW<  [kworker/R-slub_]
    5 0            0 IW   [kworker/0:0-eve]
    6 0            0 IW<  [kworker/0:0H]
    7 0            0 IW   [kworker/u2:0-xp]
    8 0            0 IW<  [kworker/R-mm_pe]
    9 0            0 SW   [ksoftirqd/0]
   10 0            0 SW   [kdevtmpfs]
   11 0            0 IW<  [kworker/R-inet_]
   12 0            0 IW   [kworker/u2:1-nf]
   13 0            0 SW   [oom_reaper]
   14 0            0 IW<  [kworker/R-write]
   15 0            0 SW   [kcompactd0]
   16 0            0 IW<  [kworker/R-kbloc]
   17 0            0 SW   [watchdogd]
   18 0            0 IW   [kworker/0:1-eve]
   19 0            0 IW<  [kworker/R-rpcio]
   20 0            0 IW<  [kworker/R-xprti]
   21 0            0 IW<  [kworker/R-cfg80]
   22 0            0 SW   [kswapd0]
   23 0            0 IW<  [kworker/R-nfsio]
   24 0            0 SW   [hwrng]
   25 0            0 SW   [spi0]
   26 0            0 SW   [spi1]
   29 0            0 SW   [irq/38-atmel_us]
   30 0            0 IW   [kworker/0:2-eve]
   31 0            0 IW   [kworker/u2:2-nf]
   32 0            0 IW   [kworker/u2:3-nf]
   33 0            0 IW   [kworker/0:3-pm]
   34 0            0 IW<  [kworker/R-mld]
   35 0            0 IW<  [kworker/R-ipv6_]
   39 0            0 IW   [kworker/u2:4-xp]
   40 0            0 IW   [kworker/u2:5-nf]
   41 0            0 IW   [kworker/u2:6]
   45 0         1492 S    -/bin/sh
   46 0         1492 R    ps

On peut y voir la liste des process en cours et on peut inspecter nos directory /proc et /sys

~ # cd proc
/proc # ls
1             26            8             interrupts    pagetypeinfo
10            29            9             iomem         partitions
11            3             asound        ioports       scsi
12            30            buddyinfo     irq           self
13            31            bus           kallsyms      slabinfo
14            32            cgroups       key-users     softirqs
15            33            cmdline       keys          stat
16            34            consoles      kmsg          sys
17            35            cpu           kpagecount    sysvipc
18            39            cpuinfo       kpageflags    thread-self
19            4             crypto        loadavg       timer_list
2             40            device-tree   locks         tty
20            41            devices       meminfo       uptime
21            45            diskstats     misc          version
22            48            driver        modules       vmallocinfo
23            5             execdomains   mounts        vmstat
24            6             filesystems   mtd           zoneinfo
25            7             fs            net
/proc # cd ..
~ # cd sys
/sys # ls
block     class     devices   fs        module
bus       dev       firmware  kernel    power

Le mount a donc bien réussi

Par contre le test un peu bizarre ou il faut faire un sleep de 10s et l'arrêter j'ai pas réussi à le faire fonctionner. Ctrl+C ca l'interromp mais pas Ctrl+Z. Et je ne vois juste absolument pas comment on est sensé debug ca du coup bah... dommage quoi je sais pas.

J'ai bien verifié et le message d'erreur can ' t access tty : job control turned off n'est pas présent donc... bref j'éspère que ca va pas me poser de problème plus tard "C'est tellement sur que si"

Utilisation de librairies partagées

On fait un petit programme c pas bien complexe :

#include <stdio.h>
#include <stdlib.h>

int main(){
	printf("Hello, world !\n");
}

On peut le compiler avec notre petit gcc maison fait pour linux.

arm-buildroot-linux-musleabi-gcc test.c -o test

Et ne pas oublier dans le repertoire partagé NFS

chmod +x test

Ensuite on peut le poser quelque part sur le rootfs de notre linux embarqué

J'ai créé un repertoire à la racine qui s'appelle "TP" dans lequel j'ai posé le programme que l'on vient de compiler

/tp # ./test
-/bin/sh: ./test: not found

Et avec la version statique

arm-buildroot-linux-musleabi-gcc test.c -o test_static -static

ce qui nous donne

/tp # ./test_static
Hello, world !
/tp #

[Q5] : Pourquoi est-ce que la première version du programme compilé ne sexécute pas correctement ?

Il n'arrivait pas à utiliser le permier script car les librairies n'existent juste pas sur notre système embarqué. Stdlib et Stdio n'existent pas et donc le programme c a envie de mourir et il ne peut pas tourner.

Quand on compile statiquement la on arrive à lancer le programme car stdlib et stdio sont built-in avec l'executable.

[Q6] : De quelles librairies dynamiques dépend donc votre petit programme ?

Normalement les deux librairies dont mon petit programme a besoin sont stdio.h et stdlib.h

arm-buildroot-linux-musleabi-gcc test.c -o test_static -static -print-sysroot
/home/moi/tp/toolchain/arm-buildroot-linux-musleabi/sysroot

dans sysroot sous lib on peut faire un ls -a

ls -l
total 6284
-rw-r--r-- 1 moi moi    1404 Aug 17 09:48 Scrt1.o
-rw-r--r-- 1 moi moi    1404 Aug 17 09:48 crt1.o
-rw-r--r-- 1 moi moi     824 Aug 17 09:48 crti.o
-rw-r--r-- 1 moi moi     788 Aug 17 09:48 crtn.o
lrwxrwxrwx 1 moi moi       7 Aug 17 09:49 ld-musl-arm.so.1 -> libc.so
-rw-r--r-- 1 moi moi   70798 Aug 17 09:53 libatomic.a
-rwxr-xr-x 1 moi moi    1059 Aug 17 09:53 libatomic.la
lrwxrwxrwx 1 moi moi      18 Aug 17 09:53 libatomic.so -> libatomic.so.1.2.0
lrwxrwxrwx 1 moi moi      18 Aug 17 09:53 libatomic.so.1 -> libatomic.so.1.2.0
-rwxr-xr-x 1 moi moi   57512 Aug 17 09:53 libatomic.so.1.2.0
-rw-r--r-- 1 moi moi 2494014 Aug 17 09:48 libc.a
-rwxr-xr-x 1 moi moi  939268 Aug 17 09:48 libc.so
-rw-r--r-- 1 moi moi       8 Aug 17 09:48 libcrypt.a
-rw-r--r-- 1 moi moi       8 Aug 17 09:48 libdl.a
-rw-r--r-- 1 moi moi     132 Aug 17 09:53 libgcc_s.so
-rw-r--r-- 1 moi moi 2800704 Aug 17 09:53 libgcc_s.so.1
-rw-r--r-- 1 moi moi       8 Aug 17 09:48 libm.a
-rw-r--r-- 1 moi moi       8 Aug 17 09:48 libpthread.a
-rw-r--r-- 1 moi moi       8 Aug 17 09:48 libresolv.a
-rw-r--r-- 1 moi moi       8 Aug 17 09:48 librt.a
-rw-r--r-- 1 moi moi       8 Aug 17 09:48 libutil.a
-rw-r--r-- 1 moi moi       8 Aug 17 09:48 libxnet.a
-rw-r--r-- 1 moi moi    2364 Aug 17 09:48 rcrt1.o

On peut voir une libc.a et libc.so

Après discussion avec mes collègues, on peut utiliser juste le .so car il est compilé dynamiquement mais ca devrait marcher quand même.

On va donc copier cette lib dans /lib de notre nfs (que on a créé à la racine)

[Q7] : Quelles librairies (fichiers) avez-vous ajoutées à votre système embarqué ? Où se trouvent ces fichiers sur votre système hôte et où les avez-vous copié sur votre système embarqué ?

La libc.so ET ld-musl-arm.so.1

Il faut aussi les passer en autorisations d'execution

Quand on a pu faire ca la même la version dynamique de test fonctionne !!

Déploiement dun mini serveur web embarqué

[Q8] : Créez et donnez le contenu du patch permettant de patcher larborescence dorigine afin dobtenir une nouvelle arborescence qui rempli le cachier des charges demandé (ajout nouveau script, modifications pages, config, etc.).

J'ai créé un repertoire www dans /var et j'ai copié le contenu du repertoire www dans ressources que l'on a de disponible dans le git du cours.

On peut voir ca depuis la machine

/var/www # ls
cgi-bin     gohome.png  index.html  upload
/var/www # httpd -h /var/www

Et la si on va sur 192.168.144.10 dans mon navigateur on a accès à notre site youpiiiii !

Ensuite je suis allé dans www/cgi-bin pour modifier les différents fichiers qui ont des chemins hard codés en www/... en /var/www/

il faut le faire dans le fichier upload.cfg et dans index.html également pour que les liens soient corrects

Maintenant quand on essaie d'upload on a plus une erreur 404 mais une erreur 501 Not implemented. Il faut donc encore trouver le bon endroit ou mettre le fichier binaire upload que on a compilé.

Ensuite pour faire une nouvelle page on peut aller regarder comment est fait une page classique pour les cpu par exemple

#!/bin/sh

UPLOAD_DIR="/www/upload/files"
URL_PATH="/upload/files"

echo "Content-type: text/html"
echo
echo "<html>"
echo "<body>"
echo "<h1>CPU information</h1>"
echo "The embedded system is based on the following CPU:<pre>"
cat /proc/cpuinfo
echo "</pre>"
echo "<p><a href=\"/\"><img src=\"/gohome.png\" border=\"0\"></a></p>"
echo "</body></html>"

On peut voir que la seule partie vraiment script c'est le 'cat /proc/cpuinfo' et que donc si on veut faire une page qui permette de lancer notre script on peut tout copier et changer ici.

#!/bin/sh

echo "Content-type: text/html"
echo
echo "<html>"
echo "<body>"
echo "<h1>System usage and processes</h1>"
echo "Informations about processes and sys usage :<pre>"
top -n1 -b
echo "</pre>"
echo "<p><a href=\"/\"><img src=\"/gohome.png\" border=\"0\"></a></p>"
echo "</body></html>"

Pour plus d'infos à propos de la commande top on peut utiliser

top -n1 -b

Qui nous donne ce resultat

Mem: 11484K used, 235516K free, 0K shrd, 0K buff, 1352K cached
CPU:  0.0% usr  9.0% sys  0.0% nic 90.9% idle  0.0% io  0.0% irq  0.0% sirq
Load average: 0.01 0.00 0.00 1/35 110
  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
  109    46 0        R     1496  0.6   0  5.4 top -n1 -b
    7     2 0        IW       0  0.0   0  1.8 [kworker/u2:0-nf]
   39     2 0        IW       0  0.0   0  1.8 [kworker/u2:4-xp]
   46     1 0        S     1492  0.6   0  0.0 -/bin/sh
    1     0 0        S     1484  0.6   0  0.0 init
    ....

On doit évidemment ajouter les entrées dans la page index.html pour avoir un lien qui pointe vers notre nouveau fichier

<html>
    <head>
    <title>Tiny Web Server</title>
    </head>
    <body>
        <h1>Tiny Web Server</h1>
        <h3>Available pages</h1>
        <ul>
            <li><a href="/cgi-bin/uptime.sh">Uptime</a></li>
            <li><a href="/cgi-bin/kernel.sh">Kernel info</a></li>
            <li><a href="/cgi-bin/cpu.sh">CPU info</a></li>
            <li><a href="/cgi-bin/list_files.sh">Uploaded files</a></li>
	          <li><a href="/cgi-bin/top.sh">Processes</a></li>
        </ul>
        <h3>Upload a file</h3>
        <form action="/var/www/cgi-bin/upload" enctype="multipart/form-data" method=post>
            <input type=file name="File">
            <input type=submit value="Upload">
        </form>
    </body>
</html>

Et voila on a une nouvelle page qui nous annonce des trucs super !

[Q9] : Quel nouveau script avez-vous ajouté et quel est son contenu ?

Pour que le service web se lance directement au démarrage, j'ai ajouté un scrip nommé StartHttp.sh dans /etc/init.d

#!/bin/sh

httpd -h /var/www

Très simple mais ca fait le boulot car au redémarrage de la board, le site web est accessible.

Note: Il faut que le script commence avec un 'S' sinon il n'est pas pris en compte par notre inittab