Licence CC BY

Un shell en écrit en Rust

Voilà depuis quelques temps, si vous me suivez, vous avez peut-être remarqué ou pas(car je le dit peu et que je ne suis pas très actif ici) je m’intéresse beaucoup au langage de programmation Rust, et très récemment j’ai découvert Redox qui est un micro kernel écrit en Rust(je pense faire un billet dessus, si je trouve comment build une iso ou une image pour une vm).
Et en explorant leurs forums et leurs gitlab je suis tombé sur ça,
un shell écrit en Rust pour Linux et Redox, j’ai été très surpris et en bon utilisateur d’ArchLinux je suis allé voir l’AUR;
j’y ai trouvé le paquet correspondant ion, je l’ai installé et l’ai testé.
EDIT: ion n’est pas mit régulièrement à jour sur l’AUR, installez-le via cargo

Introduction à Ion

Ion est donc un shell Unix non-POSIX(si vous ne savez pas ce que c’est je pense que quelques recherches s’imposent) pour Linux mais aussi pour Redox.
Globalement les fonctions simples d’un shell sont là, ls, cd et d’autres encore. Mais plus intéressant encore c’est son auto-complétion semblable à fish ou à zsh(deux autres shells).

Je me permet de vous donner un peu de documentation car je ne saurais pas tout expliquer.
Le manuel de Ion(présenté à la manière des Rust book)
Le site de Redox
Les forums de Redox(pour poser des questions)
Qu’es-ce qu’un kernel Un microkernel c’est un kernel, mais en plus petit.(enfin… pas vraiment, encore une fois Wikipédia vous aidera grandement)
Il y en à qui ont besoin de liens pour ce que c’est qu’un shell?
Shell Unix
Ça suffit les liens maintenant, on passe à la suite.

Le shell

Ion par défaut ressemble à ça (j’ai eu la flemme de virer mon fichier de config du coup y’a quand même deux/trois modifications par rapport au shell de base) Ion avec screenfetch

Et l’auto-complétion aussi y est! Démonstration de l'auto-complétion dans ion

Grâce à screenfetch vous pouvez admirer mon environnement, le prompt est assez dénudé car je n’ai pas encore compris comment le personnaliser, le documentation n’étant pas finie et le projet étant encore tout nouveau.
Malgré cela j’ai quand même personnalisé mon fichier de configuration, qui par défaut se trouve dans $HOME/.config/ion/initrc,
la syntaxe n’est pas très différente de celle de bash ou zsh dans leurs fichiers de configuration respectifs.

Voici la partie utilisé de mon fichier de configuration(dans le reste c’est un tas de commentaires pour moi-même)

############################
# Ion global configuration #
############################

# History configuration
let HISTORY_SIZE = "100000"
let HISTFILE_SIZE = "100000"
let HISTORY_IGNORE = ["no_such_command", "duplicates"]


##########
# Prompt #
##########

fn PROMPT
    echo -n "${c::0x55,bold}${USER}${c::0x4B}\@${c::0x55,bold}$(hostname)${c::default}:${c::0x4B}${SWD}${c::default}# ${c::reset}"
end

################
# Set misc var #
################

# Exported vars
export VISUAL='vim'
export EDITOR='vim'
export PAGER='less'
export HASTE_SERVER="https://haste.breizh.me"
export GTK2_RC_FILES="$HOME/.gtkrc-2.0"
export QT_QPA_PLATFORMTHEME='qt5ct'
export BROWSER="firefox-nightly"
export TERMINAL="termite"
export OPENSSL_INCLUDE_DIR="/usr/include/openssl-1.0"
export OPENSSL_LIB_DIR="/usr/lib/openssl-1.0"

# Paths
export PATH="$HOME/.local/bin:$HOME/.cargo/bin/:/usr/bin/core_perl/:$PATH"
export LD_LIBRARY_PATH="/usr/local/lib"

# Ion internal vars
let right_prompt="date '+%m/%d/%y %H:%M:%S'"


###########
# Aliases #
###########

# Color support
alias ls="ls --color=auto"
alias dir="dir --color=auto"
alias vdir="vdir --color=auto"
alias grep="grep --color=auto"
alias fgrep="fgrep --color=auto"
alias egrep="egrep --color=auto"

# ls, cd, rm, mv...
alias sl="ls --color=auto"
alias dc="cd --color=auto"
alias l="ls -CF --color=auto"
alias la="ls -FA --color=auto"
alias lla="ls -lrthFA --color=auto"
alias ll="ls -lrthF --color=auto"
alias cp="cp --interactive"
alias mv="mv --interactive"
alias df="df --human-readable"
alias du="du --human-readable"
alias rm="rm -I --preserve-root"

