Çalışan bir programı Ubuntu'da taşımak neden mümkün?


24

Çalışan bir programı farklı bir dizine taşıyabileceğimi farkettim. Tecrübelerime göre bu MacO'larda veya Windows'ta mümkün değildi. Ubuntu'da nasıl çalışır?

Düzenleme: Mac'te mümkün olmadığını düşündüm ancak görünüşe göre yorumların doğrulanması mümkün. Belki sadece Windows'ta mümkün değildir. Tüm cevaplar için teşekkürler.


2
Hemen hemen bir çapraz site dupe: stackoverflow.com/a/196910/1394393 .
jpmc26

1
rename(2)OS X'de çalışan bir yürütülebilir dosya olamaz mı? Ne oldu, anladın EBUSYmı? Neden çalışmıyor Rename (2) man sayfası ETXTBUSYbu sistem çağrısı için belge oluşturmaz ve sadece EBUSYdizin isimleri için mümkün olabileceğinden bahseder , böylece bir POSIX sisteminin yeniden adlandırılabilir çalıştırılabilir dosyaları bile devre dışı bırakabileceğini bilmiyordum.
Peter Cordes

3
macOS uygulamaları da çalıştırılırken taşınabilir, ancak çöpe atılmazlar. Bazı uygulamaların, bundan sonra, örneğin, dosya URL'lerini NSBundle ve ark. MacOS'un POSIX uyumluluğu olduğundan şüpheleniyorum.
Constantino Tsarou,

1
Aslında Linux'un niyetinde olduğu gibi çalışır, ne yaptığınızı bilmelisiniz. : P
kullanıcıAğustos

2
Sanırım bunu düşünmenin başka bir yolu da, neden mümkün olmasın ? Sadece Windows size izin vermediğinden, süreçlerin nasıl çalıştığı ya da bir şey yüzünden temelde mümkün olmadığı anlamına gelmez.
Thomas

Yanıtlar:


32

Ayrılmama izin ver.

