日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > 綜合技術 > u-boot中環境變量操作和hash表

u-boot中環境變量操作和hash表

來源:程序員人生   發布時間:2016-11-11 09:13:25 閱讀次數:5529次
u-boot對環境變量的處理主要包括兩部份:
1是環境變量初始化,2是環境變量的設定、刪除等操作。下面將分別進行討論。
這里所使用的u-boot版本為2015.7,硬件為I.MX6 boundary nitrogen6q開發平臺。
1 .環境變量初始化
1.讀取環境變量
環境變量的初始化在board_init_f階段完成,其由在common/barod_r.c中定義的靜態函數initr_env來實現:
static int initr_env(void) { /* initialize environment */ if (should_load_env()) env_relocate(); else set_default_env(((void *)0)); /* Initialize from environment */ load_addr = getenv_ulong("loadaddr", 16, load_addr); return 0; }

should_load_env是board_r.c中的靜態函數,經過編譯預處理,直接返回1。接著履行env_relocate(),該函數在common/env_common.c中實現,編譯預處理后為:

void env_relocate(void) { if (gd->env_valid == 0) { bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM); set_default_env("!bad CRC"); } else { env_relocate_spec(); } }
gd->env_valid在board_f階段中的函數env_init調用中被賦值為1,這里將接著履行env_relocate_spec。env_relocate_spec針對不同的環境變量存儲裝備有多處實現,這里使用CONFIG_ENV_IS_IN_SPI_FLASH宏,所以使用common/Env_sf.c中的定義(參見common/Makefile),由于沒有定義CONFIG_ENV_OFFSET_REDUND,則
env_relocate_spec實現為:
void env_relocate_spec(void) { int ret; char *buf = NULL; buf = (char *)malloc(CONFIG_ENV_SIZE); env_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE); if (!env_flash) { set_default_env("!spi_flash_probe() failed"); if (buf) free(buf); return; } ret = spi_flash_read(env_flash, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE, buf); if (ret) { set_default_env("!spi_flash_read() failed"); goto out; } ret = env_import(buf, 1); if (ret) gd->env_valid = 1; out: spi_flash_free(env_flash); if (buf) free(buf); env_flash = NULL; }
如果從spi flash中讀取環境變量成功,則調用函數env_import,該函數將對讀取到的環境變量進行CRC校驗,如校驗失敗,會履行set_default_env。否則接著調用himport_r履行hash表的初始化。
set_default_env函數用來配置默許的的環境變量。它在common/env_common.c中實現:
void set_default_env(constchar*s) { int flags = 0; if (sizeof(default_environment) > ENV_SIZE) { puts("*** Error - default environment is too large\n\n"); return; } if (s) { if (*s == '!') { printf("*** Warning - %s, " "using default environment\n\n", s + 1); } else { flags = H_INTERACTIVE; puts(s); } } else { puts("Using default environment\n\n"); } if (himport_r(&env_htab, (char *)default_environment, sizeof(default_environment), '\0', flags, 0, 0, NULL) == 0) error("Environment import failed: errno = %d\n", errno); gd->flags |= GD_FLG_ENV_READY; }
default_environment為include/Env_default.h中定義的變量。它是1個常量字符串數組。在default_environment定義時賦值時,賦值的常量字符串又包括了nitrogen6x.h中的宏定義CONFIG_EXTRA_ENV_SETTINGS,該宏定義為代表附加環境變量的常量字符串。也即是default_environment值為Env_default.h加上nitrogen6x.h文件中定義的環境變量值。
另外注意,set_default_env函數中,gd->flags最后被賦值為gd->flags |= GD_FLG_ENV_READY,而從SPI Flash中讀取的環境變量,在使用后續函數env_import時,該函數在返回前也會進行一樣的賦值操作。該標志代表環境變量已準備好,可以對其進行打印、編輯操作。
環境變量讀取的履行總流程圖示以下:


不管是使用默許的環境變量,還是使用從spi flash讀取到的有效環境變量配置,完成環境變量的讀取后,都將調用himport_r將獲得到的環境變量導入到hash表中。
2. 導入環境變量到hash表中
u-boot中使用3個結構體描寫了hash表,它們在include/search.h文件中定義:
struct hsearch_data;
struct _ENTRY;
struct entry,即ENTRY;
下圖描寫了這些結構體的定義和它們之間的關系:


