<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何對(duì)一個(gè)【可執(zhí)行程序】進(jìn)行攔截和包裝?

          共 2227字,需瀏覽 5分鐘

           ·

          2022-06-20 08:42

          作  者:道哥,10+年嵌入式開發(fā)老兵,專注于:C/C++、嵌入式、Linux。

          關(guān)注下方公眾號(hào),回復(fù)【書籍】,獲取 Linux、嵌入式領(lǐng)域經(jīng)典書籍;回復(fù)【PDF】,獲取所有原創(chuàng)文章( PDF 格式)。


            別人的經(jīng)驗(yàn),我們的階梯!

            之前層寫過一篇文章,討論如何對(duì)一個(gè)庫中的函數(shù)進(jìn)行攔截和封裝,也就是所謂的插樁。

            文章的鏈接是:Linux中對(duì)【庫函數(shù)】的調(diào)用進(jìn)行跟蹤的 3 種【插樁】技巧

            文中一共討論了3種方法,來實(shí)現(xiàn)對(duì)【函數(shù)】進(jìn)行攔截:

            1. 在編譯階段插樁;

            2. 在鏈接階段插樁;

            3. 在執(zhí)行階段插樁;

            昨天一個(gè)網(wǎng)友提了另外一個(gè)問題:如何對(duì)一個(gè)可執(zhí)行程序進(jìn)行攔截?

            他提出了一個(gè)實(shí)際的示例:

            Ubuntu 18.04操作系統(tǒng)中,重啟指令/sbin/reboot是一個(gè)軟鏈接,鏈接到可執(zhí)行程序/bin/systemctl,那么是否可以在執(zhí)行systemctl之前,做一些其它的事情(例如:保持一些應(yīng)用程序的狀態(tài)數(shù)據(jù))?

            Ubuntn18.04 中使用 systemd 來管理系統(tǒng)的所有 Service;

            除了 reboot 指令,還有其它幾個(gè)指令也是軟鏈接到 /bin/systemctl;

            這里就引出一個(gè)問題了:

            既然上面這6個(gè)命令都鏈接到systemctl,那么當(dāng)systemctl被執(zhí)行的時(shí)候,它是如何知道它是被哪一個(gè)命令調(diào)用的呢?

            看一下源碼就知道了:通過參數(shù) argv[0] 來獲得的。

            我們知道,main函數(shù)通過argcargv[]來獲取所有的參數(shù),如下:

            // 測(cè)試文件:test1.c

            #include <stdio.h>

            int main(int argc, char *argv[])
            {
            printf("argc = %d \n", argc);
            for (int i = 0; i < argc; i++)
            printf("argv[%d] = %s \n", i, argv[i]);
            return 0;
            }

            編譯、執(zhí)行一下:

            $ gcc test1.c -o test1
            $ ./test1 aaa bbb
            argc = 3
            argv[0] = ./test1
            argv[1] = aaa
            argv[2] = bbb

            可以看到:argv[0] = ./test1,因?yàn)槲覀兪窃诿钚?span style="color:LightSeaGreen;">直接調(diào)用test可執(zhí)行程序的,這很容易理解。

            那么:如果test是被一個(gè)軟鏈接調(diào)用的呢?

            測(cè)試一下,創(chuàng)建軟鏈接:

            $ ln -s test1 link1

            執(zhí)行一下:

            此時(shí),argv[0] = ./link1。

            也就是說:第一個(gè)參數(shù)存放的是軟鏈接文件路徑,systemctl 的道理也是如此!

            知道了這個(gè)原理,那我們就可以在rebootsystemc之間橫叉一刀,增加一個(gè)中間可執(zhí)行文件

            為了便于描述,我們把這個(gè)中間文件創(chuàng)建為腳本pre_systemctl.sh,然后把root軟鏈接到這個(gè)腳本。

            注意:在理解原理之前,建議不要直接用 reboot 等系統(tǒng)命令進(jìn)行操作,可以自己寫一些測(cè)試程序,例如上面的 test。

            操作如下:

            $ cd /sbin
            $ sudo rm root
            $ sudo touch pre_systemctl.sh
            $ sudo chmod +x pre_systemctl.sh
            $ sudo ln -s pre_systemctl.sh reboot

            創(chuàng)建了pre_systemctl.sh腳本之后,并且把reboot軟鏈接到它,在腳本中輸入如下內(nèi)容:

            此時(shí),在命令行中執(zhí)行reboot命令,就會(huì)執(zhí)行這個(gè)腳本,并且這個(gè)腳本也能夠正確的把/sbin/root作為第0個(gè)參數(shù)傳遞給/bin/systemctl,如下圖所示:

            在這個(gè)腳本中,可以在執(zhí)行systemctl之前,做任何需要關(guān)機(jī)前需要處理的一些事情。

            問題似乎是解決了,但是好像還有一個(gè)問題:

            如果用戶在執(zhí)行命令時(shí)輸入了一些其它的參數(shù),這個(gè)腳本程序也應(yīng)該透明的把這些參數(shù)傳遞給 systemctl 才可以!

            為了便于觀察,我們?cè)谀_本中多打印個(gè)參數(shù),并通過exec來啟動(dòng)systemctl,并且強(qiáng)制把參數(shù)$0設(shè)置為systemctl的第0個(gè)參數(shù):

            這個(gè)腳本文件中的重點(diǎn)是最后一條命令:

            exec -a $0 /bin/systemctl $*

            此時(shí),在命令行中執(zhí)行reboot指令,輸出如下:

            如此調(diào)用systemctl,就解決了剛才提出的問題,而且通過 $*,可以把任意多個(gè)參數(shù)透明的傳遞下去。

            這里的關(guān)鍵還是 exec 的參數(shù) -a ,看一下它的指令說明:

            exec [-cl] [-a name] [command [arguments ...]] [redirection ...]

            這里還有一個(gè)更詳細(xì)的說明:


            ------ End ------

            以上就是今天分享的內(nèi)容,感謝您的閱讀!

            既然看到這里了,如果覺得不錯(cuò),請(qǐng)您隨手點(diǎn)個(gè)【贊】和【在看】吧!

            如果轉(zhuǎn)載本文,文末務(wù)必注明:“轉(zhuǎn)自微信公眾號(hào):IOT物聯(lián)網(wǎng)小鎮(zhèn)”。


            推薦閱讀

            【1】C語言指針-從底層原理到花式技巧,用圖文和代碼講解透徹

            【2】GCC 鏈接過程中的【重定位】過程分析

            【3】Linux 動(dòng)態(tài)鏈接過程中的【重定位】底層原理

            【4】原來gdb的底層調(diào)試原理這么簡單

            【5】gcc編譯時(shí),鏈接器安排的【虛擬地址】是如何計(jì)算出來的?

            【6】Linux中對(duì)【庫函數(shù)】的調(diào)用進(jìn)行跟蹤的3種【插樁】技巧


            星標(biāo)公眾號(hào),第一時(shí)間看文章!


            瀏覽 62
            點(diǎn)贊
            評(píng)論
            收藏
            分享

            手機(jī)掃一掃分享

            分享
            舉報(bào)
            評(píng)論
            圖片
            表情
            推薦
            點(diǎn)贊
            評(píng)論
            收藏
            分享

            手機(jī)掃一掃分享

            分享
            舉報(bào)
            <kbd id="afajh"><form id="afajh"></form></kbd>
            <strong id="afajh"><dl id="afajh"></dl></strong>
              <del id="afajh"><form id="afajh"></form></del>
                  1. <th id="afajh"><progress id="afajh"></progress></th>
                    <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    手机超碰在线 | 台湾精品一区二区三区最新作品 | jizz麻豆 | 欧美精品在线自偷自拍 | 青青久操 |