Bir yürütülebilir dosyayı çalıştırdığınızda, en önemlisi fork()ve bir dizi sistem çağrısı yürütülür execve():

  • fork()Her ikisi de hala aynı yürütülebilir dosyayı çalıştıran (üzerine yazılan bellek sayfalarını kullanarak, bu nedenle etkilidir) (çoğunlukla) ebeveynin tam bir kopyası olan çağrı sürecinin alt sürecini oluşturur. İki kez döner: Ebeveynde, alt PID değerini döndürür. Çocukta 0 döndürür. Normalde, çocuk işlemi hemen yürütme çağırır:

  • execve()yürütülebilir dosyaya tam bir yol olarak argüman olarak gider ve çağıran işlemi yürütülebilir ile değiştirir. Bu noktada, yeni oluşturulan süreç kendi sanal adres alanını, yani sanal belleği alır ve yürütme giriş noktasında başlar (platform ABI'nin yeni işlemler için kuralları tarafından belirtilen bir durumda).

Bu noktada, çekirdeğin ELF yükleyicisi, sistem çağrısını kullanıyormuşçasına (sırasıyla paylaşılan salt okunur ve özel okuma-yazma eşleşmeleriyle birlikte) çalıştırılabilir metin ve veri bölümlerini belleğe mmap()eşlemiştir. BSS ayrıca MAP_ANONYMOUS ile eşleştirilir. (BTW, basitlik için buradaki dinamik bağlantıyı görmezden geliyorum: Dinamik bağlayıcı , ana çalıştırılabilir giriş noktasına atlanmadan önce tüm dinamik kitaplıkları open()s ve mmap()s.)

Yeni bir exec () ed kendi kodunu çalıştırmaya başlamadan önce sadece birkaç sayfa aslında diskten belleğe yüklenir. İşlem sanal adres alanının bu kısımlarına dokunduğunda / gerektiğinde, gerektiğinde sayfalar talep edilir. (Kullanıcı alanı kodunu çalıştırmaya başlamadan önce herhangi bir kod veya veri sayfasını önceden yüklemek sadece bir performans optimizasyonudur.)


Yürütülebilir dosya inode tarafından alt seviyedeki tanımlanır. Dosya çalıştırılmaya başladıktan sonra, çekirdek dosya içeriğini açık dosya tanımlayıcıları veya dosya destekli bellek eşlemeleri gibi dosya adıyla değil inode referansı ile aynı tutar. Böylece, yürütülebilir dosyayı dosya sisteminin başka bir yerine, hatta farklı bir dosya sisteminde kolayca taşıyabilirsiniz. Bir yan not olarak, sürecin çeşitli stat'lerini kontrol etmek için /proc/PID(PID verilen işlemin İşlem Kimliğidir) dizine göz atabilirsiniz . Yürütülebilir dosyayı /proc/PID/exebile diskten bağlantısı kesilmiş olarak açabilirsiniz .


Şimdi harekete geçelim:

Bir dosyayı aynı dosya sistemi içinde taşıdığınızda rename(), dosyayı başka bir isimle yeniden adlandıran çalıştırılan sistem çağrısı , dosyanın inode işlevi aynı kalır.

İki farklı dosya sistemi arasında iki şey olur:

  • Dosyanın içeriği önce ve sonra yeni konuma kopyalanır read()vewrite()

  • Bundan sonra, dosya kullanılarak kaynak dizinden bağlantı kaldırılır unlink()ve dosya açıkça yeni dosya sisteminde yeni bir inode alır.

rmaslında unlink()verilen dosyayı dizin ağacından ayırmak, dizinde yazma iznine sahip olmanız, bu dizinden herhangi bir dosyayı çıkarmanız için yeterli hakkı sağlayacaktır.

Şimdi eğlenmek için, iki dosya sistemi arasında dosya taşırken neler olduğunu unlink()ve dosyaya kaynaktan izin almadığınızı hayal edin.

Peki, dosya ilk başta ( read(), write()) hedefe kopyalanacak ve ardından unlink()yetersiz izin nedeniyle başarısız olacaktır. Böylece, dosya her iki dosya sisteminde de kalacaktır !!


5
Biraz sanal ve fiziksel belleği karıştırıyorsunuz. Programın fiziksel belleğe yüklenme şeklindeki açıklamanız yanlış. Exec sistem çağrısı, bir çalıştırılabilir dosyanın çeşitli bölümlerini fiziksel belleğe kopyalamaz, ancak yalnızca işlemi başlatmak için gerekli olanı yükler. Daha sonra, talep edilen sayfalar talep üzerine, muhtemelen uzun zaman sonra yüklenir. Yürütülebilir dosya baytları işlem sanal belleğinin bir parçasıdır ve işlemin ömrü boyunca okunabilir ve muhtemelen tekrar okunabilir.
jlliagre

@jlliagre Düzenlendi, umarım şimdi açıklığa kavuşturulur. Teşekkürler.
heemayl

6
"İşlem artık dosya sistemini kullanmıyor" ifadesi hala sorgulanabilir.
jlliagre

2
Dosya sistemindeki belirli bir dosyanın doğrudan dosya adıyla tanımlanmadığının temel anlayışı çok daha net olmalıdır.
Thorbjørn Ravn Andersen

2
Güncellemenizde hala yanlışlıklar var. mmapVe unmapsistem çağrıları yüke kullanılan ve işletim sistemi RAM daha iyi başka bir şey için kullanılacak hissettiğinde sayfalar bellekten boşaltılır, onları bir sayfa hatası oluşturmak erişirken sayfalar çekirdek tarafından yüklenen, talep üzerine sayfaları boşaltmak değildir. Bu yükleme / boşaltma işlemlerinde sistem çağrısı yapılmaz.
jlliagre

14

Eh, bu oldukça ileri doğru. / Usr / local / bin / whoopdeedoo adında bir çalıştırılabilir dosya alalım. Bu sadece inode (Unix Filesystems üzerindeki dosyaların temel yapısı) olarak adlandırılan bir referanstır . "Kullanımda" olarak işaretlenen inode'dur.

Şimdi / usr / local / whoopdeedoo dosyasını sildiğinizde veya taşıdığınızda, taşınan (veya silinen) tek şey inode'a yapılan referanstır. İnode'un kendisi değişmeden kalır. Temel olarak bu.

Bunu doğrulamalıyım, ancak bunu Mac OS X dosya sistemlerinde de yapabileceğinizi düşünüyorum.

Windows farklı bir yaklaşım getiriyor. Niye ya? Kim bilir...? NTFS'nin içindekileri tanımadım. Teorik olarak, dosya adları için iç yapılara referans kullanan tüm dosya sistemlerinin bunu yapabilmesi gerekir.

Kabul ediyorum, aşırı derecede basitleştirdim, ama gidip Wikipedia'dan "Etkiler" bölümünü okudum ve benden çok daha iyi bir iş çıkardı.


1
Yürütülebilir dosyayı başlatmak için Windows'ta bir kısayol kullanıyorsanız, kısayolu da silebilirsiniz, eğer öyle karşılaştırmak istiyorsanız, belki? = 3
Ray

2
Hayır, bu sembolik bir bağı silmek gibi olur. Diğer yorumlarda bir yerde, davranışın FAT dosya sistemleriyle eski desteğe bağlı olduğu belirtiliyor. Muhtemel bir sebep gibi geliyor.
jawtheshark

1
Bunun özellikle inode ile ilgisi yok . NTFS dosya durumunu izlemek için MFT kayıtlarını kullanır ve FAT bunun için dizin girişlerini kullanır, ancak Linux yine de kullanıcının bakış açısından bu dosya sistemlerinde aynı şekilde çalışır.
Ruslan,

13

Diğer tüm cevaplar eksik görünüyor tek şey şudur: Bir dosya açtı ve bir program dosyası olacak bir açık dosya tanıtıcı tutan bir kez değil o dosya tanıtıcı kapatılana kadar sistemden çıkarılmalıdır.

Başvurulan inode'u silme girişimleri dosya kapanana kadar ertelenir: aynı veya farklı bir dosya sisteminde yeniden adlandırmak açık dosyayı etkilemez, yeniden adlandırma davranışından bağımsız olarak veya dosyayı yeni bir dosyayla açıkça siler veya üzerine yazar. Bir dosyayı karışık hale getirmenin tek yolu, dosyayı yeniden adlandırma / silme gibi işlemlerle değil, dizinini açıkça açıp içeriğiyle karıştırmaktır.

Ayrıca, çekirdek bir dosyayı çalıştırdığında, yürütülebilir dosyaya bir referans tutar ve bu, yürütme sırasında herhangi bir şekilde değiştirilmesini önler.

Yani sonunda o bile benziyor program bitene kadar aslında bu dosyaların içeriğini bellekte tutulur çalışan bir programı oluşturan dosyaları taşımak / silmek mümkün olduğunu.


1
Bu doğru değil. execve()Herhangi bir FD döndürmez, sadece programı çalıştırır. Koşarsan Yani örneğin, tail -f /foo.logdaha sonra FD (onların /proc/PID/fd/<fd_num>ilişkili) tailiçin foo.logdeğil yürütülebilir kendisi için, taildeğil kendi üst yanı. Bu, tek çalıştırılabilir dosyalar için de geçerlidir.
heemayl

@heemayl Bahsetmedim, execvebu yüzden bunun nasıl alakalı olduğunu göremiyorum. Çekirdek bir dosyayı çalıştırmaya başladığında, dosyayı değiştirmeye çalışmak programı değiştirmeyecek, çekirdeği nokta çekimi yaparak yükleyecektir. Çalıştırılabilir durumdayken yürütülebilir dosyayı "güncellemek" istiyorsanız execve, çekirdeğin dosyayı yeniden okumasını sağlamak için bir noktada çağrı yapabilirsiniz, ancak bunun nasıl önemli olduğunu anlamıyorum. Mesele şu ki: "çalışan bir çalıştırılabilir dosya" silmek, çalıştırılabilir durana kadar veri silmeyi gerçekten tetiklemez.
Bakuriu

Bu rolde bahsediyorum programı tek bir yürütülebilir dosya oluşuyorsa program dizininde herhangi bir değişiklik ince bağımsız çalışır yürütme başladıktan sonra: Aynı veya farklı dosya sisteminde yeniden adlandırma etkileyemez açık işleyicisi , mutlaka konuşuyorsun hakkında execve()ve bu davada FD bulunmadığında bir FD.
heemayl

2
Dosyaya atıf yapmak için bir dosya tanıtıcısına ihtiyacınız yoktur; sayfaların eşlenmesi de yeterlidir.
Simon Richter

1
Unix'in "dosya tanıtıcıları" yok. heemayl'ın burada konuştuğu open()dosya tanıtıcısını döndürür execve(). Evet, çalışan bir işlemin yürütülebilir dosyasına bir referansı var, ancak bu bir dosya tanıtıcısı değil. Muhtemelen munmap(), çalıştırılabilir kodunun tüm eşlemelerini yazsa bile , hala inode'un serbest kalmasını durduran bir referansı (/ proc / self / exe olarak yansıtılmış) olacaktır. (Bu, asla geri dönmeyen bir kütüphane işlevinden yaptıysa çökme ile mümkün olabilir.) BTW, kullanımdaki bir yürütülebilir dosyayı kesme veya değiştirme size verebilir ETXTBUSY, ancak işe yarayabilir.
Peter Cordes

7

Bir Linux dosya sisteminde, bir dosyayı taşıdığınızda, dosya sistemi sınırlarını aşmadığı sürece (okuma: aynı diskte / bölümde kalır) değiştirdiğiniz tek şey .., yeni konumun (ana dizin) inode'udur. . Gerçek veri diskte hiç hareket etmedi, sadece işaretçi, böylece dosya sistemi onu nerede bulacağını biliyor.

Bu nedenle taşıma işlemleri çok hızlı ve büyük olasılıkla programın kendisini taşımadığınız için çalışan bir programın taşınmasında sorun yok.


Cevabınız, bir ikili dosyayı çalıştırılabilir dosyayı başka bir dosya sistemine taşımak anlamına geliyor gibi görünüyor.
jlliagre

6

Bir programın taşınması, başlatılarak başlatılan çalışan işlemleri etkilememesi nedeniyle mümkündür.

Bir program başlatıldığında, diskteki bitleri üzerine yazılmaya karşı korunur, ancak dosyanın yeniden adlandırılması, aynı dosya sisteminde farklı bir konuma taşınması, dosyanın yeniden adlandırılması veya taşınmasıyla eşdeğer olması gerekmez. dosyayı başka bir yere kopyalamakla eşdeğer olan farklı bir dosya sistemine, sonra da onu kaldırın.

Bir işlemin üzerinde açık bir dosya tanımlayıcısı olduğundan veya bir işlemin yürütüldüğü için kullanımda olan bir dosyayı kaldırmak, dosya inode tarafından başvuruda kalan dosya verilerini kaldırmaz, ancak yalnızca dizin girişini kaldırır, yani inode'a ulaşılabilecek bir yol.

Bir programı başlatmanın her şeyi bir kerede (fiziksel) belleğe yüklemediğini unutmayın. Bunun tersine, sadece sürecin başlaması için gereken asgari yük yüklenir. Ardından, işlemin ömrü boyunca talep üzerine istenen sayfalar yüklenir. Buna talep çağrı çağrısı denir. RAM yetersizliği varsa, işletim sistemi bu sayfaları tutan RAM'i serbest bırakmakta serbesttir, böylece bir işlemin aynı sayfanın çalıştırılabilir inode'dan birden çok kez yüklenmesi iyi olur.

Windows ile mümkün olmama nedeni, temelde dosya sisteminin (FAT), dizin girişleri ve inode gibi bölünmüş dizin kavramını desteklememesi nedeniyle büyük olasılıkla muhtemeldir. Bu sınırlama NTFS ile artık mevcut değildi, ancak işletim sistemi tasarımı uzun süredir kullanılmaya başlandı, bu da Windows'un yeni sürümleri için geçerli olmayan bir ikili dosya sürümünü kurarken yeniden başlatılması gereken zorlayıcı bir kısıtlamaya yol açtı.


1
Windows'un yeni sürümlerinin yeniden başlatılmadan kullanılan ikili dosyaları değiştirebileceğine inanıyorum.
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersen Tüm güncellemelerin neden hala yeniden başlatılmasını gerektirdiğini merak ediyorum:
Braiam,

1
@Braiam Onlar değil. Daha yakından bir göz atın. İkili dosyalar güncellenebilse de, çekirdek (bilmediğim kadarıyla) yapamaz ve daha yeni bir sürümle değiştirilmek için yeniden başlatma gerektirir. Bu, çoğu işletim sistemi çekirdekleri için geçerlidir. Çalışırken bir Linux çekirdeğini yamalayabilen Linux için kpatch yazdığımdan daha zeki insanlar - bkz. En.wikipedia.org/wiki/Kpatch
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersen "Tüm Windows güncellemelerini" kastettim
Braiam

@Braiam evet - ben de öyle. Lütfen daha yakından bir göz atın.
Thorbjørn Ravn Andersen

4

Temel olarak, Unix ve ilklerinde, bir dosyayı açarken ilişkilendirmek / bulmak için bir dosya adı (kendisine giden dizin yolu dahil) kullanılır (bir dosyayı çalıştırmak bir şekilde açmanın bir yoludur). Bu andan sonra, dosyanın kimliği ("inode" aracılığıyla) kurulur ve artık sorgulanmaz. Dosyayı kaldırabilir, yeniden adlandırabilir, izinlerini değiştirebilirsiniz. Herhangi bir işlem veya bir dosya yolu bu dosya / inode üzerinde bir tutamağa sahip olduğu sürece, işlemler arasında bir boru gibi yapışacaktır (aslında, tarihi UNIX'te bir boru , sadece içine yerleştirilmiş bir büyüklükte isimsiz bir inode idi) inode'da "doğrudan bloklar" disk depolama referansı, 10 blok gibi bir şey).

Bir PDF dosyasına açık bir PDF görüntüleyiciniz varsa, bu dosyayı silip aynı ada sahip yeni bir dosyayı açabilirsiniz ve eski görüntüleyici açık olduğu sürece eski dosyaya erişmeye devam eder (aktif olarak izleyenler dışında) dosyanın orijinal adı altında kaybolduğunu fark etmek için dosya sistemi).

Geçici dosyalara ihtiyaç duyan programlar, böyle bir dosyayı bir ad altında açabilir ve daha sonra hala açıkken derhal (ya da dizin girdisini) kaldırabilir. Daha sonra dosyaya adla erişilemiyor, ancak dosyaya açık bir dosya tanıtıcısına sahip herhangi bir işlem dosyaya hala erişebiliyor ve daha sonra programdan beklenmeyen bir sonuç çıkması durumunda, dosya kaldırılacak ve depolama alanı otomatik olarak kurtarılacak.

Bu nedenle, bir dosyanın yolu dosyanın kendisinin bir özelliği değildir (aslında, sabit bağlantılar bu gibi birkaç yolu sağlayabilir) ve zaten açık olan işlemler tarafından sürekli erişim için değil, dosyayı açmak için gereklidir.

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.