Questa è la homepage/documentazione per il crosh, il Chromium OS shell. Se sei su un dispositivo CrOS in questo momento, dovresti essere in grado di lanciare crosh premendo Ctrl+Alt+T. Se non sei su CrOS, molto probabilmente non farà nulla di utile :).
Basta eseguire help
per ottenere informazioni sui comandi disponibili e scoprire di più.
È inoltre possibile utilizzare il completamento scheda per trovare rapidamente i comandi esistenti.
È un’avventura!
- Per gli sviluppatori di Chromium OS
- Avviso di sicurezza
- Dove vivono i file
- Repository di origine
- Aggiunta di nuovi comandi
- Command Design
- Esempi
- Configurazione del modulo
- Implementazione del comando
- Comando Help
- Deprecare i comandi
- Testing
- Iterative Development
- Unittests
- Lavoro futuro
- Legacy Crosh Documentation
- API di comando
- Comando Help
- Nascondere i comandi
Per gli sviluppatori di Chromium OS
Questa sezione è pensata per le persone che hacking su Chromium OS, soprattutto quando hanno bisogno di modificare/estendere crosh.
Avviso di sicurezza
Si prega di non installare nuovi moduli senza revisione completa di sicurezza. Qualsiasi codice insicuro che crosh carica sarà direttamente disponibile per le persone in modalità verificata. Questo è un vettore di attacco facile da eseguire codice arbitrario e pasticciare con lo stato dell’utente. Non vogliamo minare la sicurezza di CrOS!
Se siete alla ricerca di revisori, guardare il ./ File PROPRIETARI.
Dove vivono i file
Crosh viene migrato dalla shell a Rust. Crosh inizia l’esecuzione da src / main. rs ma la maggior parte dei comandi sono implementati come sottomodulo proprio di uno dei moduli di alto livello (ad esempio base
o dev
).
Lo script principalecrosh
contiene l’implementazione legacy della logica crosh di base mentre altre funzioni legacy vivono nelle directory dei moduli. La versione precedente di crosh è installata sul dispositivo come crosh.sh
.
Repository di origine
I moduli specifici per una scheda, o fortemente specifici per un pacchetto, dovrebbero generalmente convivere con quella scheda e / o pacchetto. Per le funzioni che sono sempre disponibili su tutti i dispositivi CrOS, tale codice deve essere conservato in questo repository.
Se non sei sicuro, basta chiedere su [email protected].
Aggiunta di nuovi comandi
Determinare innanzitutto quale strategia di implementazione utilizzerà il nuovo comando. Quando si seleziona una strategia, aiuta a sapere quali autorizzazioni e privilegi sono necessari. Con la strategia in mente, controlla i vari esempi qui sotto.
Command Design
La shell crosh viene eseguita nello stesso ambiente del browser (stesso utente / gruppo, stessi spazi dei nomi Linux, ecc…). Quindi qualsiasi strumento eseguito in crosh, o informazioni che si tenta di acquisire, deve essere accessibile all’utente chronos
.
Tuttavia, raramente vogliamo che crosh esegua effettivamente gli strumenti direttamente. Invece, è necessario aggiungere callback D-Bus al demone debugd e inviare tutte le richieste ad esso. Possiamo controllare meglio l’accesso in debug e bloccare gli strumenti. Quindi l’unica logica che esiste in crosh è una chiamata IPC D-Bus e quindi visualizza l’output da quei programmi. La discussione su debugd è fuori dallo scopo qui, quindi controlla invece la directory debugd.
Esempi
Implementazioni di esempio:
- D-Bus method wrapper (debug): base::verify_ro
Usalo quando un’API D-Bus è già pianificata o crosh non ha le autorizzazioni o le capacità necessarie. - External binary wrapper: base::ccd_pass
Usalo quando c’è già uno strumento da riga di comando che implementa il comando che funziona quando viene eseguito come chronos con le funzionalità di crosh. - Comando scritto in Rust: base::arc
Questo è più adatto per i casi in cui non sono necessarie funzionalità aggiuntive e avere uno strumento a riga di comando separato non è giustificato.
Di seguito è incluso un flusso di lavoro di esempio per la scrittura di un nuovo comando.
Configurazione del modulo
Scegli un modulo appropriato per il comando a cui appartenere. Per i comandi della modalità dev questo saràdev
, la maggior parte degli altri comandi apparterrà abase
. Questo esempio utilizzerà base
come modulo, ma gli stessi passaggi dovrebbero essere applicati in altri casi.
Quindi scegli un nome di comando, crea un modulo secondario con quel nome e registralo con il modulo genitore. Per questo esempio, il comando verify_ro
, in modo che il nuovo file di origine è src/base/verify_ro.rs
e due linee devono essere aggiunte alla src/base/mod.rs
:
in Primo luogo, il submodule deve essere importato:
mod verify_ro;
Secondo la funzione di registrazione (per essere creata sotto) deve essere chiamato mediante la funzione di registrazione nel modulo principale src/base/mod.rs
:
pub fn register(dispatcher: &mut Dispatcher) { ... verify_ro::register(dispatcher); ...}
Ora il file sorgente src/base/verify_ro.rs
è pronto per essere scritto. Inizia con questo file sorgente minimo e verifica che crosh compili con cargo build
:
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!();}
Implementazione del comando
Questo presuppone che le istruzioni precedenti siano già complete.
Poiché le operazioni privilegiate non possono essere eseguite da Crosh (ma dovrebbero essere implementate in debugd o altrove), l’esempio seguente si concentra su D-Bus in particolare e presuppone che esista un metodo D-Bus esistente che deve essere chiamato da un nuovo comando Crosh.
Nota che debugd l’interfaccia D-Bus ha già la Ruggine associazioni generato attraverso il dev-ruggine/system_api, quindi, le associazioni e D-Bus possono essere importati con:
use dbus::blocking::Connection;use system_api::client::OrgChromiumDebugd;
Se si desidera visualizzare il codice sorgente generato associazioni, dopo l’esecuzione di build_packages, date un’occhiata al il seguente percorso:
/build/${BOARD}/usr/lib/cros_rust_registry/registry/system_api-*/src/bindings/client/
all’Interno del comando di attuazione D-Bus di connessione deve essere inizializzato. In questo esempio viene utilizzata una connessione di blocco.
let connection = Connection::new_system().map_err(|err| { error!("ERROR: Failed to get D-Bus connection: {}", err); dispatcher::Error::CommandReturnedError})?;
Il collegamento al bus può quindi essere utilizzato per ottenere un’interfaccia per il servizio desiderato, che è debugd in questo caso:
let conn_path = connection.with_proxy( "org.chromium.debugd", "/org/chromium/debugd", DEFAULT_DBUS_TIMEOUT,);
Il resto della chiamata al metodo utilizza il fatto che la importati tratto system_api::client::OrgChromiumDebugd
è implementato per conn_path
le funzioni membro che la mappa di D-Bus metodi può essere chiamato da un conn_path
. Ad esempio:
conn_path .update_and_verify_fwon_usb_stop(handle) .map_err(|err| { println!("ERROR: Got unexpected result: {}", err); dispatcher::Error::CommandReturnedError })?;
Questo copre le basi. Se si guarda il codice sorgente effettivo per base::verify_ro, fornisce un esempio più complicato con una chiamata al metodo start, un watcher e una chiamata al metodo stop.
Comando Help
Le stringhe di aiuto predefinite vengono compilate utilizzando il nome del comando, la stringa di utilizzo, la stringa di descrizione e tutte le opzioni o i flag registrati tramite l’API dispatcher.
In alternativa, è possibile impostare un callback di aiuto quando si registra il comando per eseguire una logica personalizzata come richiamare l’opzione di aiuto di un binario. Biru:
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!(); }}
Deprecare i comandi
Se si desidera sostituire un comando crosh con qualche altra interfaccia utente (come una pagina chrome://), e si desidera deprecare il comando con garbo lasciando dietro di sé una nota amichevole se le persone cercano di usarlo, ecco il modulo.
# 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")
Assicurati di aggiungere il commento TODO in modo che le persone sappiano in futuro quando è ok pulirlo.
Testing
Iterative Development
È possibile eseguire./crosh
sul sistema desktop per ottenere una shell di esempio. Puoi testare rapidamente le interazioni di base (come l’analisi degli argomenti) qui o controllare l’output della guida. Non avrai accesso ai servizi CrOS con cui molti comandi crosh si aspettano di parlare (tramite D-Bus), quindi quei comandi falliranno.
Se si desidera caricare i moduli in modalità dev, è possibile utilizzare ./crosh --dev
. Caricherà solo moduli locali (./dev.d/
), quindi se il tuo modulo vive altrove, puoi copiarlo qui temporaneamente.
Allo stesso modo, se si desidera caricare moduli di dispositivi rimovibili, è possibile utilizzare./crosh --removable
.
Unittests
Per eseguire i test unitari chiamarecargo test --workspace
nella cartella crosh oppure eseguireemege-${BOARD} crosh && FEATURES=test emerge-${BOARD}
Il./run_tests.sh
legacy unittest runner esegue una serie di controlli di base di stile e solidità. Eseguilo contro qualsiasi modifica al codice della shell!
Lavoro futuro
Chiunque dovrebbe sentirsi libero di raccogliere queste idee e cercare di implementarle :).
- Sposta tutti i comandi rimanenti implementati sul posto per eseguire il debug delle chiamate in modo che possano essere eseguite su D-Bus.
- Esegui crosh stesso in una sandbox limitata (namespaces / seccomp / etc…). Una volta che tutti i comandi vengono eseguiti tramite IPC, non è necessario mantenere i priv. Potrebbe renderlo dipendente dalla modalità dev, quindi non interrompiamo
shell
. - Migrare ulteriori comandi shell legacy su Rust. Questo può anche essere fatto contemporaneamente alla migrazione di un comando su debug.
Legacy Crosh Documentation
Crosh è stato originariamente scritto in shell. Al momento della scrittura molti dei comandi rimangono ancora nella shell e devono ancora essere portati su Rust crosh. Questa documentazione è conservata qui per il mantenimento di questi comandi.
API di comando
Per ogni comando, si definiscono due variabili e una funzione. Non è necessario registrare i nuovi comandi ovunque, poiché crosh ispezionerà il proprio ambiente di runtime per scoprirli.
Ecco come registrare un nuovo comandofoo
.
# 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!...)
Vedere la sezione design di seguito per maggiori dettagli su cosa e come strutturare il nuovo comando.
Comando Help
Se il tuo comando crosh chiama semplicemente un programma esterno per eseguire l’elaborazione e quel programma offre già dettagli sull’utilizzo, probabilmente non vuoi dover duplicare le cose. È possibile gestire questo scenario definendo una funzionehelp_foo
che effettua la rispettiva chiamata.
# Set the help string so crosh can discover us automatically.HELP_foo=''cmd_foo() ( ...)help_foo() ( /some/command --help)
Prendi nota che abbiamo ancora impostato HELP_foo
. Questo è necessario in modo che crosh possa scoprirci automaticamente e visualizzarci negli elenchi di utenti pertinenti (come il comandohelp_advanced
). Non abbiamo bisogno di impostare USAGE_foo
anche se la funzione help_foo
lo fa per noi.
Nascondere i comandi
Se un comando non è ancora pronto per “prime time”, potresti volerlo avere in crosh per i primi test, ma non farlo apparire nell’outputhelp
dove gli utenti possono facilmente scoprirlo (ovviamente, il codice è tutto pubblico, quindi chiunque legga la fonte effettiva può trovarlo). Ecco come si fa.
# 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() ( ...)