還原git簽出檔案的修改時間

執行 git clone 以後取得的修改時間是當下執行的時間,所以其實是沒辦法去判斷哪個檔案是七天前修改的,或是十天前修改的。

Stackoverflow 上有人問了相同的問題:Git clone changes file modification time – Stack Overflow

有人就回答了,其實 git 裡面沒有保留檔案修改時間的資訊,但可以有個 tricky 的方法,就是透過 git log 的資訊來變更檔案的修改日期:

git ls-tree -r --name-only HEAD | while read filename; do
  unixtime=$(git log -1 --format="%at" -- "${filename}")
  touchtime=$(date -d @$unixtime +'%Y%m%d%H%M.%S')
  touch -t ${touchtime} "${filename}"
done

這邊主要用到幾個指令,說明如下

  • git ls-tree 是取出檔案名稱
  • git log -1 --format 是取出檔案提交的日期,這邊取出的是 timestamp 值
  • date -d 將 timestamp 值,轉換為日期時間格式。
  • touch -t 依據指定的日期格式去設定檔案的修改日期。

這邊要注意,目錄的修改時間不會被更動到。

透過以上的腳本,就可以還原git簽出檔案的修改時間,然後再搭配 find 指令來找出七天前修改的檔案了。

測試指定的套件會影響哪些套件

若是想知道指定的套件會影響哪些套件,這時候可以怎麼做呢?

我第一個是想到可以用 rpm ,用 man rpm 可以查到 rpm 有以下參數

  • –provides
  • –requires
  • –whatprovides
  • –whatrequires

所以就試試看

rpm -q --whatrequires libweb

但結果卻不如預期,上網找到這篇 centos – Why does rpm –whatrequires fail to report dependencies? – Unix & Linux Stack Exchange

才知道正確用法是這樣,要先用 rpm -q --provides libwebp 去查到 libwebp 有提供什麼capability,然後再用 rpm -q --whatrequires <capability> 去找。

例如 libwebp

[root@workstation ~]# rpm -q --provides libwebp
libwebp = 1.0.0-5.el8
libwebp(x86-64) = 1.0.0-5.el8
libwebp.so.7()(64bit)
libwebpdecoder.so.3()(64bit)
libwebpdemux.so.2()(64bit)
libwebpmux.so.3()(64bit)
[root@workstation ~]# rpm -q --whatrequires "libwebp.so.7()(64bit)"
libwebp-1.0.0-5.el8.x86_64
gd-2.2.5-7.el8.x86_64
ImageMagick-libs-6.9.12.50-2.el8.x86_64

這樣就可以找到,但若是如此,就要寫腳本了。因為 libwebp 有提供多個 capability ,需要逐一去查才行。

有沒有更快的方法呢?

centos – Why does rpm –whatrequires fail to report dependencies? – Unix & Linux Stack Exchange 裡面有提到可以用 rpm -e --test ,直接模擬看看移除。

rpm -e --test libwebp 2>&1 | grep needed | awk '{print $6}' | sort | uniq

這樣就可以很快找出來了。

ufw in archlinux

最近想試試看 wireguard,看了文件,都會提到用 ufw/firewalld 來配置網路,就想說,自家的 archlinux 都沒用防火牆,是不是該來用一下比較好。經過找 archlinux 文件以後,發現 archlinux 其實很自由,可以自由選 firewalld 或 ufw。在公司因為用 RHEL8 ,都是用 firewalld ,為了平衡一下還有家裡的其他電腦,決定就用 debian/ubuntu 的 ufw 。

ufw 的全名是 Uncomplicated firewall ,archlinux wiki 裡就有詳細的說明文件:https://wiki.archlinux.org/title/Uncomplicated_Firewall

安裝方法

用 yay 或 pacman 安裝

yay -S ufw

設定

安裝好以後,先不要啟用,要先設定。

sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw allow ssh

這幾行的意思是說,允許出去,禁止進來,只允許 ssh 服務的連線進來。

接著啟用

sudo ufw enable
sudo systemctl enable --now ufw

然後可以用 sudo systemctl status ufwsudo ufw status 檢查狀態。

接下來因為自己有用 http/https/gitlab/samba/squid 服務,也有使用 docker,所以要額外設置。

先允許 http/https 連線。

sudo ufw allow http
sudo ufw allow https

設置 docker 規則,docker 的部份有人寫好了,所以安裝套件以後再啟用即可。(ufw and docker),啟用以後,docker 容器有 expose 的 port 就會自動 allow。

yay -S ufw-docker
sudo ufw-docker install

再來是 samba,這也是有人寫好套件

yay -S ufw-extras
sudo ufw allow from 192.168.11.0/24 to any app samba

最後是 squid

sudo ufw allow from 192.168.11.0/24 to any port 3128 proto tcp

