mv 與 cp:產生的檔案有什麼不同?

mv 與 cp:產生的檔案有什麼不同?

我遇到了一個錯誤,某些應用程式的設定檔未正確包含,因此為了嘗試隔離檔案中有問題的行,我將舊內容一次複製幾行到新檔案中。

最後,我已經製作了該文件的精確副本,但舊文件仍然無法工作,而新文件則運作得很好。

更重要的是,如果我使用該mv命令將文件從儲存位置移動到它想要的位置,則會導致錯誤。如果我用來cp將文件複製到它想要的位置,則不會出現錯誤。

顯然,諸如difffile、 或 之類的內容ls -l表明兩個文件之間沒有差異,因為一個是另一個文件的副本,只要cp製作文件的精確副本

我無法分享太多有關該文件的信息,因為這是工作內容。底線是命令cp fileA fileB產生mv fileA fileB一個“不同的”檔案B。我最好的猜測是 fileB 中的一些超低級屬性在期間被遺留下來cp(甚至cp -p產生相同的行為)。

mv 與 cp 的作用有何不同,與結果檔案的確切內容有關?

編輯:與ls -l

-rw-r--r--. 1 root root 3389 Aug  8 22:53 fileA
-rw-r--r--. 1 root root 3389 Aug  8 23:03 fileB

編輯:應用程式是 mysql,文件是 .cnf 文件,此設定檔中特別感興趣的項目是主從資料庫複製中使用的二進位日誌的名稱。 “錯誤”是“您沒有使用二進位日誌記錄”,因為沒有二進位日誌,因為該專案從未被 mysql“讀取”。

我最初的想法是設定檔中存在語法錯誤,導致整個文件無法讀取,這導致我透過複製文字區塊手動重新建立它

編輯:到達某處...最後文件有所不同。

ls -lZ

-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 server.cnf.bad
-rw-r--r--. root root unconfined_u:object_r:mysqld_etc_t:s0 server.cnf.good

答案1

TL;DR:在一個系統中SELinuxcp -aZ在使用中,系統使用的檔案(即:守護程式)應該使用和mv -Z而不是cp -a和來複製或移動mv。如果沒有這樣做,則應該在目標上使用restorecon -v -rrestorecon -v -F -r來要求系統恢復預設的 SELinux 上下文。使用總是一個好主意restorecon在處理關鍵設定檔的腳本的末尾。

RHEL 及其大多數衍生產品預設使用 SELinux

因此,要解決您的問題,如果您的系統是基於 RHEL 並使用該mariadb-server軟體包,只需在檔案中位於正確的地方

# restorecon -v -F /etc/my.cnf.d/server.cnf
Relabeled /etc/my.cnf.d/server.cnf from unconfined_u:object_r:user_home_t:s0 to system_u:object_r:mysqld_etc_t:s0

(請注意,如果沒有-F它,就不會更改unconfined_u為已配置的system_u。對於常見系統來說,這並不重要。我對差異以及為什麼它不重要的了解還沒有走到這一步)。

將正確的上下文放入文件中將需要更多工作其他地方。chcon可以做到這一點(透過使用等來聲明-u -t,更簡單地透過使用從其他文件複製上下文--reference):

# ls -lZ /home/test/server.cnf.bad
-rw-r--r--. 1 root root unconfined_u:object_r:user_home_t:s0 744 Apr 30  2017 /home/test/server.cnf.bad
# chcon -v -u system_u -t mysqld_etc_t /home/test/server.cnf.bad 
changing security context of '/home/test/server.cnf.bad'
# ls -lZ /home/test/server.cnf.bad
-rw-r--r--. 1 root root system_u:object_r:mysqld_etc_t:s0 744 Apr 30  2017 /home/test/server.cnf.bad

如果您懷疑 SELinux 有問題,請檢查是否有與您的進程或檔案相關的/var/log/audit/audit.log單字的條目。denied您始終可以暫時要求 SELinux 允許操作,然後恢復它們,分別與setenforce Permissivesetenforce Enforcing進行比較行為。Permissive特別是在生產時不要保留。

以下各種解釋...

範例以及處理設定檔時應該做什麼

cp具有各種選項且mv在啟用 SELinux 的系統上的行為範例:

$ id
uid=1034(test) gid=1034(test) groups=1034(test)
$ pwd
/home/test
test@glasswalker:~$ ls -lZ foo
-rw-r--r--. 1 test test unconfined_u:object_r:user_home_t:s0 0 Aug 11 11:25 foo
$ cp foo /tmp/foo1
$ cp --preserve=context foo /tmp/foo2
$ cp -a foo /tmp/foo3
$ cp -aZ foo /tmp/foo4
$ mv foo /tmp/foo5
$ ls -lZ /tmp/foo?
-rw-r--r--. 1 test test unconfined_u:object_r:user_tmpfs_t:s0 0 Aug 11 11:25 /tmp/foo1
-rw-r--r--. 1 test test unconfined_u:object_r:user_home_t:s0  0 Aug 11 11:25 /tmp/foo2
-rw-r--r--. 1 test test unconfined_u:object_r:user_home_t:s0  0 Aug 11 11:25 /tmp/foo3
-rw-r--r--. 1 test test unconfined_u:object_r:user_tmpfs_t:s0 0 Aug 11 11:25 /tmp/foo4
-rw-r--r--. 1 test test unconfined_u:object_r:user_home_t:s0  0 Aug 11 11:25 /tmp/foo5
$ touch bar
$ ls -lZ bar
-rw-r--r--. 1 test test unconfined_u:object_r:user_home_t:s0 0 Aug 11 11:49 bar
$ mv -Z bar /tmp
$ ls -lZ /tmp/bar
-rw-r--r--. 1 test test unconfined_u:object_r:user_tmpfs_t:s0 0 Aug 11 11:49 /tmp/bar

