Crosh — Die Chromium OS-Shell

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

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() ( ...)

Related Posts

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.