I comandi concatenati sono atomici?


8

Se ci fosse un processo che scrive continuamente su un file e volessi prendere il controllo del file con root, potrei fare qualcosa del genere:

sudo rm somefile; sudo touch somefile

È possibile per il processo di aggiunta aggiungere al file tra questi due comandi? In tal caso, esiste un modo per garantire che nessun altro comando venga eseguito in mezzo?


4
Questo potrebbe essere un problema XY . Puoi spiegare il problema di fondo che stai cercando di risolvere?
Nate Eldredge,

1
@NateEldredge: Totalmente no. Posso capire perché sembra così basato sul mio ipotetico inventato. Non ho nemmeno problemi. Solo curioso.
Darth Egregious,

5
Il processo probabilmente continuerà probabilmente a scrivere sul file eliminato e nemmeno tenterà di aprire quello nuovo.
Casuale 832

La mia ipotesi sull'ipotetico si è rivelata un po 'sbagliata, ma immagino che potresti cambiare "append" in "open" o "touch" e avrebbe comunque senso.
Darth Egregious,

Risposte:


12

Una riga di comando concatenata è fondamentalmente un piccolo script di shell; eseguirà il primo comando usando la solita procedura fork + exec, attenderà che esca, quindi eseguirà il secondo allo stesso modo. Tra i due comandi, c'è una quantità arbitraria di tempo che la shell impiega nella sua contabilità ed elaborazione, durante la quale avviene il multiprocessing ordinario e altri processi arbitrari possono fare altre cose arbitrarie. Quindi la risposta è no'. (Se lo fai effettivamente, scoprirai che la voce della directory somefilesvanisce, ma il file stesso rimane (poiché è aperto da un processo) fino alla sua chiusura. Lo spazio su disco utilizzato dal file non verrà recuperato fino a quando ciò non accadrà. Nel frattempo , il touchcomando creerà un nuovo file non correlato con lo stesso nome e percorso.)

Se vuoi cambiare la proprietà del file in root, fallo sudo chown root:root somefile(anche se non sono sicuro di come ciò influirà sui processi con un filehandle aperto su di esso). Se si desidera distruggere il contenuto del file corrente, provare truncate -s 0 somefile(il processo in esecuzione continuerà ad aggiungere al file ora vuoto). Se è qualcos'altro, forse chiarisci cosa vuoi fare.


Grazie Tom. Non ero molto preoccupato per la mia ipotetica situazione. Mi chiedevo solo se fosse possibile fare qualcosa del genere.
Darth Egregious,

Per quanto riguarda la domanda generale, non penso che ci sia davvero un modo per garantire l'atomicità in uno script di shell. È possibile utilizzare lockfile e simili per garantire che due processi cooperanti non si calpestino l'un l'altro e si possono usare le autorizzazioni per garantire che un processo arbitrario non possa calpestare il proprio lavoro. Ma impedire a qualcos'altro di funzionare sarebbe un grosso problema con il multiprocessing del kernel; Non credo che il codice ring-3 possa farlo.
Tom Hunt,

Puoi usare i blocchi di file obbligatori se sono abilitati e disponibili sul tuo filesystem.
roaima,

5
chowning alcuni file non influiranno sui processi che hanno un file handle per alcuni file.
PSkocik,

Ad esempio, puoi farlo exec 3>somefile; sudo chmod 0600 somefile; echo hello world >&3; sudo cat somefile; exec 3>&-.
PSkocik,

6

No. Un rmcomando seguito da un touchcomando non è affatto atomico. Ci vorrà molto tempo tra i due comandi, possibilmente nell'intervallo di millisecondi. Molto può succedere in quel periodo. Se sei sfortunato, le tue credenziali sudo potrebbero anche scadere.

Un singolo programma che chiama le chiamate unlinke openlascerebbe una finestra molto più breve per una gara, ma potrebbe ancora succedere.

Un approccio più sicuro sarebbe quello di creare il nuovo file con un nome temporaneo e utilizzare la renamechiamata di sistema. "Sovrascrivere" un nome con la renamechiamata di sistema è garantito per essere atomico. Questo potrebbe essere ottenuto usando touche mv.

Ma un processo che ha aperto il vecchio file per la scrittura può continuare a scriverlo per molto tempo dopo che è stato eliminato. Questo sarà il caso sia di un file eliminato usando unlinksia di uno eliminato usando rename.


3

Una volta che un processo ha un filehandle aperto per la lettura, non importa cosa fai con la proprietà o le autorizzazioni: il processo può continuare ad accedere al file. Puoi anche eliminare il file e il processo sarà in grado di continuare ad accedervi tramite il filehandle.

Considera le autorizzazioni come gate di controllo per ottenere un filehandle.

Se vuoi creare un file atomicamente, invece di farlo:

sudo rm somefile
sudo touch somefile

potresti considerare questo:

sudo touch anotherfile
sudo perl -e "rename 'anotherfile', 'somefile'"

che sostituirà atomicamente somefilecon anotherfile. (Avrei preferito usare, mv -fma non riesco a trovare un'istruzione che garantisca che questo chiama la rename(2)chiamata di sistema.


Forse potresti aggiornare la tua domanda per spiegare cosa intendi per "assumere il controllo del file". Potresti avere un problema XY qui.


Utilizzare mv -fper ricevere una rename(2)chiamata di sistema. Hai ragione ln, perché non usa sempre la link(2)chiamata di sistema, che non può sostituire atomicamente. ln -ffa solo unlink(2)sul bersaglio prima.
Peter Cordes,

@PeterCordes ah sì certo, grazie. Ho avuto lnil cervello. Non ero sicuro di come essere rename(2)garantito per essere coinvolto ed era troppo tardi per continuare a scavare
roaima,

POSIX garantisce che mv"deve eseguire azioni equivalenti a" rename(old, new). pubs.opengroup.org/onlinepubs/9699919799/utilities/mv.html . mv -fsi comporta come mv -ise la destinazione non fosse scrivibile, ma non è come cp -fo ln -fdove prima si scollegherà.
Peter Cordes,

2

No ma

sudo rm somefile; sudo touch somefile

è sicuro nella maggior parte delle situazioni.

La maggior parte dei processi apre i file e quindi utilizza il descrittore di file acquisito per accedere al contenuto del file.

Se un processo apre un file, in sh:

 exec 3>somefile

Quindi un altro processo è libero di scollegare (= rimuovere) un file e il descrittore di file su cui un file è stato aperto dal primo processo (3 in questo caso) continuerà a fare riferimento al contenuto originale di un file, che ora è un file in un limbo.

sudo touch somefile

creerà un nuovo file non correlato e tutti i processi che avevano il vecchio file aperto e ora stanno usando solo uno script di file per riferirsi ad esso non saranno interessati perché si riferiscono a un file diverso - uno che è ora in un limbo.

Se un processo non root tenta di fare riferimento a un file per nome, riceverà un errore EPERM, poiché il nuovo file è di proprietà di root.

Se vuoi impedire che più processi sotto lo stesso utente (es. Root) corrompano un file, Linux ha il blocco obbligatorio e consultivo dei file. È possibile utilizzare il flockcomando negli script shell per il blocco dei file di avviso (consultare la manpage per ulteriori informazioni).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.