İşlem çıkışından sonra otomatik olarak yok edilen geçici klasör


Yanıtlar:


12

Geçici bir dosya söz konusu olduğunda, sorunuzdaki örnek onu oluşturur, daha sonra dizinden bağlantısını keser ("kaybolmasını sağlar") ve komut dosyası dosya tanımlayıcıyı kapattığında (muhtemelen sonlandırıldığında), dosya tarafından alınan alan sistem tarafından geri alınabilir. Bu, C gibi dillerde geçici dosyalarla başa çıkmanın yaygın bir yoludur.

Bildiğim kadarıyla, bir dizini aynı şekilde açmak mümkün değildir, en azından dizini kullanılabilir hale getirecek hiçbir şekilde değildir.

Bir komut dosyasının sonlandırılması sırasında geçici dosyaları ve dizinleri silmenin yaygın bir yolu, bir temizleme EXITtuzağı kurmaktır. Aşağıda verilen kod örnekleri dosyalanmış tanımlayıcıları tamamen dengelemekten kaçınır.

tmpdir=$(mktemp -d)
tmpfile=$(mktemp)

trap 'rm -f "$tmpfile"; rm -rf "$tmpdir"' EXIT

# The rest of the script goes here.

Veya bir temizleme işlevi çağırabilirsiniz:

cleanup () {
    rm -f "$tmpfile"
    rm -rf "$tmpdir"
}

tmpdir=$(mktemp -d)
tmpfile=$(mktemp)

trap cleanup EXIT

# The rest of the script goes here.

EXITTuzak alınması üzerine icra edilmez KILLhiçbir temizlik sonra gerçekleştirilen olacağı aracı (tuzak edilemez) bir sinyal. Bununla birlikte, bir INTveya TERMsinyali nedeniyle sonlandırıldığında ( bashveya kshbaşka kabuklarda çalışıyorsa EXIT, trapkomut satırından sonra bu sinyalleri eklemek isteyebilirsiniz ) veya komut dosyasının sonuna gelmesi veya exitaramak.


5
Zaten bağlantısı kaldırılmış geçici dizinleri kullanamayan bir kabuk değil, C programları da kullanamaz. Sorun, bağlantısız dizinlerin içinde dosya bulunmamasıdır. Çalışma dizininiz olarak bağlantısı kaldırılmış boş bir dizine sahip olabilirsiniz, ancak herhangi bir dosya oluşturma girişimi hata verir.
derobert