到這邊就設定完了,沒遇到什麼特別狀況。

參考資料

如何檢查RHEL有受到特定CVE影響?

因為好奇怎麼去查,就找到這篇:How to check if an RHEL system is vulnerable to a CVE ,文章裡面提到兩個方法。

第一個方法是用 rpm -q --changelog <套件> | grep <CVE_number>

舉個例子

rpm -q --changelog openssl | grep CVE-2021-3450

第二個方法是用 yum updateinfo info --cve <CVE_number>

舉個例子

yum updateinfo info --cve CVE-2021-3445

最後,想調查這台 RHEL 有受到哪些 Errata 影響,可以用

yum updateinfo info --summary
yum updateinfo info --list

若要帶入 CVE 資訊,可以用這兩個指令

yum updateinfo info --summary --with-cve
yum updateinfo info --list --with-cve

Red Hat 也有一篇 KB ,方法相似:https://access.redhat.com/solutions/3628301

不太一樣的地方是,指令是查看 rpm 的,所以是用

rpm -qp kernel-3.10.0-862.11.6.el7.x86_64.rpm --changelog | grep CVE-2017-12190

或者是用 yum list –cve <CVE_number>

yum list --cve CVE-2017-12190 | grep kernel.x86_64

找指定位置下的目錄

想找到指定位置下的目錄,但不要再深入。指定位置下的目錄是這樣的

/tmp/location
  +-- dir1
    + dir11
  +-- dir2
    + dir21
  foo.txt

我預期是只看到 dir1 跟 dir2,所以我用 find

find /tmp/location -type d -print

結果我找到的是

/tmp/location
/tmp/location/dir2
/tmp/location/dir2/dir21
/tmp/location/dir1
/tmp/location/dir1/dir11

find 的輸出跟我預期的不相符啊,我又不想用 ls 處理,後來找到 -maxdepth -mindepth 這兩個參數,搭配起來使用就可以了。

find /tmp/location -maxdepth 1 -mindepth 1 -type d -print

這樣就會是我需要的 dir1 跟 dir2

/tmp/location/dir2
/tmp/location/dir1

又學到一課,謝謝你 find

paps

之前使用 enscript 來將文字檔轉為 pdf,但實測發現,若文字檔裡面是中文,那麼轉出來是亂碼。

只好找其他的方案,找到的是 paps: https://github.com/dov/paps

paps 比較麻煩的是需要自己安裝,安裝說明可以參考:https://github.com/dov/paps/blob/master/INSTALL.md

我的環境是 Ubuntu 20.04

第一個是需要 meson,這個直接用 apt-get 安裝就可以

sudo apt install meson

第二個是 fmtlib ,Ubuntu 20.04 內的 fmtlib 版本過舊,這邊需要借助 backports

sudo add-apt-repository ppa:savoury1/backports
sudo apt install libfmt-dev

最後就是編譯

https://github.com/dov/paps.git
cd paps
meson build
cd build && ninja
sudo ninja install

這樣就可以得到 paps 了。

大量程式碼輸出為pdf

因為客戶文件需要,得把一堆檔案輸出為pdf。懶人如我,當然要找一下是不是有好的方法可以達成這個需求。

第一個找到的是 pandoc ,這個工具好是好,但遇到 Ansible playbook ,pandoc 會以為檔案是設定檔,就沒辦法輸出。

第二個找到的是 enscript ,這工具就可以很輕易的將文字檔轉換為 postscript 檔案,同時還可以加上語法高亮效果,但可惜語法高亮效果不支援 Ansible playbook 。有了 postscript 檔案,接下來就可以用 ps2pdf 將 postscript 檔案轉換為 pdf。

# Ubuntu
sudo apt install ps2pdf enscript
enscript playbook.yml doc.ps
ps2pdf doc.ps doc.pdf

現在可以處理單一個檔案以後,接下來要想怎麼處理多個檔案,這裡透過 find, xargs 跟 enscript 的協作就可以做到

find . -name '*.yml' -print | xargs enscript --output=doc.ps
ps2pdf doc.ps doc.pdf

不免俗,還要加上頁首跟頁尾,頁尾也要加上頁次,這部份需要為 enscript 加上自訂的頁首跟調整頁尾的高度。

mkdir ~/.enscript
cp /usr/share/enscript/simple.hdr ~/.enscript/my.hdr

然後修改 ~/.enscript/my.hdr

% -- code follows this line --
%Format: fmodstr        $D{%a %b %d %H:%M:%S %Y}
%Format: pagenumstr     $V$%
%FooterHeight: 15