# Git
alias gst="git st"
alias gco="git co"
alias gadd="git add"
alias gico="git co"
alias gist="git st"
alias giadd="git add"

# Django
alias runserver="pipenv run python manage.py runserver"
alias migrate="pipenv run python manage.py makemigrations; pipenv run python manage.py migrate"
alias manage="pipenv python manage.py"

# Flask
alias fndebug="export FLASK_DEBUG=0"
alias frun="flask run"

# Python
alias pep="pycodestyle --show-pep --count"
alias pep8="pycodestyle --show-pep --count"

# Other
alias chx="chmod +x"
alias alsamixer="alsamixer -c 0"
alias qemu-kvm="qemu-system-x86_64 -enable-kvm"


########################
# Sourcing other files #
########################

screenfetch

Vous reconnaissez probablement la syntaxe de bash ou de zsh, ce qui est normal car cette syntaxe est très proche, rappelez-vous c’est un shell après-tout.

La syntaxe

Mais du coup qu’est-ce qui change entre bash ou zsh et ion?

La syntaxe et le fait que ion ne soit pas POSIX, mais ça ça fait partie de la syntaxe.
Du coup voici vite fait un résumé de ce que j’ai trouvé dans ion et qui change des autres shells.

Les couleurs

# Pour définir une couleur vous devrez utiliser le code suivant
echo ${c::0xCouleurEnHexadécimal}
# ou pour passer à la couleur pas défaut
echo ${c::default}
# ou pour réinitialiser toute les modifications
echo ${c::reset}
# ou encore pour définir une couleur en gras
echo ${c::Couleur,bold}

La définition des variables

## Pour définir une variable on peut utiliser:
# Pour la définir uniquement dans le shell.
let var = "contenu de la variable"
# ou le classique export pour définir une variable globale.
export var = "contenu de la variable"

# Mais aussi
let a b = "contenu de a" "contenu de b"

# Le mot-clé pour supprimer une variable est 'drop'
drop a b

Les variables ont des utilisations spéciales dans ion, regardez

let foo = "Hello, World"
echo $foo[..5]
echo $foo[7..]
echo $foo[2..9]

# Donne
Hello
World
llo, Wo

Une utilisation sympathique du texte et des "intervalles"(traduction pas très sure de "range")

Mais dans ion il existe aussi des array

# On crée un array comme ça
let array = [ one two 'three four' ]

# On peu utiliser des méthodes similaires à celles utilisés sur le texte
let array = [ 1 2 3 4 5 6 7 8 9 10 ]
echo @array[0]
echo @array[5..=8]

# On peu aussi copier un array dans un autre
let array_copy = [ @array ]

# Effectuer un join sur les éléments d'un array(sur du texte par exemple)
let array = [ hello world ]
let as_string = @array

# Mais on peu aussi les concaténer
let array = [1 2 3]
let array ++= [5 6 7]
let array ::= 0

# Ou les utiliser pour passer un argument à une commande
let args = [-l -a --color]
ls @args

# Finalement vous pouvez détruire un array en utilisant 'drop -a'
drop -a array

Mais mieux encore… Non seulement il y à des arrays mais en plus il y à des maps(aussi connues sous le nom dictionnaires)

# Les maps tels qu'elles sont utilisés dans ion viennent tout droit de Rust et sont eput-être un peu complèxes à comprendre, il y en à différents types

# Création d'un/une? HashMap
let hashmap:hmap[] = [ foo=hello bar=world fizz=I buzz=was bazz=here ]

# Création d'un/une? BTreeMap
let hashmap:hmap[] = [ foo=hello bar=world fizz=I buzz=was bazz=here ]

# C'est un dictionnaire donc... on appelle la clé et on à le contenu de cette clé.
let x = bazz
echo @hashmap[bar] @hashmap[$x]

# Ajouter une nouvelle clé(et son contenu)
let x[bork] = oops

# Lister les clés
echo @keys(hashmap)

# Lister les valeurs
echo @values(hashmap)

# Lister les valeurs et les clés en même temps
echo @hashmap

Sympa non? Ion permet donc de faire plein de choses plus poussés les unes que les autres.

Ion supporte aussi les assignations de variables avec le opérateurs mathématiques, mais pas tous, voici la liste de ceux supportés(et non supporté)