struct _ENTRY代表1個hash表項,其內部包括的struct entry(ENTRY)為hash表中具體的內容數據。struct hsearch_data用來管理全部hash表。struct _ENTRY結構體中的成員used也是作為hash表的管理之用。
讀入的環境變量會導入到hash表中,以方便環境變量的查找,插入,編輯等操作。
在下面的描寫中,使用了hash表鍵值和key兩個名稱,hash表鍵值代表上圖中的hash表項索引index(整數),它還會存儲在struct _ENTRY成員變量used中,當其為空時,表示該hash表中該索引表項未被占用;key代表是的是上圖中ENTRY結構體中的成員變量字串指針key。hash表鍵值根據key通過hash算法來生成。key在u-boot中實際代表是環境變量名(name)。ENTRY結構體中的成員變量字符串指針data則代表相應環境變量的值(value)。

環境變量的hash表導入是通過函數himport_r來實現。該函數包括代碼較多,為了便于分析,這里刪除略去了出錯檢查和復雜的字符串操作代碼,只保存其主要架構:

int himport_r(struct hsearch_data *htab, const char *env, size_t size, const char sep, int flag, int crlf_is_lf, int nvars, char * const vars[]) { char *data, *sp, *dp, *name, *value; char *localvars[nvars]; int i; if (htab == NULL) ...設定毛病標志,返回0; if ((data = malloc(size)) == NULL) ...設定毛病標志,返回0; memcpy(data, env, size); dp = data; /* make a local copy of the list of variables */ if (nvars) memcpy(localvars, vars, sizeof(vars[0]) * nvars); if ((flag & H_NOCLEAR) == 0) { /* Destroy old hash table if one exists */ if (htab->table) hdestroy_r(htab); } /*如果還未創建,則下面創建它*/ if (!htab->table) { int nent = CONFIG_ENV_MIN_ENTRIES + size / 8; if (nent > CONFIG_ENV_MAX_ENTRIES) nent = CONFIG_ENV_MAX_ENTRIES; /*創建hash表--分配存儲空間*/ if (hcreate_r(nent, htab) == 0) { ...釋放data存儲空間,然后返回0; } } ... if(crlf_is_lf){ crlf_is_lf回車標志,這里傳入的參數crlf_is_lf為0,不做處理 如果有些環境變量太長,字符串中間包括'\r'分行,那末這里處理它,去掉回車,并將'\r'前后的字符串 串連成1個字符串。 如:"bootdelay=" "\r" "3" "\0"處理后為"bootdelay=" "3" "\0" 在do_env_import(履行env import命令時帶-r選項)中包括了crlf_is_lf的情況。 } /* Parse environment; allow for '\0' and 'sep' as separators */ do { ENTRY e, *rv; /*...解析環境變量,解析結構存入name和value中"*/ /* enter into hash table */ e.key = name; e.data = value; hsearch_r(e, ENTER, &rv, htab, flag); } while ((dp < data + size) && *dp); /* size check needed for text */ /* without '\0' termination */ free(data); /* process variables which were not considered */ ... return 1; /* everything OK */ }
該函數首先為環境變量分配內存空間。如果標志參數flag中包括H_NOCLEAR---該標志代表強迫清除hash表,那末就調用hdestroy_r函數。如果hash表為空(!htab->table)那末將創建hash表。語句
CONFIG_ENV_MIN_ENTRIES + size / 8
用來根據環境變量包括的字節數,和CONFIG_ENV_MIN_ENTRIES宏定義的最小表項數,來計算hash表包括的表項數。這里的8,使用的是估算法,假定每條環境變量占用8個字節,即key=value(不含等號)。源代碼中對此有詳細注解。然后調用hcreate_r創建hash表----初始化htab->size為上面的表項數,分配hash表的內存空間。
if(crlf_is_lf)代碼段處理環境變量中包括的'\r'。上面程序中有詳細注解。
do {
...          
} while ((dp < data + size) && *dp); 
do-while代碼段解析環境變量,然后將解析后的所有環境變量,逐條填入hash表中。程序首先解析環境變量,每條環境變量的設定用"\0"分割,環境變量名和其設定值用"="號分隔,程序最后將解析后的環境變量名存入name,值存入value中,如"baudrate=" "115200" "\0",解析后name的值為"baudrate",value的內容為"115200"。
e.key = name;
e.data = value;
hsearch_r(e, ENTER, &rv, htab, flag);
上述代碼將環境變量名字符串name賦值給hash表項中的key,環境變量值賦值給hash表項中的data,然后將e代表的hash表項插入到hash表中。下面將會分析具體的插入操作實現。
3.環境變量hash表的插入、編輯等操作
下面的討論觸及到hash表鍵值生成算法,關于這方面的內容,可參見數據結構的相干書籍和網絡上的相干文章。
u-boot中觸及到的hash表操作主要包括環境變量初始化和環境變量編輯。前者被上面的函數himport_r調用,后者則被u-boot1些環境變量編輯命令所調用。