因此,當安全上下文確實很重要並且仍然保留其他屬性時,使用cp -aZor可以很好地工作。mv -Z移動系統檔案的腳本應始終使用-Z任何cpmv命令的選項,否則僅restorecon在最後一步中使用以避免意外問題。

為什麼會有這些差異?

mv命令保持一致的行為。如果它發生在同一個檔案系統中,當然,附加到檔案的任何內容(包括其安全上下文)都不會改變,因為它只是「重新命名」。因此,在兩個檔案系統中,它實際上是一個副本然後刪除,它還會複製未更改的附加到檔案的所有內容以及它知道的內容,包括其安全上下文,以保持一致性。

cp命令預設只是創造一個新文件,因此該文件照常繼承父級的 selinux 上下文,除非另有說明,--preserve=context其中包含在-a.可以使用該選項--preserve=context進行減去,因此複製整個樹狀圖時最好的選擇是使用而不是使用 SELinux 確實重要。-a-Z-aZ-a

預設情況下,在建立檔案時(這是通常的情況),這個新檔案繼承其目錄 SELinux 上下文,這就是為什麼一切正常(題外話:在極少數情況下,檔案上下文應該與其目錄上下文不同,只是因為規則其名稱,核心不會關心,像守護程式這樣的程序restorecond將需要處理它)。

什麼是 SELinux

SELinux 是一種強制存取控制機制(又稱蘋果)除了所有其他機制(unix 權限又名數位類比轉換器,存取控制清單又名前十字韌帶ETC。當進程在進程安全性上下文中運行時,有一個「規則矩陣」來檢查這是否過程上下文可以執行所要求的操作(打開,讀取,寫入,mmap,...)文件它試圖發揮作用的背景。

OP 案例的範例:如果mysqld的進程上下文僅允許存取少數檔案上下文類型(包括mysqld_etc_t但不包括) ,user_home_t則啟動mysqld將失敗,因為它無法讀取錯誤user_home_t類型的設定檔。

在通常的系統上,這對於互動式/登入使用者來說並不重要,因為它通常的進程上下文是不受限制的,這意味著不會應用任何 SELinux 規則。由systemd或其他類似機制啟動的每個守護程式將要接收進程上下文,可以使用ps-Z選項進行檢查。運行 SELinux 的 Debian 系統上的範例:

# ps -Z -p $$
LABEL                             PID TTY          TIME CMD
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 22498 pts/7 00:00:00 bash
# ps -Z -p $(pidof /sbin/getty)
LABEL                             PID TTY      STAT   TIME COMMAND
system_u:system_r:getty_t:s0     6158 tty1     Ss+    0:00 /sbin/getty 38400 tty1
system_u:system_r:getty_t:s0     6159 tty2     Ss+    0:00 /sbin/getty 38400 tty2
system_u:system_r:getty_t:s0     6160 tty3     Ss+    0:00 /sbin/getty 38400 tty3
system_u:system_r:getty_t:s0     6161 tty4     Ss+    0:00 /sbin/getty 38400 tty4
system_u:system_r:getty_t:s0     6162 tty5     Ss+    0:00 /sbin/getty 38400 tty5
system_u:system_r:getty_t:s0     6163 tty6     Ss+    0:00 /sbin/getty 38400 tty6

答案2

是的,有一個主要區別:

  • cp 複製文件
  • mv(如果您留在檔案系統內)只是移動磁碟上的一些指標。

請嘗試以下操作:

touch a
ls -i a
cp a b
ls -i a b
mv a c
ls -i b c

您將看到 b 是一個具有新 inode 編號的新文件,而 c 是具有舊 a 的 inode 編號的同一個文件。

儘管如此,這並不能解釋你奇怪的行為。

答案3

這是什麼可能正在發生(您分享的有關應用程式或這些錯誤的資訊很少,所以我只能猜測)。

在Linux中強製檔案鎖定並不常見。打電話就像flock(2)管理諮詢鎖。這意味著核心會追蹤鎖,但不會強制執行它們,而是由應用程式遵守它們。

如果某些東西鎖定fileA並且您的應用程式遵守該鎖定,則它可能會拒絕服務。讓我們假設這就是所發生的情況。

鎖影響索引節點而不是路徑或名稱。將鎖定的檔案移動(重新命名)fileAfileB單一檔案系統內對 inode 沒有任何作用,檔案仍然被鎖定,應用程式仍然拒絕使用它。複製檔案會建立一個單獨fileB的索引節點,未鎖定,應用程式可以正常運作。

(注意:將檔案移至另一個檔案系統實際上是複製+刪除,因此它應該打破鎖定(如果有)。

相關內容