一、kobject_uevent簡(jiǎn)介
在linux內(nèi)核中,uevent機(jī)制是一種內(nèi)核和用戶空間通信的機(jī)制,用于通知用戶空間應(yīng)用程序各種硬件更改或其他事件,比如插入或移除硬件設(shè)備(如USB驅(qū)動(dòng)器或網(wǎng)絡(luò)接口)。uevent表示“用戶空間事件”,當(dāng)硬件事件發(fā)生時(shí),內(nèi)核會(huì)生成一個(gè) uevent,并通過 netlink 套接字將其發(fā)送到用戶空間。用戶空間應(yīng)用程序(例如 udev、mdev),可以監(jiān)聽這些事件并采取相應(yīng)的操作,例如加載適當(dāng)?shù)尿?qū)動(dòng)程序或執(zhí)行其他配置任務(wù)。
kobject_uevent()函數(shù)可通過發(fā)送一個(gè)uevent通知用戶空間:
intkobject_uevent(structkobject*kobj,enumkobject_actionaction) { returnkobject_uevent_env(kobj,action,NULL); }
從上述代碼可知,kobject_uevent()調(diào)用kobject_uevent_env()實(shí)現(xiàn)核心操作,但是kobject_uevent()沒有傳輸環(huán)境變量,故而設(shè)置kobject_uevent_env()的第三個(gè)參數(shù)為NULL。
enum kobject_action用于描述內(nèi)核對(duì)象的操作,內(nèi)核中定義了以下幾種操作:
enumkobject_action{ KOBJ_ADD,//對(duì)象添加。表示向系統(tǒng)中添加了一個(gè)新的kobject對(duì)象。 KOBJ_REMOVE,//對(duì)象移除。表示從系統(tǒng)中移除了一個(gè)kobject對(duì)象。 KOBJ_CHANGE,//對(duì)象修改。表示kobject對(duì)象的屬性或狀態(tài)發(fā)生了變化。 KOBJ_MOVE,//對(duì)象移動(dòng)。表示kobject對(duì)象被移動(dòng)到了另一個(gè)位置。 KOBJ_ONLINE,//對(duì)象上線。表示kobject對(duì)象已經(jīng)準(zhǔn)備好在線工作。 KOBJ_OFFLINE,//對(duì)象離線。表示kobject對(duì)象已經(jīng)離線,不再處于工作狀態(tài)。 KOBJ_MAX//動(dòng)作類型的最大值,用于邊界檢查。 };
在用戶空間可使用udevadm monitor查看uevent事件:
udevadmmonitor--udev
二、重要數(shù)據(jù)結(jié)構(gòu)
1、struct kobj_uevent_env
struct kobj_uevent_env結(jié)構(gòu)的目的是在內(nèi)核中傳遞事件相關(guān)的參數(shù)、環(huán)境變量和數(shù)據(jù)。通過使用這個(gè)結(jié)構(gòu)體,內(nèi)核可以輕松地傳遞事件相關(guān)的信息和數(shù)據(jù)給相關(guān)的處理程序或模塊。
structkobj_uevent_env{ char*argv[3];//用于存儲(chǔ)傳遞給事件的參數(shù)。通常情況下,用于表示事件的命令行參數(shù)。 char*envp[UEVENT_NUM_ENVP];//這是一個(gè)包含UEVENT_NUM_ENVP個(gè)指針的數(shù)組,用于存儲(chǔ)傳遞給事件的環(huán)境變量。在Linux內(nèi)核中,環(huán)境變量通常以鍵值對(duì)的形式傳遞。 intenvp_idx;//用于跟蹤環(huán)境變量數(shù)組中的當(dāng)前索引。它指示下一個(gè)環(huán)境變量應(yīng)該存儲(chǔ)在數(shù)組的哪個(gè)位置。 charbuf[UEVENT_BUFFER_SIZE];//用于存儲(chǔ)事件的文本數(shù)據(jù)。在內(nèi)核中,事件通常以文本形式表示。 intbuflen;//用于跟蹤事件數(shù)據(jù)緩沖區(qū)中的當(dāng)前有效數(shù)據(jù)長度。它指示緩沖區(qū)中包含的事件數(shù)據(jù)量。 };
2、struct kset_uevent_ops
struct kset_uevent_ops結(jié)構(gòu)體定義了 kset 的事件操作接口,使得用戶可以通過提供相應(yīng)的函數(shù)指針來自定義 kset 中 kobject 的事件處理行為:
structkset_uevent_ops{ int(*constfilter)(structkset*kset,structkobject*kobj); constchar*(*constname)(structkset*kset,structkobject*kobj); int(*constuevent)(structkset*kset,structkobject*kobj, structkobj_uevent_env*env); };
int (_ const filter)(struct kset _kset, struct kobject *kobj);:這是一個(gè)指向函數(shù)的指針,該函數(shù)用于過濾 kset 中的 kobject(內(nèi)核對(duì)象)。它接受兩個(gè)參數(shù),分別是指向 kset 和 kobject 的指針,返回一個(gè)整數(shù)值,通常表示過濾操作的結(jié)果。
const char ( const name)(struct kset _kset, struct kobject _kobj);:這是一個(gè)指向函數(shù)的指針,該函數(shù)用于獲取 kobject 的名稱。它接受兩個(gè)參數(shù),分別是指向 kset 和 kobject 的指針,返回一個(gè)指向字符常量的指針,通常是 kobject 的名稱字符串。
int (_ const uevent)(struct kset _kset, struct kobject _kobj, struct kobj_uevent_env _env);:這是一個(gè)指向函數(shù)的指針,該函數(shù)用于生成 kobject 的事件。它接受三個(gè)參數(shù),分別是指向 kset、kobject 和 kobj_uevent_env 結(jié)構(gòu)體的指針。該函數(shù)負(fù)責(zé)將 kobject 的事件信息填充到給定的環(huán)境中,并返回一個(gè)整數(shù)值,通常表示操作的成功或失敗。
三、kobject_uevent_env()詳細(xì)剖析
kobject_uevent_env()用于在給定的 kobject 上觸發(fā)一個(gè)事件,并且傳遞一個(gè)額外的環(huán)境變量數(shù)組:
intkobject_uevent_env(structkobject*kobj,enumkobject_actionaction,char*envp_ext[])
struct kobject *kobj:表示要觸發(fā)事件的內(nèi)核對(duì)象。
enum kobject_action action:表示要執(zhí)行的動(dòng)作,通常是一個(gè)枚舉類型,定義了可能的動(dòng)作列表。這可能包括添加、刪除或修改對(duì)象等操作。
char *envp_ext[]:是一個(gè)字符指針數(shù)組,用于傳遞額外的環(huán)境變量給事件處理程序。這些環(huán)境變量以 key=value 的形式表示,其中 key 是環(huán)境變量的名稱,value 是其對(duì)應(yīng)的值。
該函數(shù)將會(huì)觸發(fā)一個(gè)事件,并將指定的動(dòng)作和環(huán)境變量信息傳遞給與該對(duì)象相關(guān)聯(lián)的事件處理程序。事件處理程序通常會(huì)根據(jù)傳入的動(dòng)作和環(huán)境變量來執(zhí)行相應(yīng)的操作,例如更新內(nèi)核狀態(tài)、通知用戶空間進(jìn)程等。kobject_uevent_env()實(shí)現(xiàn)如下(具體執(zhí)行步驟見注釋):
intkobject_uevent_env(structkobject*kobj,enumkobject_actionaction, char*envp_ext[]) { structkobj_uevent_env*env; constchar*action_string=kobject_actions[action]; constchar*devpath=NULL; constchar*subsystem; structkobject*top_kobj; structkset*kset; conststructkset_uevent_ops*uevent_ops; inti=0; intretval=0; /* *Mark"remove"eventdoneregardlessofresult,forsomesubsystems *donotwanttore-trigger"remove"eventviaautomaticcleanup. */ /如果動(dòng)作是KOBJ_REMOVE,則將對(duì)象的state_remove_uevent_sent標(biāo)志設(shè)置為1,表示“remove”事件已發(fā)送。 if(action==KOBJ_REMOVE) kobj->state_remove_uevent_sent=1; //打印調(diào)試信息,包括對(duì)象的名稱、指針和函數(shù)名稱。 pr_debug("kobject:'%s'(%p):%s ", kobject_name(kobj),kobj,__func__); //找該對(duì)象所屬的kset。 top_kobj=kobj; while(!top_kobj->kset&&top_kobj->parent) top_kobj=top_kobj->parent; //如果對(duì)象不屬于任何kset,則返回錯(cuò)誤。 if(!top_kobj->kset){ pr_debug("kobject:'%s'(%p):%s:attemptedtosenduevent" "withoutkset! ",kobject_name(kobj),kobj, __func__); return-EINVAL; } kset=top_kobj->kset; uevent_ops=kset->uevent_ops; //檢查對(duì)象的uevent_suppress標(biāo)志是否設(shè)置,如果設(shè)置了則跳過事件發(fā)送。 if(kobj->uevent_suppress){ pr_debug("kobject:'%s'(%p):%s:uevent_suppress" "causedtheeventtodrop! ", kobject_name(kobj),kobj,__func__); return0; } //如果uevent_ops和uevent_ops->filter存在且filter函數(shù)返回0,則跳過事件發(fā)送。 if(uevent_ops&&uevent_ops->filter) if(!uevent_ops->filter(kset,kobj)){ pr_debug("kobject:'%s'(%p):%s:filterfunction" "causedtheeventtodrop! ", kobject_name(kobj),kobj,__func__); return0; } //獲取事件的子系統(tǒng)名稱。 if(uevent_ops&&uevent_ops->name) subsystem=uevent_ops->name(kset,kobj); else subsystem=kobject_name(&kset->kobj); if(!subsystem){ pr_debug("kobject:'%s'(%p):%s:unsetsubsystemcausedthe" "eventtodrop! ",kobject_name(kobj),kobj, __func__); return0; } //分配并初始化一個(gè)kobj_uevent_env結(jié)構(gòu)體 env=kzalloc(sizeof(structkobj_uevent_env),GFP_KERNEL); if(!env) return-ENOMEM; //獲取對(duì)象的路徑。 devpath=kobject_get_path(kobj,GFP_KERNEL); if(!devpath){ retval=-ENOENT; gotoexit; } //添加默認(rèn)的環(huán)境變量,包括動(dòng)作(ACTION)、設(shè)備路徑(DEVPATH)和子系統(tǒng)(SUBSYSTEM)。 retval=add_uevent_var(env,"ACTION=%s",action_string); if(retval) gotoexit; retval=add_uevent_var(env,"DEVPATH=%s",devpath); if(retval) gotoexit; retval=add_uevent_var(env,"SUBSYSTEM=%s",subsystem); if(retval) gotoexit; //如果有傳入的額外環(huán)境變量,則將它們添加到事件環(huán)境中 if(envp_ext){ for(i=0;envp_ext[i];i++){ retval=add_uevent_var(env,"%s",envp_ext[i]); if(retval) gotoexit; } } //調(diào)用uevent_ops->uevent函數(shù),如果存在,以允許kset特定的操作添加額外的環(huán)境變量。 if(uevent_ops&&uevent_ops->uevent){ retval=uevent_ops->uevent(kset,kobj,env); if(retval){ pr_debug("kobject:'%s'(%p):%s:uevent()returned" "%d ",kobject_name(kobj),kobj, __func__,retval); gotoexit; } } //根據(jù)動(dòng)作執(zhí)行額外的操作。如果是KOBJ_ADD,則標(biāo)記對(duì)象已發(fā)送state_add_uevent_sent為1。 switch(action){ caseKOBJ_ADD: /* *Mark"add"eventsowecanmakesurewedeliver"remove" *eventtouserspaceduringautomaticcleanup.If *theobjectdidsendan"add"event,"remove"will *automaticallygeneratedbythecore,ifnotalreadydone *bythecaller. */ kobj->state_add_uevent_sent=1; break; caseKOBJ_UNBIND: zap_modalias_env(env); break; default: break; } mutex_lock(&uevent_sock_mutex); /*wewillsendanevent,sorequestanewsequencenumber*/ //獲取一個(gè)新的序列號(hào)并將其添加到事件環(huán)境中 retval=add_uevent_var(env,"SEQNUM=%llu",++uevent_seqnum); if(retval){ mutex_unlock(&uevent_sock_mutex); gotoexit; } //通過網(wǎng)絡(luò)廣播發(fā)送事件。 retval=kobject_uevent_net_broadcast(kobj,env,action_string, devpath); mutex_unlock(&uevent_sock_mutex); //如果配置了CONFIG_UEVENT_HELPER,則調(diào)用uevent_helper來執(zhí)行額外的操作。 #ifdefCONFIG_UEVENT_HELPER /*calluevent_helper,usuallyonlyenabledduringearlyboot*/ if(uevent_helper[0]&&!kobj_usermode_filter(kobj)){ structsubprocess_info*info; retval=add_uevent_var(env,"HOME=/"); if(retval) gotoexit; retval=add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); if(retval) gotoexit; retval=init_uevent_argv(env,subsystem); if(retval) gotoexit; retval=-ENOMEM; info=call_usermodehelper_setup(env->argv[0],env->argv, env->envp,GFP_KERNEL, NULL,cleanup_uevent_env,env); if(info){ retval=call_usermodehelper_exec(info,UMH_NO_WAIT); env=NULL;/*freedbycleanup_uevent_env*/ } } #endif exit: kfree(devpath); kfree(env); returnretval; }
總而言之,kobject_uevent_env()調(diào)用add_uevent_var()構(gòu)建默認(rèn)的信息(包括:ACTION、DEVPATH、SUBSYSTEM和自定義數(shù)據(jù)envp_ext),然后調(diào)用kobject_uevent_net_broadcast()發(fā)送uevent。
1、add_uevent_var()
add_uevent_var()是一個(gè)用于在內(nèi)核中構(gòu)建uevent環(huán)境的輔助函數(shù),它允許向 uevent 環(huán)境中添加一個(gè)鍵值對(duì),表示內(nèi)核對(duì)象事件中的一個(gè)屬性或信息。該函數(shù)實(shí)現(xiàn)如下:
intadd_uevent_var(structkobj_uevent_env*env,constchar*format,...) { va_listargs; intlen; if(env->envp_idx>=ARRAY_SIZE(env->envp)){ WARN(1,KERN_ERR"add_uevent_var:toomanykeys "); return-ENOMEM; } va_start(args,format); len=vsnprintf(&env->buf[env->buflen], sizeof(env->buf)-env->buflen, format,args); va_end(args); if(len>=(sizeof(env->buf)-env->buflen)){ WARN(1,KERN_ERR"add_uevent_var:buffersizetoosmall "); return-ENOMEM; } env->envp[env->envp_idx++]=&env->buf[env->buflen]; env->buflen+=len+1; return0; }
add_uevent_var()函數(shù)的作用是根據(jù)指定的格式將鍵值對(duì)添加到 uevent 環(huán)境中,該函數(shù)使用vsnprintf()函數(shù)將格式化字符串和參數(shù)組合成一個(gè)字符串,并將該字符串添加到 kobj_uevent_env 結(jié)構(gòu)體的緩沖區(qū)中,如果成功添加鍵值對(duì),則返回0;如果緩沖區(qū)空間不足導(dǎo)致添加失敗,則返回-ENOSPC。
使用add_uevent_var()函數(shù)可以方便地構(gòu)建uevent環(huán)境,向用戶空間發(fā)送有關(guān)內(nèi)核對(duì)象事件的信息。通常情況下,該函數(shù)用于在kobject_uevent_env()函數(shù)中構(gòu)建uevent環(huán)境,以向用戶空間發(fā)送內(nèi)核對(duì)象事件。
2、kobject_uevent_net_broadcast()
`kobject_uevent_net_broadcast()用于在網(wǎng)絡(luò)命名空間上廣播內(nèi)核對(duì)象事件:
intkobject_uevent_net_broadcast(structkobject*kobj, structkobj_uevent_env*env, constchar*action_string, constchar*devpath)
(1)首先,它檢查是否啟用了網(wǎng)絡(luò)支持 (CONFIG_NET),因?yàn)檫@個(gè)功能是基于網(wǎng)絡(luò)命名空間的。
(2)它獲取與給定 kobject 相關(guān)聯(lián)的命名空間類型操作 (ops),以確定是否存在網(wǎng)絡(luò)命名空間。
(3)如果 ops 存在,且命名空間類型是網(wǎng)絡(luò)命名空間 (KOBJ_NS_TYPE_NET),則獲取該命名空間。
(4)如果存在網(wǎng)絡(luò)命名空間,它調(diào)用 uevent_net_broadcast_tagged 函數(shù),將事件廣播到指定的網(wǎng)絡(luò)命名空間。
(5)如果沒有找到網(wǎng)絡(luò)命名空間,或者網(wǎng)絡(luò)命名空間不支持事件廣播,它調(diào)用 uevent_net_broadcast_untagged 函數(shù),將事件廣播到所有未標(biāo)記的網(wǎng)絡(luò)命名空間。
(6)最后,它返回廣播函數(shù)的返回值,指示事件廣播的成功或失敗??偟膩碚f,這個(gè)函數(shù)負(fù)責(zé)根據(jù)對(duì)象的網(wǎng)絡(luò)命名空間屬性,將內(nèi)核對(duì)象事件廣播到適當(dāng)?shù)木W(wǎng)絡(luò)命名空間中。uevent_net_broadcast_tagged()和uevent_net_broadcast_untagged()本質(zhì)上都調(diào)用netlink_broadcast()實(shí)現(xiàn)核心功能。
3、call_usermodehelper_setup()
call_usermodehelper_setup 函數(shù)是 Linux 內(nèi)核中的一個(gè)函數(shù),用于設(shè)置和準(zhǔn)備調(diào)用用戶空間輔助程序(usermode helper)。這個(gè)函數(shù)并不直接執(zhí)行用戶空間輔助程序,而是為其設(shè)置參數(shù)和環(huán)境,并返回一個(gè) subprocess_info 結(jié)構(gòu)體,用于后續(xù)的執(zhí)行。
這個(gè)函數(shù)通常在內(nèi)核中的一些子系統(tǒng)中使用,例如 kobject_uevent_net_broadcast 中的調(diào)用。函數(shù)原型如下:
structsubprocess_info*call_usermodehelper_setup(char*path,char**argv, char**envp,gfp_tgfp_mask, int(*init)(structsubprocess_info*info, structcred*new), void(*cleanup)(structsubprocess_info*info), void*data);
path:用戶空間輔助程序的路徑。
argv:參數(shù)數(shù)組,用于傳遞給用戶空間輔助程序的命令行參數(shù)。
envp:環(huán)境變量數(shù)組,用于傳遞給用戶空間輔助程序的環(huán)境變量。
gfp_mask:內(nèi)存分配標(biāo)志。
init:一個(gè)可選的初始化函數(shù),用于在用戶空間輔助程序執(zhí)行前進(jìn)行一些初始化操作。
cleanup:一個(gè)可選的清理函數(shù),用于在用戶空間輔助程序執(zhí)行完畢后進(jìn)行清理操作。
data:可選的附加數(shù)據(jù),可以在初始化和清理函數(shù)中使用。
這個(gè)函數(shù)的作用是為用戶空間輔助程序設(shè)置參數(shù)和環(huán)境,以及提供初始化和清理函數(shù)。返回的 subprocess_info 結(jié)構(gòu)體包含了執(zhí)行用戶空間輔助程序所需的所有信息,包括路徑、參數(shù)、環(huán)境等。一旦設(shè)置完成,用戶空間輔助程序就可以通過call_usermodehelper_exec 函數(shù)執(zhí)行。
4、call_usermodehelper_exec()
call_usermodehelper_exec 函數(shù)是 Linux 內(nèi)核中與執(zhí)行用戶空間輔助程序(usermode helper)相關(guān)的一個(gè)函數(shù)。它負(fù)責(zé)實(shí)際執(zhí)行用戶空間輔助程序,并監(jiān)控其執(zhí)行狀態(tài)。通常情況下,它會(huì)在 call_usermodehelper_setup 函數(shù)之后被調(diào)用。
下面是call_usermodehelper_exec 函數(shù)原型:
intcall_usermodehelper_exec(structsubprocess_info*sub_info,enumumh_waitwait);
sub_info:指向 subprocess_info 結(jié)構(gòu)體的指針,該結(jié)構(gòu)體包含了執(zhí)行用戶空間輔助程序所需的所有信息,包括路徑、參數(shù)、環(huán)境等。
wait:指定是否等待用戶空間輔助程序執(zhí)行完成的標(biāo)志,可以是 UMH_WAIT_EXEC(等待執(zhí)行完成)或 UMH_NO_WAIT(不等待執(zhí)行完成)。
call_usermodehelper_exec 函數(shù)的作用是執(zhí)行用戶空間輔助程序,并等待其執(zhí)行完成(如果需要)。在執(zhí)行期間,它會(huì)監(jiān)控用戶空間輔助程序的執(zhí)行狀態(tài),并在適當(dāng)?shù)臅r(shí)候返回執(zhí)行結(jié)果。
這個(gè)函數(shù)通常在 Linux 內(nèi)核中的一些子系統(tǒng)中使用,例如 kobject_uevent_net_broadcast 中的調(diào)用。通過調(diào)用用戶空間輔助程序,內(nèi)核可以執(zhí)行一些需要借助用戶空間程序完成的任務(wù),例如配置、初始化等。
四、uevent_helper機(jī)制
在 Linux 內(nèi)核中,uevent_helper 是一個(gè)用戶空間輔助程序,用于處理內(nèi)核對(duì)象事件(uevent)。它通常在內(nèi)核啟動(dòng)期間使用,負(fù)責(zé)處理設(shè)備管理相關(guān)的事件,例如設(shè)備的插入、拔出、狀態(tài)變化等。下面是一些使用uevent_helper的典型實(shí)踐:
設(shè)備熱插拔管理: 當(dāng)一個(gè)設(shè)備被插入或拔出時(shí),內(nèi)核會(huì)生成相應(yīng)的 uevent,并調(diào)用 uevent_helper 來處理這些事件。uevent_helper 可以根據(jù)事件類型執(zhí)行一些特定的操作,例如加載適當(dāng)?shù)脑O(shè)備驅(qū)動(dòng)、更新設(shè)備管理信息等。
自動(dòng)配置和初始化: 在系統(tǒng)啟動(dòng)期間,內(nèi)核可能需要執(zhí)行一些自動(dòng)配置和初始化任務(wù),例如掛載文件系統(tǒng)、加載網(wǎng)絡(luò)配置、啟動(dòng)服務(wù)等。uevent_helper 可以被用于執(zhí)行這些任務(wù),并根據(jù)事件類型執(zhí)行相應(yīng)的初始化操作。
系統(tǒng)監(jiān)控和管理: uevent_helper 還可以被用于系統(tǒng)監(jiān)控和管理任務(wù),例如記錄事件日志、生成警報(bào)、執(zhí)行故障排除操作等。
用戶空間通知: uevent_helper 還可以與用戶空間的其他程序進(jìn)行通信,例如向用戶空間的監(jiān)控程序發(fā)送通知或觸發(fā)相應(yīng)的操作。
具體使用 uevent_helper 的方式取決于系統(tǒng)的需求和設(shè)計(jì)。通常情況下,它會(huì)被配置為一個(gè)可執(zhí)行文件或腳本,并在系統(tǒng)啟動(dòng)時(shí)由內(nèi)核調(diào)用。在使用uevent_helper時(shí),需要確保其具有足夠的權(quán)限來執(zhí)行所需的操作,并確保其安全性和穩(wěn)定性。
五、mdev
mdev是Linux系統(tǒng)中用于設(shè)備管理的工具,具有以下特征:
mdev 是一個(gè)更輕量級(jí)的設(shè)備管理器,通常用于嵌入式系統(tǒng)和一些輕量級(jí) Linux 發(fā)行版中。
由 BusyBox 提供,并用于在啟動(dòng)時(shí)自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn)。
mdev 不支持復(fù)雜的規(guī)則配置,而是基于簡(jiǎn)單的設(shè)備名匹配規(guī)則來創(chuàng)建設(shè)備節(jié)點(diǎn)。
所以綜上所述,mdev 更適用于嵌入式系統(tǒng)或者對(duì)資源有限的系統(tǒng),因?yàn)樗虞p量級(jí),但功能也更加有限。
參考busybox源碼,mdev實(shí)現(xiàn)如下:
intmdev_main(intargcUNUSED_PARAM,char**argv) { enum{ MDEV_OPT_SCAN=1<0, ??MDEV_OPT_SYSLOG?????=?1?<1, ??MDEV_OPT_DAEMON?????=?1?<2, ??MDEV_OPT_FOREGROUND?=?1?<3, ?}; ?int?opt; ?RESERVE_CONFIG_BUFFER(temp,?PATH_MAX?+?SCRATCH_SIZE); ?INIT_G(); ?/*?We?can?be?called?as?hotplug?helper?*/ ?/*?Kernel?cannot?provide?suitable?stdio?fds?for?us,?do?it?ourself?*/ ?bb_sanitize_stdio(); ?/*?Force?the?configuration?file?settings?exactly?*/ ?umask(0); ?xchdir("/dev"); ?opt?=?getopt32(argv,?"^" ??"sS"?IF_FEATURE_MDEV_DAEMON("df")?"v" ??"?" ??"vv", ??&G.verbose); #if?ENABLE_FEATURE_MDEV_CONF ?G.filename?=?"/etc/mdev.conf"; ?if?(opt?&?(MDEV_OPT_SCAN|MDEV_OPT_DAEMON))?{ ??/*?Same?as?xrealloc_vector(NULL,?4,?0):?*/ ??G.rule_vec?=?xzalloc((1?<4)?*?sizeof(*G.rule_vec)); ?} #endif ?if?(opt?&?MDEV_OPT_SYSLOG)?{ ??openlog(applet_name,?LOG_PID,?LOG_DAEMON); ??logmode?|=?LOGMODE_SYSLOG; ?} #if?ENABLE_FEATURE_MDEV_DAEMON ?if?(opt?&?MDEV_OPT_DAEMON)?{ ??/*?Daemon?mode?listening?on?uevent?netlink?socket.?Fork?away ???*?after?initial?scan?so?that?caller?can?be?sure?everything ???*?is?up-to-date?when?mdev?process?returns. ???*/ ??int?fd?=?daemon_init(temp); ??if?(!(opt?&?MDEV_OPT_FOREGROUND))?{ ???/*?there?is?no?point?in?logging?to?/dev/null?*/ ???logmode?&=?~LOGMODE_STDIO; ???bb_daemonize_or_rexec(0,?argv); ??} ??daemon_loop(temp,?fd); ?} #endif ?if?(opt?&?MDEV_OPT_SCAN)?{ ??/* ???*?Scan:?mdev?-s ???*/ ??//初始化掃描 ??initial_scan(temp); ?}?else?{ ??//處理action ??process_action(temp,?getpid()); ??dbg1("%s?exiting",?curtime()); ?} ?if?(ENABLE_FEATURE_CLEAN_UP) ??RELEASE_CONFIG_BUFFER(temp); ?return?EXIT_SUCCESS; }
上述代碼中,具體實(shí)現(xiàn)步驟如下:
使用位掩碼枚舉定義了幾個(gè)選項(xiàng)(MDEV_OPT_SCAN、MDEV_OPT_SYSLOG、MDEV_OPT_DAEMON、MDEV_OPT_FOREGROUND)。
初始化一些配置變量并設(shè)置環(huán)境(INIT_G()、bb_sanitize_stdio()、umask(0)、xchdir("/dev"))。
解析了命令行參數(shù),根據(jù)參數(shù)的不同執(zhí)行不同的操作,比如掃描設(shè)備、啟用系統(tǒng)日志、以守護(hù)進(jìn)程模式運(yùn)行等。
根據(jù)程序運(yùn)行的不同情況,執(zhí)行相應(yīng)的操作,比如進(jìn)行初始掃描、處理動(dòng)作等。
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1361瀏覽量
40191 -
Linux
+關(guān)注
關(guān)注
87文章
11213瀏覽量
208736 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4286瀏覽量
62335
原文標(biāo)題:linux設(shè)備驅(qū)動(dòng)模型(uevent)
文章出處:【微信號(hào):嵌入式小生,微信公眾號(hào):嵌入式小生】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論