這些操作主要通過函數hsearch_r來實現。刪除操作則通過hdelete_r函數實現。

和通用的hash表操作不同,u-boot中hash表的操作中附加了權限檢查和可履行的回調函數。前者是針對結構體ENTRY中的成員flags的檢查,后者則是對ENTRY中的成員callback的調用。

下面主要分析hash表項初始化(插入表項,和編輯操作中的插入相同)和編輯(插入、修改,刪除等)操作的實現函數hsearch_r。我們將分段討論該函數。

int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, struct hsearch_data *htab, int flag) { unsigned int hval; unsigned int count; unsigned int len = strlen(item.key); unsigned int idx; unsigned int first_deleted = 0; int ret; /* Compute an value for the given string. Perhaps use a better method. */ hval = len; count = len; while (count-- > 0) { hval <<= 4; hval += item.key[count]; } /* * First hash function: * simply take the modul but prevent zero. */ hval %= htab->size; if (hval == 0) ++hval; /*--------------------------以上為代碼段1--------------------------------------------*/ /* The first index tried. */ idx = hval; if (htab->table[idx].used) { /* * Further action might be required according to the * action value. */ unsigned hval2; if (htab->table[idx].used == ⑴ && !first_deleted) /*下面的函數_hdelete中會把used填充為⑴*/ first_deleted = idx; /*_compare_and_overwrite_entry中履行了change_ok權限檢查, 和履行回調call_back函數*/ ret = _compare_and_overwrite_entry(item, action, retval, htab, flag, hval, idx); if (ret != ⑴) return ret; /* * Second hash function: * as suggested in [Knuth] */ hval2 = 1 + hval % (htab->size - 2); /*如如hash表鍵值出現重復*/ do { /* * Because SIZE is prime this guarantees to * step through all available indices. */ if (idx <= hval2) idx = htab->size + idx - hval2; else idx -= hval2; /* * If we visited all entries leave the loop * unsuccessfully. */ if (idx == hval) break; /* If entry is found use it. */ ret = _compare_and_overwrite_entry(item, action, retval, htab, flag, hval, idx); if (ret != ⑴) /*沒有毛病,直接返回*/ return ret; } while (htab->table[idx].used); /*直至生成或找到沒有重復的鍵值*/ } /*--------------------------以上為代碼段2--------------------------------------------*/ /* An empty bucket has been found. */ if (action == ENTER) { /*這里是填充操作,即初始化*/ /* * If table is full and another entry should be * entered return with error. */ if (htab->filled == htab->size) { ...設置毛病標志,且返回0; } /* * Create new entry; * create copies of item.key and item.data */ if (first_deleted) idx = first_deleted; htab->table[idx].used = hval; htab->table[idx].entry.key = strdup(item.key); htab->table[idx].entry.data = strdup(item.data); if (!htab->table[idx].entry.key || !htab->table[idx].entry.data) { ...設置毛病標志 ENOMEM,且返回0; } ++htab->filled; /* This is a new entry, so look up a possible callback */ env_callback_init(&htab->table[idx].entry); /*回調函數初始化*/ /* Also look for flags */ env_flags_init(&htab->table[idx].entry); /*flag標志初始化*/ /*hash表項初始化時,其中觸及的環境變量表現會履行其相干的命令,如stdout=serial,vga 那末就會履行類似u-boot中的setenv stdout serial,vga命令,且進行權限檢查。 固然這些回調函數是用戶定義的。如權限檢查置位且回調函數不為空,權限檢查和回調函數返回失敗, 則刪除相應的hash表項,且返回標志*/ /* check for permission */ if (htab->change_ok != NULL && htab->change_ok( &htab->table[idx].entry, item.data, env_op_create, flag)) { _hdelete(item.key, htab, &htab->table[idx].entry, idx); ...設置毛病標志EPERM ,且返回0; } /* If there is a callback, call it */ if (htab->table[idx].entry.callback && htab->table[idx].entry.callback(item.key, item.data, env_op_create, flag)) { _hdelete(item.key, htab, &htab->table[idx].entry, idx); ...設置毛病標志 EINVAL,且返回0; } /* return new entry */ *retval = &htab->table[idx].entry; /*--------------------------以上為代碼段3--------------------------------------------*/ return 1; } ...設置毛病標志 ESRCH,且返回0; }
代碼段1:hash表鍵值生成算法
其中的代碼
while (count-- > 0) { /*這里使用的是估算法,假定每條環境變量占8個字節,hval為32位(32/4)*/ hval <<= 4; hval += item.key[count]; }
是hash鍵值算法的核心。將item.key---環境變量name中的字符移位并累加,然后模hash表項數,即為該環境變量在hash表項中的數組索引---hash表鍵值。注意這里使用的還是估算法,即假定每條環境變量字符串占用8個字節,注意上述代碼中hval為32位數,移位操作8次就會產生循環。
if (hval == 0) ++hval;
保存了表項數組索引0的空間,在上面himport_r調用的hcreate_r分配hash存儲空間時,多分配了1個表項空間,即該處的保存空間。
代碼段2:hash表鍵值重復沖突處理和編輯操作
上述代碼中
if (htab->table[idx].used == ⑴ && !first_deleted) /*下面的函數_hdelete中會把used填充為⑴*/ first_deleted = idx;
別處使用的函數_hdelete中會把used填充為⑴,變量first_deleted記錄第1次被刪除的鍵值。下面的代碼段3將會使用此處被賦值的first_deleted。
函數_compare_and_overwrite_entry主要履行3項操作:
c.1)檢查以idx為索引的hash表項中的key(環境變量名字符串)是不是和輸入參數item.key1致,不1致返回⑴
c.2)調用change_ok履行權限檢查,不通過返回0。

c.3)如果相應表項的成員callback 不為空,則履行該回調函數。函數履行失敗返回0。

      回調函數在hash表項初始化時或被填充(見下面的代碼段3)。

c.4)履行hash表項修改操作,即修改hash表項中的data為新值。
htab->table[idx].used的包括的值及其含義說明以下:
0        -- 未使用;
⑴      -- 曾被刪除   
index -- 鍵值索引
當htab->table[idx].used為0時,則代表還未被使用和填充,將跳過代碼段2,履行代碼段3。
當htab->table[idx].used不為空,表示以下3種情況:
a)代碼段生成的hash表鍵值出現重復
即以idx為索引的表項已被其他環境變量占用,由于環境變量名是唯1的,那末_compare_and_overwrite_entry履行的hash表項中key(代表被占用的環境變量名)和輸入參數item.key1致性檢查將出錯返回⑴。然后調劑hash表的鍵值生成算法,履行while循環,直至找到1個未重復的hash表鍵值,注意while將循環里重復上述檢查進程。

另外還有1種情況,即此時hash表項中key為空,即還未被初始化,那末_compare_and_overwrite_entry也將返回⑴。

這里重點說明的是hash表項初始化中鍵值生成時重復問題,但鍵值重復的處理又不但限于此。環境變量編輯時所觸及的hash表操作也會遇到該問題。但后者只不太重復還原前者的鍵值生成操作流程,以保證鍵值映照的1致性。