[x] Addition (+)
[x] Soustraction (-)
[x] Multiplication (*)
[x] Division (/)
[x] Division entière(sans virgule) (//)
[ ] Modulo(reste de la division) (%)
[x] Powers(en anglais car je sais pas) (**)

Et on peu assigner les valeurs aux variables comme il suit

let value = 0
let value += 5
let value -= 2
let value *= 3
let value //= 2
let value **= 10
let value /= 2

let a b = 5 5
let a b += 3 2
let a b -= 1 1
echo $a $b

Les conditions Pas trop de changements de ce côté là, mais voici un exemple

# Je ne présente pas les conditions
let x = 5

if test 1 == 1
  let x = 2 # updates existing x
  let y = 3 # defines y
end

echo $x
echo $y

Les fonctions Pas trop de changements non-plus, Utilisation des fonctions dans l’exemple précédent.

let x = 5

fn print_vars
  echo $x
  echo $y
end

if test 1 == 1
  let x = 2
  let y = 3
  print_vars
end

Je laisserais les curieux regarder le manuel(en anglais) pour regarder comment on peu faire fonctionner ça de manière plus poussé.


Voilà, j’ai fait un très rapide tour d’horizon de ce shell.
J’ai ignoré beaucoup de mots-clés, et d’explications(tel que les alias, la configuration… etc)

Peut-être que j’expliquerais tout ça plus en détails dans un autre article/billet.

Donnez-moi vos commentaires et votre avis sur ion, est-ce un shell qui va être oublié? Quelles sont les fonctionnalités que vous appréciez?

Personnellement je suit de très près l’avancement de ce shell, car il me plaît et offre un nouvelle alternative aux shells "standards" sur les OS Unix-like.

10 commentaires

Salut,

J’ai beaucoup de mal à voir l’intérêt. Certes, c’est codé en Rust, c’est cool. Mais passé ça …

+1 -0

L’objectif de ce shell est de ne pas avoir de failles de sécurités et de s’intégrer parfaitement dans Redox qui est un OS entièrement fait en Rust, pour les mêmes raisons que Ion, ne aps avoir de faille de sécu et être très léger(actuellement plus léger que Linux) et prévu pour pouvoir en créer des distributions.
L’objectif n’est donc pas forcément d’être utilisé par tous mais plus de répondre à un besoin spécifique pour une situation spécifique, ici on à besoin d’un shell assez puissant avec aucune faille de sécurité pour aller dans un système sécurisé et relativement puissant.

Cela reste à mes yeux un faux argument.

L’utilisateur final se moque de ces problèmes sous-jacents qui ne concernent directement qu’une infime minorité d’utilisateurs.

« Ne pas avoir de faille de sécu », c’est selon moi une asymptote. Tu trouveras toujours des brêches dans des systèmes au fur et à mesure que la science progressera. On a vu des vulnérabilités dans Rust comme dans OpenBSD où les développeurs mettent pourtant un point d’honneur sur sa sécurité.

Les vulnérabilités que tu peux trouver dans un programme écrit dans un langage moins évolué que Rust (au hasard, C ?) ne viennent pas du langage en lui-même, mais du manque de rigueur du ou des programmeurs. Si Rust saurait atténuer les erreurs humaines, il ne les évitera pas toutes.

Il aurait donc été plus juste de vanter un programme shell éprouvé par l’industrie et pour n’avoir connu en une décennie qu’un nombre de bugs mineurs, plutôt que de vanter un shell « écrit en Rust ».

+2 -1

Les vulnérabilités que tu peux trouver dans un programme écrit dans un langage moins évolué que Rust (au hasard, C ?) ne viennent pas du langage en lui-même, mais du manque de rigueur du ou des programmeurs.

Les constructeurs de voiture avaient le même argument dans les années 60/70. Pourquoi faire des voitures plus sûres ? S’il y’a un accident, c’est de toute façon de la faute du conducteur.

Mon objectif n’est pas de vanter les mérites d’un shell(à mes yeux zsh et fish sont toujours les meilleurs shells du monde)
Mais de partager une découverte que j’ai faite et qui peut potentiellement intéresser du monde, le logiciel est encore très jeune et je en l’ai pas encore assez testé pour pouvoir tout lister, il à sans doutes d’autres oints positifs comme des points négatifs.

Personnellement je ne comprend pas trop l’idée d’avoir un shell avec des concepts (plus que des features) en plus par rapport à bash ou zsh. Déjà que zsh permet beaucoup beaucoup de choses par rapport à ce qu’on attendrait d’un shell pour moi, j’ai un peu l’impression que typiquement vouloir rajouter des array c’est résoudre un problème qui n’existe pas. Si j’ai besoin de faire des choses suffisamment poussées je vais généralement me tourner vers un langage fait pour ça, typiquement python.

L’objectif d’un shell (et des scripts qu’il interprète) c’est généralement l’interopérabilité.

Il y a aussi des shells qui sont capables d’afficher une image (en bitmap, pas en libcaca), et si ça peut paraitre comme une « avancée technique », je ne vois pas l’utilité par rapport à l’afficher dans une application dédiée, qui va permettre le zoom, la rotation, etc, de façon bien plus agréable et puissante que le terminal lui-même, sans gêner l’utilisation du terminal.

Pour la personnalisation, ça peut être intéressant mais je ne vois pas ce que ça change par rapport à zsh, donc perdre la conformité à POSIX pour les mêmes features ça me parait dommage.

Ce débat sur l’utilité d’un shell en Rust me dérange un petit peu. Quel est l’intérêt de ce projet libre ? Eh bien le même que tous les autres, déjà : celui d’exister !

Je suis très serieux quand je dis ça. Il y a des tas de questions intéressantes auxquelles l’examen du code source (ou une contribution) peuvent apporter une réponse :

  • Ce projet a-t’il été un prétexte pour developper des bibliothèques nouvelles dans l’écosystème de Rust, et donc l’enrichir ?
  • Peut-on trouver une mesure quantitative de l’effort pour rendre ce shell aussi sûr et performant que bash ?
  • Cet effort est-il suffisamment bas pour en déduire que le développement en Rust permet d’obtenir un résultat comparable "pour beaucoup moins cher" ?
  • Quelles sont les difficultés inhérentes (le plus souvent cachées) au développement d’un shell ?
  • Comment ces difficultés ont-elles été surmontées dans ion ? Dans bash ? Dans zsh ?

M’est avis que trouver une réponse à ces questions est un préalable avant de savoir si l’adoption de ce shell représente un réel avantage, ou non, pour l’utilisateur final, car elles sont indicatives du niveau de confiance que celui-ci peut avoir dans le logiciel, dans le fait que celui-ci va évoluer sainement ou non, avec des mises à jours petites et régulières, pour corriger des bugs qui auront demandé une quantité plus ou moins grande d’efforts aux contributeurs.

C’est le principal argument de vente de Rust : faire au moins aussi bien, au moins aussi rapide, au moins aussi sûr, en retirant le plus de charge possible des épaules du développeur.

Ce projet est à mon avis un mètre étalon parfait pour vérifier que ces objectifs sont atteints par Rust dans la vraie vie. Et si tel est le cas (et je suis plutôt optimiste à ce sujet), alors oui, c’est fait en Rust deviendrait derechef un indicateur a priori de qualité et de sûreté d’un logiciel. Pas forcément un indicateur 100% fiable, bien sûr, mais suffisant pour justifier que ce projet ait été entrepris et mérite qu’on y contribue, ne serait-ce qu’en l’utilisant et en ouvrant des tickets le cas échéant.

Par ailleurs je ne trouve pas non plus que la remarque de @davidbrcz plus haut soit "hors-sujet" : la façon dont un logiciel est produit a une influence décisive sur sa fiabilité, et le parallèle avec une chaîne de production de voitures n’est pas du tout déconnant. Vous auriez confiance en une voiture ou un avion dont les circuits ont été soudés à la main ("avec <3") dans une cave ?

Rejeter tout le besoin de rigueur sur le développeur, c’est un peu facile. Moi aussi je préfère, a priori, utiliser un langage malléable quand je sais que j’arriverai plus vite à un résultat correct sur un projet pas trop critique en reposant sur ma seule expérience et quelques hacks, mais ça ne veut pas dire que tout le monde dans l’équipe dispose de cette expérience/cette rigueur, ou peut l’acquérir rapidement pour ce projet. Dans ces conditions, il y a effectivement des cas dans lesquels je préfère être logé à la même enseigne que les autres et me battre contre un compilateur qui va me chier dans les bottes avant d’autoriser mon code à tourner, plutôt que chier moi-même dans les bottes des autres contributeurs pendant les reviews et faire humainement tout un tas d’allers-retours qui auraient pu être faits automatiquement avec le compilateur : sans aller jusqu’à en foutre partout et tout faire avec par défaut, on ne peut pas nier la valeur de Rust dans ces conditions. Conditions qu’un projet de shell remplit allègrement.

+6 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte