Unix et, par extension, Linux, ont pour mantra de faire ressembler tout ce qui est possible à un fichier. Les fichiers, bien sûr, ressemblent à des fichiers. Mais aussi les périphériques, les sockets réseau et même les informations système apparaissent comme des éléments qui semblent être des fichiers. Il y a beaucoup d’avantages à faire cela puisque vous pouvez utiliser tous les bons outils comme grep
et find
pour travailler avec des fichiers. Cependant, faire en sorte que vos propres programmes exposent un système de fichiers peut être difficile. Le code du système de fichiers fonctionne traditionnellement au niveau du module du noyau, où les erreurs peuvent effacer beaucoup de choses et le débogage est difficile. Cependant, il existe FUSE – le système de fichiers dans la bibliothèque de l’espace utilisateur – qui vous permet d’écrire du code plus ou moins ordinaire et d’exposer tout ce que vous voulez en tant que système de fichiers. Vous avez probablement vu FUSE utilisé pour monter, par exemple, des lecteurs distants via ssh ou Dropbox. Nous avons même déjà examiné FUSE, même pour Windows.
Ce qui manque, naturellement, c’est le flux RSS Hackaday, montable comme un fichier normal. Et c’est ce que nous construisons aujourd’hui.
L’écriture d’un système de fichiers FUSE n’est pas si difficile, mais il y a beaucoup de tâches fastidieuses. Vous devez essentiellement fournir des rappels que FUSE utilise pour faire des choses lorsque le système d’exploitation les demande. Ouvrir un fichier, lire un fichier, lister un répertoire, etc. Le problème est que pour certains projets simples, vous ne vous souciez pas de la moitié de ces choses, mais vous devez quand même les fournir.
Heureusement, il existe des bibliothèques qui peuvent le rendre beaucoup plus facile. Je vais vous montrer un programme C++ simple qui peut monter votre flux RSS préféré (en supposant que votre favori soit Hackaday, bien sûr) en tant que système de fichiers. Certes, ce n’est pas étonnant, mais c’est plutôt sympa de pouvoir parcourir les histoires de la première page à partir de la ligne de commande ou de voir les derniers articles en utilisant Dolphin.
Choisissez une bibliothèque
Il existe de nombreuses bibliothèques et wrappers autour de FUSE. j’en ai choisi un par [jachappell] sur GitHub. C’était assez simple et cache juste assez de FUSE pour être pratique, mais pas au point d’être un problème. Tout le code est caché dans Fuse.h
.
Une chose à noter est que la bibliothèque suppose que vous utilisez libfuse
3.0. Si vous ne l’avez pas déjà, vous devrez installer le libfuse
package de développement 3.0 de votre gestionnaire de packages. Il existe d’autres choix de bibliothèques, bien sûr, et vous pouvez simplement écrire dans le sous-jacent libfuse
mise en œuvre, mais une bonne bibliothèque peut rendre le démarrage beaucoup plus simple.
Juste pour garder les choses simples, j’ai bifurqué le projet original sur GitHub et ajouté un répertoire fusehad.
Contraintes
Pour garder les choses simples, j’ai décidé de ne pas trop me soucier des performances. Étant donné que les données voyagent sur le réseau, j’essaie de les mettre en cache et je n’actualise pas les données plus tard. Bien sûr, vous ne pouvez pas du tout écrire sur le système de fichiers. C’est uniquement pour lire Hackaday.
Ces contraintes facilitent les choses. Bien sûr, si vous écriviez votre propre système de fichiers, vous pourriez en assouplir certains, mais cela aide toujours à faire fonctionner quelque chose d’aussi simple que possible en premier.
Le faire fonctionner d’abord
En parlant de cela, la première chose à faire est de pouvoir lire le flux RSS de Hackaday et d’extraire les pièces dont nous avons besoin. Encore une fois, sans me soucier des performances, j’ai décidé de le faire avec une pipe et d’appeler à curl
. Oui, c’est de la triche, mais ça marche très bien, et c’est pourquoi nous avons des outils en premier lieu.
le HaDFS.cpp
Le fichier a quelques fonctions liées à FUSE et certaines fonctions d’assistance également. Cependant, je voulais me concentrer sur le fonctionnement du flux RSS, j’ai donc mis le code associé dans une fonction que j’ai créée et appelée userinit
. J’ai découvert à la dure que le nommer init
serait en conflit avec la bibliothèque.
Le système FUSE normal traite vos arguments de ligne de commande – une bonne chose, comme vous le verrez bientôt. Donc le principal dans HaD.cpp
est vraiment simple:
#include <stdio.h> #include "HaDFS.h" int main(int argc, char *argv[]) { HaDFS fs; if (fs.userinit()) { fprintf(stderr,"Can't fetch feedn"); return 99; }; int status; status= fs.run(argc, argv); return status; }
Cependant, pour l’instant, j’ai simplement commenté la ligne qui appelle fs.run
. Cela m’a laissé avec un programme simple qui appelle simplement userinit
.
Lire le flux n’est pas si difficile depuis que je suis conscrit curl
. Chaque sujet est dans une structure et il existe un tableau de ces structures. Si vous essayez de charger trop d’histoires, le code supprime simplement l’excédent (voir MAXTOPIC
). le topics
La variable globale indique le nombre d’histoires que nous avons réellement chargées.
// The curl line to read our feed static char cmd[]="curl https://hackaday.com/feed/ 2>/dev/null | egrep '(<title>;)|(<link>)'"; // User initialization--read the feed (note that init is reserved by the FUSE library) int HaDFS::userinit(void) { FILE *fp; char buf[1024]; // working buffer for reading strings if (!( fp = popen(cmd,"r") )) return 1; // open pipe while ( fgets(buf,sizeof(buf),fp) ) { string line = buf; line = trimrss(line); // trim off extra stuff if ( line.substr(0,7) == "<title>" ) // identify line type and process { topic[topics].title = line.substr(7); topic[topics].title += ".html"; } else if (line.substr(0,6)=="<link>") { topic[topics].url = line.substr(6); topics++; if ( topics == MAXTOPIC ) break; // quietly truncate a long feed } } pclose(fp); return 0; }
le popen
La fonction exécute une ligne de commande et nous donne le stdout
flux comme un tas de lignes. Le traitement des lignes est juste une force brute à la recherche de
curl
par grep
pour m’assurer que je n’avais pas beaucoup de lignes supplémentaires, au fait, et j’ai supposé des minuscules, mais un -i
option pourrait facilement résoudre ce problème. La redirection est d’empêcher curl
de polluer stderr
, bien que normalement FUSE déconnecte les flux de sortie, cela n’a donc pas vraiment d’importance. Notez que j’ajoute une extension HTML à chaque faux nom de fichier afin que l’ouverture d’un fichier ait plus de chances d’atteindre le navigateur.
En mettant un printf
dans le code, j’ai pu m’assurer que la récupération du flux fonctionnait comme prévu. Notez que je ne récupère les pages réelles que plus tard dans le processus. Pour l’instant, je veux juste les titres et les liens URL.
Les quatre fonctions
Il y a quatre fonctions que nous devons créer dans une sous-classe pour obtenir un système de fichiers minimal en lecture seule : getattr
, readdir
, open
et read
. Ces fonctions font à peu près ce que vous attendez. le getattr
call renverra 755 pour notre répertoire racine (et unique) et 444 pour tout autre fichier existant. le readdir
génère des entrées pour . et .. avec nos « fichiers ». Open
et read
faites exactement ce que vous pensez qu’ils font.
Il y a quelques autres fonctions, mais ce sont celles que j’ai ajoutées pour m’aider :
userinit
– Appelé pour lancer les données du système de fichierstrimrss
– Découpez une ligne RSS pour la rendre plus facile à analyserpathfind
– Transformez un nom de fichier en descripteur (un index dans le tableau des rubriques)readurl
– Renvoie une chaîne avec le contenu d’une URL (utilise curl)
Il n’y a pas grand chose à faire. Vous verrez dans le code qu’il y a quelques éléments à surveiller, comme attraper quelqu’un essayant d’écrire dans un fichier car cela n’est pas autorisé.
Options de débogage et de ligne de commande
Bien sûr, peu importe à quel point c’est simple, ça ne marchera pas la première fois, n’est-ce pas ? Bien sûr, d’abord, vous devez vous rappeler de mettre l’appel à fs.run
retour dans la fonction principale. Mais, bien sûr, les choses ne fonctionneront pas comme prévu pour un certain nombre de raisons. Il y a quelques points à retenir lors de l’exécution et du débogage.
Lorsque vous construisez votre exécutable, vous l’exécutez simplement et fournissez un argument de ligne de commande pour spécifier le point de montage qui, bien sûr, devrait exister. J’ai l’habitude d’utiliser /tmp/mnt
pendant le débogage, mais cela peut être n’importe où vous avez des autorisations.
En fonctionnement normal, FUSE détache votre programme afin que vous ne puissiez pas simplement le tuer. Vous devrez utiliser la commande unmount (fusermount -u
) avec le point de montage comme argument. Même si votre programme meurt avec une erreur de segment, vous devrez utiliser la commande unmount ou vous obtiendrez probablement le message d’erreur redouté « point final déconnecté ».
Être détaché conduit à un problème. Si vous mettez printf
instructions dans votre code, elles n’apparaîtront jamais après le détachement. Pour cette raison, FUSE comprend les -f
drapeau qui indique au système de garder votre système de fichiers en cours d’exécution au premier plan. Ensuite, vous pouvez voir les messages et une sortie propre, comme un Control + C, démontera proprement le système de fichiers. Vous pouvez aussi utiliser -d
qui permet un débogage intégré et implique -f
. le -s
flag désactive le threading, ce qui peut faciliter le débogage ou le compliquer si vous avez affaire à un problème lié au thread.
Vous pouvez utiliser gdb
, et il y a de bons articles à ce sujet. Mais pour un morceau de code aussi simple, ce n’est pas vraiment nécessaire.
Et après?
La documentation de la bibliothèque n’est presque rien. Cependant, la bibliothèque reflète étroitement la libfuse
API donc la documentation pour cela (principalement dans fuse.h) vous aidera à aller plus loin. Si vous souhaitez passer de FUSE à un « vrai » système de fichiers, la route est longue. La vidéo ci-dessous donne quelques informations sur Linux VFS, mais ce n’est que le début de cette voie.
Peut-être s’en tenir à FUSE pendant un certain temps. Si vous préférez Python, pas de problème. FUSE est très populaire pour mapper le stockage en nuage dans votre système de fichiers, mais avec votre propre codage, vous pouvez tout aussi facilement exposer votre Arduino ou tout autre élément avec lequel votre ordinateur peut communiquer.