b)已被使用,這里是編輯操作
_compare_and_overwrite_entry也會檢查根據代碼段1鍵值算法映照的鍵值是不是重復,如果不重復,那末履行上述的_compare_and_overwrite_entry中的c.2和c.3操作。c.2和c.3操作如出錯均會返回0,接著履行c.4完成表項內容修改操作(修改環境變量的值value),出錯也將返回0。所以上面的操作出錯都會返回0,而非⑴,則表示編輯操作完成,
hsearch_r函數直接返回。
如果_compare_and_overwrite_entry返回⑴, 表示該hash表項初始化時,在hash表生成時的鍵值處理中,已有重復鍵值。所以,針對已被初始化的hash表,這里也要處理對這類重復鍵值進行重定位。即履行上述的a)。由于第1個被刪除的hash表項即為有效的鍵值。
c.)相應的hash表項曾被刪除,這里再次被使用
如果已被刪除,那末只有針對hash表項的再次初始化才成心義,編輯操作履行_compare_and_overwrite_entry中的c.1返回⑴,接著將履行a)。其實,此時期碼再次履行a)要末沒法找到有效的表項索引。即便能找到,下面的代碼段3也只會使用第1次的曾被刪除的表項索引值,該值記錄在first_deleted中。
從上面的分析中可以看出,函數_compare_and_overwrite_entry的返回值為⑴時,將hash表項初始化時和編輯操作時的鍵值重復檢查混淆處理,致使程序履行流程復雜化。所以該函數的首字符為下劃線,表示可疑版本(可改進)。

代碼段3:
這里主要履行的是hash表項的初始化,在u-boot中使用新增環境命令時也將履行該段代碼。其他環境變量的編輯命令1般在代碼段2都被正確履行后直接返回。而在使用u-boot命令setenv xxx新增1個環境變量時,代碼段2也沒法正確履行,不能返回到上層函數。
不管是全部hash表項的初始化,還是上述新增環境變量時的插入新的hash表項,它們履行的操作都是相同的,即都是插入新表項操作。程序履行到代碼段3時,上面的程序已生成了有效的hash表鍵值,并賦值給變量idx。
htab->filled代表已使用的hash表項數,如其值大于hash->size,即hash表項數,那末設置毛病標志,并直接返回0。
如果first_deleted不為空,則其在代碼2中曾被賦值,表示該表項曾被刪除過,其first_deleted代表第1個被刪除的表項對應的鍵值。

htab->table[idx].used = hval; htab->table[idx].entry.key = strdup(item.key); htab->table[idx].entry.data = strdup(item.data); if (!htab->table[idx].entry.key || !htab->table[idx].entry.data) { ...設置毛病標志 ENOMEM,且返回0; } ++htab->filled;
上面的代碼完成hash表項內容的填充。strdup函數會分配內存空間,注意entry.key和entry.data都是指針變量。if語句履行鍵值1致性檢查。填充無毛病則變量htab->filled遞增1,該變量上面使用過,代表已使用的hash表項數。接著履行函數env_callback_init和env_flags_init,前者是hash表項中回調函數的初始化,后者是hash表項中flags的初始化,flags用來標志訪問權限。這兩個函數的實現比較復雜,會另做1節對它們分析。接著的代碼:
if (htab->change_ok != NULL && htab->change_ok( &htab->table[idx].entry, item.data, env_op_create, flag)) { _hdelete(item.key, htab, &htab->table[idx].entry, idx); ...設置毛病標志EPERM ,且返回0; }
htab->change_ok函數在其定義時賦值為env_flags_validate,這里不為空,則將調用該函數履行操作權限檢查。
代碼:
if (htab->table[idx].entry.callback && htab->table[idx].entry.callback(item.key, item.data, env_op_create, flag)) { _hdelete(item.key, htab, &htab->table[idx].entry, idx); ...設置毛病標志 EINVAL,且返回0; }
履行在env_callback_init中初始化的回調函數。如權限檢查和回調函數的履行出現毛病,則直接刪除該hash表項。
這里,可以看到,環境變量在其初始化的hash表填充時,就會調用表項中設置的回調函數。例如,有以下的存儲在spi flash中的環境變量:
const unsigned char default_environment[] = { "bootdelay=" "3" "\0" "baudrate=" "115200" "\0" "stdout=" "serial,vga" "\0" "ethprime=" "FEC" "\0" "preboot=" "" "\0" "loadaddr=" "0x12000000" "\0" "\0" };
以第2行的環境變量"stdout=" "serial,vga"為例,當其從spi flash加載到內存空間中,并填充到hash表中時,如果該項環境變量的相干賦值(創建)操作被允許(權限檢查通過),且有相應的回調函數,那末此處就會履行該函數。另外代碼段2中的_compare_and_overwrite_entry中也將履行權限檢查和回調函數。如,在u-boot中履行:
=>setenv stdout serial,hdmi
那末該命令會調用do_env_set函數,它又調用上述的hsearch_r并履行代碼段2。所以,在"console_init_r分析"1節中,曾提到過該命令是立即生效的。
3.env_flags_init和env_callback_init
env_flags_init初始化操作權限,env_callback_init初始化回調函數。
所謂的權限是針對每個hash表項而言的,而每個hash表項對應1條環境變量,權限即環境變量的創建,修改,刪除等權限。回調函數是履行這些環境變量的操作后附加的1些操作。
如上面的例子中,履行setenv stdout serial,hdmi時,會首先檢查環境變量stdout的修改操作是不是被允許,如果允許將環境變量的值修改成serial,hdmi,然后調用回調函數,重設console。

下面來逐1分析這兩個函數的具體實現。

3.1 env_flags_init

權限操作集中在文件env_flags.c中:

void env_flags_init(ENTRY *var_entry) { const char *var_name = var_entry->key; char flags[ENV_FLAGS_ATTR_MAX_LEN + 1] = ""; int ret = 1; if (first_call) { flags_list = getenv(ENV_FLAGS_VAR); first_call = 0; } /* look in the ".flags" and static for a reference to this variable */ ret = env_flags_lookup(flags_list, var_name, flags); /* if any flags were found, set the binary form to the entry */ if (!ret && strlen(flags)) var_entry->flags = env_parse_flags_to_bin(flags); }
first_call為靜態變量,其定義時初始化為1。上述代碼首先從環境變量中獲得flags的值(ENV_FLAGS_VAR),然后調用env_flags_lookup:
static inline int env_flags_lookup(const char *flags_list, const char *name, char *flags) { int ret = 1; if (!flags) /* bad parameter */ return ⑴; /* try the env first */ if (flags_list) ret = env_attr_lookup(flags_list, name, flags); if (ret != 0) /* if not found in the env, look in the static list */ ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags); return ret; }
1般地,環境變量中不含ENV_FLAGS_VAR,那末此處的flags_list值為空,則履行env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags);
ENV_FLAGS_LIST_STATIC定義為:
#define ENV_FLAGS_LIST_STATIC \ "ipaddr:i," \ "gatewayip:i," \ "netmask:i," \ "serverip:i," \ "serial#:so,"
每條環境變量的操作權限用逗號分隔,變量名和權限位使用冒號分隔。如上面ipaddr是環境變量名,i是權限描寫。
權限描寫又分為權限類型和權限值描寫。

類型即是該環境變量對應值的類型,其字符的定義實現及其含義以下:
字符s代表string類型數據
字符d代表decimal類型數據
字符x代表hyexadecimal類型數據
字符b代表boolean 類型數據
字符i代表ip address 類型數據
權限值及其含義以下:
字符a表示any,可進行任何操作,它為權限的默許值
字符r表示read-only,只讀
字符o表示write-once,可1次寫
字符c表示change-default,可改變成默許值
上述權限值對應的u-boot操作包括在env_flags_varaccess_mask變量中:

static const int env_flags_varaccess_mask[] = { 0, ENV_FLAGS_VARACCESS_PREVENT_DELETE | ENV_FLAGS_VARACCESS_PREVENT_CREATE | ENV_FLAGS_VARACCESS_PREVENT_OVERWR, ENV_FLAGS_VARACCESS_PREVENT_DELETE | ENV_FLAGS_VARACCESS_PREVENT_OVERWR, ENV_FLAGS_VARACCESS_PREVENT_DELETE | ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR };
env_flags_init函數會調用函數env_parse_flags_to_bin,將權限值字符,映照為上面env_flags_varaccess_mask變量中的2進制值,即

