Dies ist die Homepage/Dokumentation für Crosh, die Chromium OS-Shell. Wenn Sie sich gerade auf einem CrOS-Gerät befinden, sollten Sie Crosh starten können, indem Sie Strg + Alt + T drücken.
Führen Sie einfach help
aus, um Informationen über verfügbare Befehle zu erhalten und mehr zu erfahren.
Sie können auch die Tabulatorvervollständigung verwenden, um vorhandene Befehle schnell zu finden.
Es ist ein Abenteuer!
- Für Chromium OS-Entwickler
- Sicherheitswarnung
- Wo Dateien leben
- Source Repos
- Hinzufügen neuer Befehle
- Befehlsdesign
- Beispiele
- Modul einrichten
- Befehlsimplementierung
- Befehlshilfe
- Veraltete Befehle
- Testen
- Iterative Entwicklung
- Unittests
- Zukünftige Arbeit
- Legacy Crosh Dokumentation
- Befehls-API
- Befehlshilfe
- Ausblenden von Befehlen
Für Chromium OS-Entwickler
Dieser Abschnitt richtet sich an Personen, die unter Chromium OS hacken, insbesondere wenn sie Crosh ändern / erweitern müssen.
Sicherheitswarnung
Bitte installieren Sie keine neuen Module ohne vollständige Sicherheitsüberprüfung. Jeder unsichere Code, den Crosh lädt, steht Personen im verifizierten Modus direkt zur Verfügung. Dies ist ein einfacher Angriffsvektor, um beliebigen Code auszuführen und den Status des Benutzers zu beeinträchtigen. Wir wollen die Sicherheit von CrOS nicht untergraben!
Wenn Sie nach Rezensenten suchen, schauen Sie sich die an ./OWNERS-Datei.
Wo Dateien leben
Crosh wird von Shell nach Rust migriert. Crosh beginnt mit der Ausführung von src/main.rs, aber die meisten Befehle werden als eigenes Submodul eines der übergeordneten Module implementiert (z. B. base
oder dev
).
Das crosh
Hauptskript enthält die Legacy-Implementierung der Core-Crosh-Logik, während andere Legacy-Funktionen in Modulverzeichnissen gespeichert sind. Die Legacy-Version von crosh wird auf dem Gerät als crosh.sh
installiert.
Source Repos
Module, die spezifisch für ein Board oder stark spezifisch für ein Paket sind, sollten im Allgemeinen mit diesem Board und / oder Paket leben. Für Funktionen, die immer auf allen CrOS-Geräten verfügbar sind, sollte dieser Code in diesem Repo gespeichert werden.
Wenn Sie unsicher sind, fragen Sie einfach auf [email protected] .
Hinzufügen neuer Befehle
Bestimmen Sie zunächst, welche Implementierungsstrategie der neue Befehl verwenden wird. Bei der Auswahl einer Strategie hilft es zu wissen, welche Berechtigungen und Privilegien benötigt werden. Mit der Strategie im Auge, schauen Sie sich die verschiedenen Beispiele unten.
Befehlsdesign
Die Crosh-Shell läuft in derselben Umgebung wie der Browser (gleicher Benutzer/Gruppe, gleiche Linux-Namespaces usw…). Daher müssen alle Tools, die Sie in crosh ausführen, oder Informationen, die Sie abrufen möchten, für den Benutzer chronos
zugänglich sein.
Wir möchten jedoch selten, dass Crosh Tools direkt ausführt. Stattdessen sollten Sie dem Debugd-Daemon D-Bus-Rückrufe hinzufügen und alle Anforderungen an ihn senden. Wir können den Zugriff in debugd besser kontrollieren und Tools sperren. Dann ist die einzige Logik, die in Crosh vorhanden ist, ein D-Bus-IPC-Aufruf und zeigt dann die Ausgabe dieser Programme an. Die Diskussion über debugd ist hier nicht möglich, also schauen Sie sich stattdessen das debugd-Verzeichnis an.
Beispiele
Beispielimplementierungen:
- D-Bus Method Wrapper (debugd): base::verify_ro
Verwenden Sie diese Option, wenn eine D-Bus-API bereits geplant ist oder crosh nicht über die erforderlichen Berechtigungen oder Funktionen verfügt. - Externe Binär-Wrapper: base::ccd_pass
Verwenden Sie diese, wenn es bereits ein Kommandozeilen-Tool, das den Befehl, der funktioniert, wenn sie als chronos mit den Fähigkeiten von crosh ausgeführt implementiert. - Befehl in Rust geschrieben: base::arc
Dies eignet sich am besten für Fälle, in denen zusätzliche Funktionen nicht benötigt werden und ein separates Befehlszeilentool nicht gerechtfertigt ist.
Unten finden Sie einen Beispiel-Workflow zum Schreiben eines neuen Befehls.
Modul einrichten
Wählen Sie ein geeignetes Modul aus, zu dem der Befehl gehören soll. Für Befehle im dev-Modus ist dies dev
, die meisten anderen Befehle gehören in base
. In diesem Beispiel wird base
als Modul verwendet, aber die gleichen Schritte sollten in anderen Fällen weiterhin gelten.
Wählen Sie dann einen Befehlsnamen aus, erstellen Sie ein Untermodul mit diesem Namen und registrieren Sie es beim übergeordneten Modul. In diesem Beispiel lautet der Befehl verify_ro
, die neue Quelldatei lautet also src/base/verify_ro.rs
und es müssen zwei Zeilen zu src/base/mod.rs
:
Zuerst muss das Submodul importiert werden:
mod verify_ro;
Zweitens muss die Registerfunktion (die unten erstellt werden soll) von der Registerfunktion im übergeordneten Modul aufgerufen werden src/base/mod.rs
:
pub fn register(dispatcher: &mut Dispatcher) { ... verify_ro::register(dispatcher); ...}
Nun kann die src/base/verify_ro.rs
Quelldatei geschrieben werden. Beginnen Sie mit dieser minimalen Quelldatei und stellen Sie sicher, dass crosh mit cargo build
kompiliert wird:
use crate::dispatcher::Dispatcher;pub fn register(dispatcher: &mut Dispatcher) { dispatcher.register_command( Command::new( "verify_ro".to_string(), "TODO put usage here".to_string(), "TODO put description here".to_string(), ) .set_command_callback(Some(execute_verify_ro)), );}fn execute_verify_ro(_cmd: &Command, args: &Arguments) -> Result<(), dispatcher::Error> { unimplemented!();}
Befehlsimplementierung
Dies setzt voraus, dass die obigen Anweisungen bereits vollständig sind.
Da privilegierte Operationen nicht von Crosh ausgeführt werden können (sondern in debugd oder wo auch immer implementiert werden sollten), konzentriert sich das folgende Beispiel insbesondere auf D-Bus und geht davon aus, dass es eine vorhandene D-Bus-Methode gibt, die von einem neuen Crosh-Befehl aufgerufen werden muss.
Beachten Sie, dass die D-Bus-Schnittstelle von debugd bereits Rust-Bindungen enthält, die über dev-rust/system_api generiert wurden, sodass die Bindungen und die D-Bus-Verbindung importiert werden können mit:
use dbus::blocking::Connection;use system_api::client::OrgChromiumDebugd;
Wenn Sie nach dem Ausführen von build_packages den Quellcode der generierten Bindungen durchsuchen möchten, sehen Sie sich den folgenden Pfad an:
/build/${BOARD}/usr/lib/cros_rust_registry/registry/system_api-*/src/bindings/client/
Innerhalb der Befehlsimplementierung muss eine D-Bus-Verbindung initialisiert werden. In diesem Beispiel wird eine blockierende Verbindung verwendet.
let connection = Connection::new_system().map_err(|err| { error!("ERROR: Failed to get D-Bus connection: {}", err); dispatcher::Error::CommandReturnedError})?;
Die Busverbindung kann dann verwendet werden, um eine Schnittstelle zum gewünschten Dienst zu erhalten, der in diesem Fall debuggt wird:
let conn_path = connection.with_proxy( "org.chromium.debugd", "/org/chromium/debugd", DEFAULT_DBUS_TIMEOUT,);
Der Rest des Methodenaufrufs nutzt die Tatsache, dass das importierte Merkmal system_api::client::OrgChromiumDebugd
für conn_path
Die Memberfunktionen, die D-Bus-Methoden zugeordnet sind, können also von conn_path
aufgerufen werden. Zum Beispiel:
conn_path .update_and_verify_fwon_usb_stop(handle) .map_err(|err| { println!("ERROR: Got unexpected result: {}", err); dispatcher::Error::CommandReturnedError })?;
Dies behandelt die Grundlagen. Wenn Sie sich den tatsächlichen Quellcode für base ansehen::verify_ro bietet ein komplizierteres Beispiel mit einem Start-Methodenaufruf, einem Watcher und einem Stop-Methodenaufruf.
Befehlshilfe
Die Standard-Hilfezeichenfolgen werden mit dem Befehlsnamen, der Verwendungszeichenfolge, der Beschreibungszeichenfolge und allen Optionen oder Flags gefüllt, die über die Dispatcher-API registriert sind.
Alternativ kann bei der Registrierung des Befehls ein Hilfe-Callback gesetzt werden, um benutzerdefinierte Logik wie das Aufrufen der Hilfe-Option einer Binärdatei auszuführen. Beispielsweise:
const EXECUTABLE: &str = "/usr/bin/vmc";pub fn register(dispatcher: &mut Dispatcher) { dispatcher.register_command( Command::new("vmc".to_string(), "".to_string(), "".to_string()) .set_command_callback(Some(execute_vmc)) .set_help_callback(vmc_help), );}fn vmc_help(_cmd: &Command, w: &mut dyn Write, _level: usize) { let mut sub = process::Command::new(EXECUTABLE) .arg("--help") .stdout(Stdio::piped()) .spawn() .unwrap(); if copy(&mut sub.stdout.take().unwrap(), w).is_err() { panic!(); } if sub.wait().is_err() { panic!(); }}
Veraltete Befehle
Wenn Sie einen Crosh-Befehl durch eine andere Benutzeroberfläche ersetzen möchten (z. B. eine chrome:// -Seite) und den Befehl ordnungsgemäß verwerfen möchten, indem Sie eine freundliche Notiz hinterlassen, wenn Benutzer versuchen, ihn zu verwenden, finden Sie hier das Formular.
# Set the vars to pass the unittests ...USAGE_storage_status=''HELP_storage_status=''# ... then unset them to hide the command from "help" output.unset USAGE_storage_status HELP_storage_statuscmd_storage_status() ( # TODO: Delete this after the R## release branch. echo "Removed. See storage_info section in chrome://system")
Stellen Sie sicher, dass Sie den TODO-Kommentar hinzufügen, damit die Leute in Zukunft wissen, wann es in Ordnung ist, ihn aufzuräumen.
Testen
Iterative Entwicklung
Sie können ./crosh
auf Ihrem Desktop-System ausführen, um eine Beispiel-Shell zu erhalten. Sie können hier schnell grundlegende Interaktionen (wie Argumentanalyse) testen oder die Hilfeausgabe überprüfen. Sie haben keinen Zugriff auf die CrOS-Dienste, mit denen viele Crosh-Befehle (über D-Bus) kommunizieren sollen, sodass diese Befehle fehlschlagen.
Wenn Sie Module im Entwicklungsmodus laden möchten, können Sie ./crosh --dev
. Es werden nur lokale Module geladen (./dev.d/
).
Wenn Sie Wechselgerätemodule laden möchten, können Sie ./crosh --removable
.
Unittests
Um die Unit-Tests auszuführen, rufen Sie entweder cargo test --workspace
im Crosh-Ordner auf oder führen Sie emege-${BOARD} crosh && FEATURES=test emerge-${BOARD}
Der ./run_tests.sh
Legacy unittest runner führt eine Reihe grundlegender Style- und Soundness-Checks durch. Führen Sie es gegen Änderungen am Shell-Code aus!
Zukünftige Arbeit
Jeder sollte sich frei fühlen, diese Ideen aufzugreifen und zu versuchen, sie umzusetzen :).
- Verschieben Sie alle verbleibenden Befehle, die an Ort und Stelle implementiert sind, in Debugd-Aufrufe, damit sie über D-Bus ausgeführt werden können.
- Führen Sie crosh selbst in einer eingeschränkten Sandbox aus (Namespaces/seccomp/etc…). Sobald alle Befehle über IPC ausgeführt wurden, müssen keine privaten mehr gespeichert werden. Könnte es jedoch vom Entwicklungsmodus abhängig machen, so dass wir
shell
nicht brechen. - Migrieren Sie zusätzliche Legacy-Shell-Befehle nach Rust. Dies kann auch gleichzeitig mit der Migration eines Befehls zu debugd erfolgen.
Legacy Crosh Dokumentation
Crosh wurde ursprünglich in Shell geschrieben. Zum Zeitpunkt des Schreibens sind viele der Befehle noch in der Shell und müssen noch auf das Rust Crosh portiert werden. Diese Dokumentation wird hier für die Wartung dieser Befehle aufbewahrt.
Befehls-API
Für jeden Befehl definieren Sie zwei Variablen und eine Funktion. Die neuen Befehle müssen nirgendwo registriert werden, da Crosh seine eigene Laufzeitumgebung überprüft, um sie zu ermitteln.
So würden Sie einen neuen foo
-Befehl registrieren.
# A short description of arguments that this command accepts.USAGE_foo='<some args>'HELP_foo=' Extended description of this command.'# Not required, but lets crosh detect if the foo program is available in the# current system (e.g. the package is not installed on all devices). If it# isn't available, crosh will automatically display an error message and never# call cmd_foo.EXEC_foo='/full/path/to/program'cmd_foo() ( # Implementation for the foo command. # You should validate $# and "$@" and process them first. # For invalid args, call the help function with an error message # before returning non-zero. ...foo code goes here!...)
Weitere Informationen darüber, was und wie der neue Befehl strukturiert werden soll, finden Sie im Abschnitt Design unten.
Befehlshilfe
Wenn Ihr Crosh-Befehl einfach ein externes Programm aufruft, um die Verarbeitung durchzuführen, und dieses Programm bereits Nutzungsdetails enthält, möchten Sie wahrscheinlich keine Duplikate erstellen müssen. Sie können dieses Szenario behandeln, indem Sie eine help_foo
Funktion definieren, die den entsprechenden Aufruf ausführt.
# Set the help string so crosh can discover us automatically.HELP_foo=''cmd_foo() ( ...)help_foo() ( /some/command --help)
Beachten Sie, dass wir immer noch HELP_foo
. Dies wird benötigt, damit crosh uns automatisch erkennen und in den relevanten Benutzerlisten anzeigen kann (wie der Befehl help_advanced
). Wir müssen jedoch nicht USAGE_foo
da die help_foo
Funktion dies für uns erledigt.
Ausblenden von Befehlen
Wenn ein Befehl noch nicht für die „Prime Time“ bereit ist, möchten Sie ihn möglicherweise zum frühen Testen in crosh haben, aber nicht in der help
Ausgabe, in der Benutzer ihn leicht finden können (natürlich ist der Code öffentlich, sodass jeder, der die tatsächliche Quelle liest, ihn finden kann). Hier ist, wie Sie es tun.
# Set the vars to pass the unittests ...USAGE_vmc=''HELP_vmc=''# ... then unset them to hide the command from "help" output.unset USAGE_vmc HELP_vmccmd_vmc() ( ...)