/do_header {    % print default simple header
  % Footer
  gsave
    d_footer_x d_footer_y HFpt_h 3 div add translate
    HF setfont

    user_footer_p {
      d_footer_x  d_footer_y moveto user_footer_left_str show

      d_footer_w user_footer_center_str stringwidth pop sub 2 div
      0 moveto user_footer_center_str show

      d_footer_x d_footer_w add user_footer_right_str stringwidth pop sub
      d_footer_y moveto user_footer_right_str show
    } if
  grestore

  % Header
  gsave
    d_header_x d_header_y HFpt_h 3 div add translate

    HF setfont
    user_header_p {
      5 0 moveto user_header_left_str show

      d_header_w user_header_center_str stringwidth pop sub 2 div
      0 moveto user_header_center_str show

      d_header_w user_header_right_str stringwidth pop sub 5 sub
      0 moveto user_header_right_str show
    } {
      5 0 moveto fname show
      45 0 rmoveto fmodstr show
      45 0 rmoveto pagenumstr show
    } ifelse

  grestore
} def

產出 postscript 的指令改為

find . -name '*.yml' -print | xargs enscript --fancy-header=my --header='$N||' --footer='|$%/%p|' --output=doc.ps
ps2pdf doc.ps doc.pdf

產出以後,會發現頁碼怪怪的,頁碼只有針對個別檔案,不是整份檔案,這下就傷腦筋了。經過Google 的幫忙,找到 pdftk 來幫忙。pdftk 是一個可以操作 pdf 的工具,可以作合併、加浮水印等等的功能。

最後的成果如下

DOC_PS=/tmp/doc.ps
RAW_DOC_PDF=/tmp/raw_doc.pdf
DOC_PDF=/tmp/doc.pdf

# 產出 postscript 檔案
find collections/ansible_collections/gov/twgcb/roles -name '*.yml' -print | xargs enscript \
  --fancy-header=my \
  --header='$N||' \
  --footer='| |' \
  --output=${DOC_PS}

# 前個步驟有產出 ps 檔案
if [[ -f ${DOC_PS} ]]; then
  # 先轉為 pdf
  ps2pdf ${DOC_PS} ${RAW_DOC_PDF}
  # 取得頁數
  number_of_pages=$(pdftk /tmp/doc.pdf dump_data | grep NumberOfPages | sed 's/NumberOfPages: //g')
  # 印出
  echo "number_of_pages=${number_of_pages}"
  # 先產生一份空白的 pdf ,頁次重新編排,然後把這份 pdf 當作是前面產生的 pdf 的浮水印
  # 這樣頁次就是對的了。
  enscript -L1 --fancy-header=my --header='||' --footer '|$% / $=|' -o- < \
  <(for i in $(seq 1 $number_of_pages); do echo; done) | \
  ps2pdf - | \
  pdftk ${RAW_DOC_PDF} multistamp - output ${DOC_PDF}
fi

參考資料

[RHEL]grub設定密碼

以下指令可以避免讓使用者在開機時,可以調整 kernel 參數。若是在 kernel 參數填入 single 或 rescue ,使用者就有機會可以使用到較高的權限。

先用 grub2-setpassword 設定密碼,設定以後,/boot/grub2 資料夾裡會多出 user.cfg

grub2-setpassword 

再來重新產生 grub.cfg

grub2-mkconfig -o /boot/grub2/grub.cfg

這樣就完成了。

重開機看到開機選單以後,按下 e ,此時會要求輸入密碼,表示設定已經生效。

若要移除,刪除掉 user.cfg 即可。

rm /boot/grub2/user.cfg

若是要一進入開機選單就要輸入帳號跟密碼,那麼可以這樣設定

grub2-editenv - set grub_users="root"

這樣在開機時,就會問帳號跟密碼了。

要移除,可以用

grub2-editenv - set grub_users=

參考資料

巧用 ps 找 CPU 用量最高跟記憶體用量最高的程序

因為還蠻常用的,就紀錄起來,之後就直接複製了。

ps aux --sort -%cpu | head -n 10
ps aux --sort -%mem | head -n 10
ps -eo pid,ppid,cmd,comm,%mem,%cpu --sort=-%mem | head -10

這邊要注意的是,MacOS 的 ps 跟 Linux 的 ps 不一樣,沒有 –sort 這個參數,MacOS 是用 -r 跟 -m 來做排序。

ps aux -r | head -n 10
ps aux -m | head -n 10

參考資料

從 proc 找 IP

一般來說,在安裝完 Linux 都會有 ifconfig 或是 ip 指令可以查詢主機的 IP。在容器環境裡,會因為要節省容器映像的空間,就不裝這些指令了。那要怎麼查 IP 呢? 可以從 /proc 來查詢。

cat /proc/net/fib_trie
cat /proc/net/fib_trie | grep "|--"   | egrep -v "0.0.0.0| 127."

就這樣,蠻簡單的。

參考資料