字符a終究映照為0
字符r映照為:ENV_FLAGS_VARACCESS_PREVENT_DELETE |
            ENV_FLAGS_VARACCESS_PREVENT_CREATE |
            ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
字符o映照為:
ENV_FLAGS_VARACCESS_PREVENT_DELETE |
            ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
字符c映照為:
 ENV_FLAGS_VARACCESS_PREVENT_DELETE |
            ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR
從上面的ENV_FLAGS_VARACCESS_XX宏定義名可以看出其代表的操作權限。

env_flags_init最后會將映照后的2進制權限位值賦值給hash表項的成員flags。struct hsearch_data的成員變量change_ok,它是1個函數指針,定義時被初始化為env_flags_validate。環境變量操作的權限檢查是通過該函數來履行。

int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, int flag) { const char *name; const char *oldval = NULL; if (op != env_op_create) oldval = item->data; name = item->key; /* Default value for NULL to protect string-manipulating functions */ newval = newval ? : ""; /* validate the value to match the variable type */ if (op != env_op_delete) { enum env_flags_vartype type = (enum env_flags_vartype) (ENV_FLAGS_VARTYPE_BIN_MASK & item->flags); if (_env_flags_validate_type(newval, type) < 0) { ... return ⑴; } } /* check for access permission */ #ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE if (flag & H_FORCE) return 0; #endif switch (op) { case env_op_delete: if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) { return 1; } break; case env_op_overwrite: if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) { return 1; } else if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) { const char *defval = getenv_default(name); if (defval == NULL) defval = ""; if (strcmp(oldval, defval) != 0) { return 1; } } break; case env_op_create: if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) { return 1; } break; } return 0; }
如果定義了CONFIG_ENV_ACCESS_IGNORE_FORCE,則所有的訪問權限將被疏忽。
針對不同的操作,傳給env_flags_validate的參數op值就不同。
在上面的函數hsearch_r中,代碼段2中調用_compare_and_overwrite_entry,然后調用change_ok,傳入的op值是env_op_overwrite,而代碼段3中,調用change_ok ,傳入的op值為env_op_create。這樣env_flags_validate函數將根據不同的op操作,來履行相應的權限檢查。如當操作是創建hash表項時,那末,會檢查ENV_FLAGS_VARACCESS_PREVENT_CREATE標志。
另外,如果相應的環境變量hash表項沒有定義flags,則其值為0,允許所有的權限。即針對環境變量的操作,默許的權限為全部使能。
3.2 env_callback_init
void env_callback_init(ENTRY *var_entry) { const char *var_name = var_entry->key; char callback_name[256] = ""; struct env_clbk_tbl *clbkp; int ret = 1; if (first_call) { callback_list = getenv(ENV_CALLBACK_VAR); first_call = 0; } /* look in the ".callbacks" var for a reference to this variable */ if (callback_list != NULL) ret = env_attr_lookup(callback_list, var_name, callback_name); /* only if not found there, look in the static list */ if (ret) ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name, callback_name); /* if an association was found, set the callback pointer */ if (!ret && strlen(callback_name)) { clbkp = find_env_callback(callback_name); if (clbkp != NULL) var_entry->callback = clbkp->callback; } }
代碼首先從環境變量中獲得回調函數的值(ENV_CALLBACK_VAR),然后調用env_attr_lookup,這里使用參數ENV_CALLBACK_LIST_STATIC,該宏定義以下:
#define ENV_CALLBACK_LIST_STATIC ENV_DOT_ESCAPE ENV_CALLBACK_VAR ":callbacks," \ ENV_DOT_ESCAPE ENV_FLAGS_VAR ":flags," \ "baudrate:baudrate," \ NET_CALLBACKS \ "loadaddr:loadaddr," \ SILENT_CALLBACK \ SPLASHIMAGE_CALLBACK \ "stdin:console,stdout:console,stderr:console," \ CONFIG_ENV_CALLBACK_LIST_STATIC
每條環境變量操作的回調函數用逗號分隔,變量名和回調函數索引字符串使用冒號分隔。如上面stdin是環境變量名,冒號后面的console是回調函數索引字符串。之所以稱為"回調函數索引字符串",由于這里只是字符串,必須使用映照機制,將回調函數索引字符串和所對應的回調函數關聯起來。然后使用回調函數索引字符串,查找到相應的回調函數。