1
@derobert Ve böyle bir bağlantısız dizini .ve ..girişleri bile yok . (Linux'ta test edildi, bunun platformlar arasında tutarlı olup olmadığını bilmiyorum.)
kasperd


1
Komut dosyası exec another-commandaçıkça çağırıyorsa, EXIT tuzağının yürütülmediğini unutmayın .
Stéphane Chazelas


6

Betiğiniz bittiğinde yürütülecek bir kabuk işlevi yazın. Aşağıdaki örnekte buna 'temizleme' diyorum ve çıkış düzeylerinde yürütülecek bir tuzak ayarlıyorum, örneğin: 0 1 2 3 6

trap cleanup 0 1 2 3 6

cleanup()
{
  [ -d $TMP ] && rm -rf $TMP
}

Daha fazla bilgi için bu gönderiye bakın .


Bunlar şunlardır değil "çıkış seviyeleri" ama sinyal numaraları ve bağlantı verdiğiniz sorunun cevabı sadece olduğunu açıklar. Tuzak cleanuptemiz bir çıkıştan (0) önce ve SIGHUP (1), SIGINT (2), SIGQUIT (3) ve SIGABRT (6) alındığında çalışır. o olacak değil koşmak cleanupçünkü vb SIGTERM, SIGSEGV, SIGKILL, SIGPIPE, script çıkışları Bu açıkça yetersizliği olmasıdır.
mosvy

6

Daha sonra içindeki yolları kullanmaya çalışmamanız şartıyla içine girebilir ve kaldırabilirsiniz:

#! /bin/sh
dir=`mktemp -d`
cd "$dir"
exec 4>file 3<file
rm -fr "$dir"

echo yes >&4    # OK
cat <&3         # OK

cat file        # FAIL
echo yes > file # FAIL

Kontrol etmedim, ancak C dosyasında artık var olmayan bir dizinde openat (2) kullanırken aynı sorun büyük olasılıkla aynıdır.

Kök iseniz ve Linux'taysanız, ayrı bir ad alanı ile ve mount -t tmpfs tmpfs /diriçinde oynayabilirsiniz .

Komut dosyanız kirli bir çıkışa zorlanırsa (örn. SIGKILL ile) standart yanıtlar (EXIT üzerinde bir tuzak ayarlayın) çalışmaz; hassas verilerin etrafta asılı kalmasına neden olabilir.

Güncelleme:

İşte ad alanı yaklaşımını uygulayan küçük bir yardımcı program. İle derlenmelidir

cc -Wall -Os -s chtmp.c -o chtmp

ve verilen CAP_SYS_ADMINdosya yeteneklerini (root olarak)

setcap CAP_SYS_ADMIN+ep chtmp

Çalıştırıldığında (normal olarak) kullanıcı

./chtmp command args ...

dosya sistemi ad alanını paylaşmayacak, bir tmpfs dosya sistemini bağlayacak /proc/sysvipc, içine girecek commandve verilen argümanlarla çalışacaktır . commandolacak değil devralan CAP_SYS_ADMINyetenekleri.

Bu dosya sistemine, başlatılmayan başka bir işlemden erişilemez ve ne olursa olsun çocukları ve çocukları öldüğünde ( commandiçinde oluşturulan tüm dosyalarla) sihirli bir şekilde kaybolur command. Bunun yalnızca bağlanma ad alanını paylaşmadığına dikkat edin - commandaynı kullanıcı tarafından çalıştırılan diğer işlemler arasında zor engeller yoktur ; onlar hala aracılığıyla ya da isim alanı içinde gizlice ptrace(2), /proc/PID/cwdya da başka yöntemlerle.

"Yararsız" ın kaçırılması /proc/sysvipcelbette aptalca, ancak alternatif, /tmpkaldırılması veya bu küçük programı çatal ve beklemelerle büyük ölçüde karmaşıklaştırması gereken boş dizinlerle spam yapmak olurdu. Alternatif olarak, dirörn. /mnt/chtmpve kurulum sırasında root tarafından oluşturulmasını sağlayın; bunu kullanıcı tarafından yapılandırılabilir yapmayın ve kullanıcının sahip olduğu bir yola ayarlamayın; bu, sizi tuzaklara ve zaman harcamaya değmeyecek diğer tüylü şeylere maruz bırakabilir.

chtmp.c

#define _GNU_SOURCE
#include <err.h>
#include <sched.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mount.h>
int main(int argc, char **argv){
        char *dir = "/proc/sysvipc";    /* LOL */
        if(argc < 2 || !argv[1]) errx(1, "usage: %s prog args ...", *argv);
        argv++;
        if(unshare(CLONE_NEWNS)) err(1, "unshare(CLONE_NEWNS)");
        /* "modern" systemd remounts all mount points MS_SHARED
           see the NOTES in mount_namespaces(7); YUCK */
        if(mount("none", "/", 0, MS_REC|MS_PRIVATE, 0))
                err(1, "mount(/, MS_REC|MS_PRIVATE)");
        if(mount("tmpfs", dir, "tmpfs", 0, 0)) err(1, "mount(tmpfs, %s)", dir);
        if(chdir(dir)) err(1, "chdir %s", dir);
        execvp(*argv, argv);
        err(1, "execvp %s", *argv);
}

1
Kök olmasanız bile, bunu yeni bir kullanıcı ad alanı oluşturarak ve içine tmpfs bağlama yaparak ad alanlarıyla yapabilirsiniz. Yeni dünyaya dış dünyaya kaçakçılık yapmak biraz zor ama mümkün olmalı.
R .. GitHub BUZA YARDIMCI DURDUR

Bu hala CAP_SYS_ADMIN gerektirir. Bunu yapacak küçük setcap özellikli bir yardımcı program fikrim var, cevabı onunla güncelleyeceğim.
qubert

1
Çekirdek izin vermemek üzere kilitlenmedikçe, kullanıcı ad alanlarının oluşturulması ayrıcalıklı bir işlem değildir. Temel tasarım, sıradan kullanıcıların herhangi bir özel yetenek olmadan yapmasına izin vermenin güvenli olacağı şekildedir. Ancak yeterli dağıtım yüzeyi / birçok dağıtımın devre dışı bırakma riski olduğunu düşünüyorum.
R .. GitHub BUZA YARDIMCI DURDUR

Terminalde denedim. Bazı geçici direklerde, rm $PWDiş, kabuk hala o dir. Ancak bu "klasöre" yeni dosya yerleştirilemez. Sadece & 3, & 4 dosyası ile okuma / yazma yapabilirsiniz. Yani bu hala "geçici dosya", "geçici klasör" değil.
Bob Johnson

@BobJohnson Bu, cevabımda söylediğimden farklı değil ;-)
qubert

0

Belirli bir mermiye mi ihtiyacınız var?

Zsh bir seçenekse, lütfen okuyun zshexpn(1):

<(...) yerine = (...) kullanılırsa, bağımsız değişken olarak iletilen dosya, liste işleminin çıktısını içeren geçici bir dosyanın adı olur. Bu , girdi dosyasında lseek(bkz. lseek(2)) Olmasını bekleyen bir program için <formu yerine kullanılabilir .

[...]

Başka bir sorun, ikame içeren bir komutun bulunduğu yerde &!veya &|sonunda görünen durum da dahil olmak üzere, geçici bir dosya gerektiren bir işin kabuk tarafından reddedildiği her zaman ortaya çıkar . Bu durumda, kabuk artık işin belleğine sahip olmadığından geçici dosya temizlenmez. Geçici bir çözüm, örneğin bir alt kabuk kullanmaktır.

(mycmd =(myoutput)) &!

çatallı alt kabuk komutun bitmesini bekleyecek ve geçici dosyayı kaldıracaktır.

Bir işlem ikamesinin uygun bir süre boyunca devam etmesini sağlamak için genel bir çözüm, bunu anonim bir kabuk işlevine (işlev kapsamıyla hemen çalıştırılan bir kabuk kodu parçası) bir parametre olarak iletmektir. Örneğin, bu kod:

() {
   print File $1:
   cat $1
} =(print This be the verse)

aşağıdakine benzer bir şey çıkarır

File /tmp/zsh6nU0kS:
This be the verse

Örneğin, bir dosyanın şifresini çözmek ve daha sonra alt dosya sona erdiğinde silinir geçici dosya üzerinde tüfek çalıştırmak için tüfek (ranger dosya yöneticisinin bir parçası) kullanın. (ayarlamayı unutmayın $TERMCMD)

# ~/.config/ranger/rifle.conf
...
!ext exe, mime octet-stream$, has gpg, flag t = () { rifle -f F "$1" } =(gpg -dq "$1")
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.