結構體struct env_clbk_tbl保持著這樣1個回調函數索引字符串和回調函數的映照表:

struct env_clbk_tbl { const char *name; /* Callback name */ int (*callback)(const char *name, const char *value, enum env_op op, int flags); };
利用宏U_BOOT_ENV_CALLBACK填充該結構體,將上述的回調函數索引字符串和回調函數關聯起來,如:
U_BOOT_ENV_CALLBACK(console, on_console);
將回調函數索引字符串"console"和on_console回調函數相干聯,那末上述環境變量stdin操作最后的回調函數就是on_console。

在u-boot中,使用U_BOOT_ENV_CALLBACK定義并初始化的struct env_clbk_tbl變量都寄存在名為_u_boot_list_2_env_clbk_2_xx的符號段中。

U_BOOT_ENV_CALLBACK(console, on_console)預編譯后為:

struct env_clbk_tbl _u_boot_list_2_env_clbk_2_console __attribute__((aligned(4))) __attribute__((unused, section(".u_boot_list_2_""env_clbk""_2_""console"))) = {"console", on_console};
注意上述section中的符號段名。所有益用U_BOOT_ENV_CALLBACK 定義的的環境變量回調函數都將放在這樣1個以_u_boot_list_2_env_clbk_2開頭的符號段中。
在u-boot生成的符號表文件system.map中可查看到這些段:
17868084 D _u_boot_list_2_env_clbk_2_bootfile 1786808c D _u_boot_list_2_env_clbk_2_callbacks 17868094 D _u_boot_list_2_env_clbk_2_console 1786809c D _u_boot_list_2_env_clbk_2_ethaddr 178680a4 D _u_boot_list_2_env_clbk_2_flags 178680ac D _u_boot_list_2_env_clbk_2_gatewayip 178680b4 D _u_boot_list_2_env_clbk_2_ipaddr 178680bc D _u_boot_list_2_env_clbk_2_loadaddr 178680c4 D _u_boot_list_2_env_clbk_2_netmask
env_callback_init函數中接著履行的find_env_callback就是在_u_boot_list_2_env_clbk_2_xx段中查找環境變量相應的符號段,該符號也即上述struct env_clbk_tbl變量的地址。find_env_callback函數對其中name進行核對后,返回有效的回調函數指針然后函數env_callback_init將其賦值給hash表項的成員callback。這樣就完成了環境變量hash表項的回調函數初始化。

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 人人九九精 | 色一色成人网 | 久久久久免费精品 | 亚洲精品在线视频 | 日韩免费福利视频 | 亚洲天堂五月 | 日韩免费视频一区二区 | 粉嫩精品一区二区三区在线观看 | 中文一区二区 | a在线资源 | 精品国产成人 | 黄色大片成人 | 国产精品com| 99精品视频免费版的特色功能 | 成人黄色小视频 | 一区久久| 久久大陆| 精品欧美乱码久久久久久1区2区 | 国产一区二区免费网站 | 国产日韩精品视频 | 久久av喷吹av高潮av萌白 | 日韩午夜视频在线 | 动漫一区二区 | 色福利网| 亚洲 欧美 日韩 在线 | 国产精品一区二区三区在线 | 国产精品精品视频一区二区三区 | 亚洲三级网站 | 国产亚洲欧美另类一区二区三区 | 国产在线播放一区二区 | 99视频在线看 | av大片免费看 | 亚洲在线电影 | 精一区二区 | 欧美三区在线观看 | 精品黄网| 国产传媒一区 | 毛片免费不卡 | 操操电影 | 国产精品一区久久久 | 日韩三级中文字幕 |