• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ns_config.h"
17 
18 #include <ctype.h>
19 #include <stdarg.h>
20 
21 #include "ld_log.h"
22 /*---------------------------- Defines -------------------------------------*/
23 #define MAX_LINE_SIZE         (1024)
24 #define INI_INVALID_KEY     ((char*)-1)
25 
26 #ifdef UNIT_TEST_STATIC
27     #define UT_STATIC
28 #else
29     #define UT_STATIC static
30 #endif
31 typedef enum _line_status_ {
32     LINE_UNPROCESSED,
33     LINE_ERROR,
34     LINE_EMPTY,
35     LINE_COMMENT,
36     LINE_SECTION,
37     LINE_VALUE
38 } line_status;
39 
40 #define MAX_KEY_LEN 256
41 static char g_key[MAX_KEY_LEN+1] = {0};
42 
config_key_join(const char * join,bool start)43 static char *config_key_join(const char *join, bool start)
44 {
45     if (start) g_key[0] = 0;
46     size_t cnt = MAX_KEY_LEN - strlen(g_key);
47     return strncat(g_key, join, cnt);
48 }
49 
default_error_callback(const char * format,...)50 static int default_error_callback(const char *format, ...)
51 {
52     int ret = 0;
53     va_list argptr;
54     va_start(argptr, format);
55     /* do not print
56     ret = vfprintf(stderr, format, argptr);
57     */
58     va_end(argptr);
59     return ret;
60 }
61 
62 static int (*config_error_callback)(const char *, ...) = default_error_callback;
63 
config_set_error_callback(int (* errback)(const char *,...))64 static void config_set_error_callback(int (*errback)(const char *, ...))
65 {
66     if (errback) {
67         config_error_callback = errback;
68     } else {
69         config_error_callback = default_error_callback;
70     }
71 }
72 
config_line(char * line,char * section,char * key,char * value)73 static line_status config_line(char *line, char *section, char *key, char *value)
74 {
75     size_t len;
76     char *split;
77 
78     if ((len = strcspn(line, "#;")) == 0) {
79         /* comment line */
80         return LINE_COMMENT;
81     }
82     line[len] = 0;
83     if ((len = strtrim(line)) == 0) {
84         /* empty line */
85          return LINE_EMPTY;
86     }
87     if (line[0] == '[' && line[len-1] == ']') {
88         /* section name */
89         memcpy(section, line+1, len-2);
90         section[len-2] = 0;
91         strtrim(section);
92         return LINE_SECTION;
93     }
94     if (split = strchr(line, '=')) {
95         /* key and value */
96         size_t klen, vlen;
97         klen = split - line;
98         vlen = len - klen -1;
99         if (klen > 0) memcpy(key, line, klen);
100         if (vlen > 0) memcpy(value, split+1, vlen);
101         key[klen] = 0;
102         value[vlen] = 0;
103         strtrim(key);
104         strtrim(value);
105         return LINE_VALUE;
106     }
107     return LINE_ERROR;
108 }
109 
110 #define SECTION_DEFAULT_SIZE   16
111 #define KV_DEFAULT_SIZE   64
112 
kvlist_alloc(size_t size)113 static kvlist * kvlist_alloc(size_t size)
114 {
115     kvlist *kvs;
116 
117     if (size < KV_DEFAULT_SIZE) size = KV_DEFAULT_SIZE;
118 
119     kvs = (kvlist *)__libc_calloc(1, sizeof *kvs);
120     if (kvs) {
121         kvs->key = (char **)__libc_calloc(size, sizeof *kvs->key);
122         kvs->val = (char **)__libc_calloc(size, sizeof *kvs->val);
123         if (kvs->key && kvs->val) {
124             kvs->size = size;
125         } else {
126             __libc_free(kvs->key);
127             __libc_free(kvs->val);
128             __libc_free(kvs);
129             kvs = NULL;
130         }
131     }
132     return kvs;
133 }
134 
kvlist_realloc(kvlist * kvs)135 UT_STATIC void kvlist_realloc(kvlist *kvs)
136 {
137     if (!kvs) return;
138     size_t size = 2*kvs->size;
139     if (size) {
140         char **keys, **vals;
141         keys = (char **)__libc_realloc(kvs->key, size * (sizeof *kvs->key));
142         if (!keys) return;
143         kvs->key = keys;
144         vals = (char **)__libc_realloc(kvs->val, size * (sizeof *kvs->val));
145         if (!vals) return;
146         kvs->val = vals;
147         kvs->size = size;
148     }
149 
150     return;
151 }
152 
kvlist_free(kvlist * kvs)153 static void kvlist_free(kvlist *kvs)
154 {
155     size_t i;
156     if (!kvs) return;
157     for (i=0; i<kvs->num; i++) {
158         __libc_free(kvs->key[i]);
159         __libc_free(kvs->val[i]);
160     }
161     __libc_free(kvs->key);
162     __libc_free(kvs->val);
163     __libc_free(kvs);
164 }
165 
sections_alloc(size_t size)166 static section_list *sections_alloc(size_t size)
167 {
168     section_list *sections;
169     if (size < SECTION_DEFAULT_SIZE) size = SECTION_DEFAULT_SIZE;
170 
171     sections = (section_list *)__libc_calloc(1, sizeof *sections);
172 
173     if (sections) {
174         sections->names = (char**)__libc_calloc(size, sizeof *sections->names);
175         sections->kvs = (kvlist**)__libc_calloc(size, sizeof *sections->kvs);
176         if (sections->names && sections->kvs) {
177             sections->size = size;
178         } else {
179             __libc_free(sections->names);
180             __libc_free(sections->kvs);
181             __libc_free(sections);
182             sections = NULL;
183         }
184     }
185     return sections;
186 }
187 
sections_realloc(section_list * sections)188 UT_STATIC void sections_realloc(section_list *sections)
189 {
190     if (!sections) return;
191     size_t size = 2*sections->size;
192     if (size) {
193         char **names;
194         kvlist **kvs;
195         names = (char **)__libc_realloc(sections->names, size * (sizeof *sections->names));
196         if (!names) return;
197         sections->names = names;
198         kvs = (kvlist **)__libc_realloc(sections->kvs, size * (sizeof *sections->kvs));
199         if (!kvs) return;
200         sections->kvs = kvs;
201         sections->size = size;
202     }
203     return;
204 }
205 
sections_free(section_list * sections)206 static void sections_free(section_list *sections)
207 {
208     if (!sections) return;
209     for (size_t i=0; i < sections->num; i++) {
210         __libc_free(sections->names[i]);
211         kvlist_free(sections->kvs[i]);
212     }
213     __libc_free(sections->names);
214     __libc_free(sections->kvs);
215     __libc_free(sections);
216 }
217 
kvlist_set(kvlist * kvs,const char * key,const char * val)218 static void kvlist_set(kvlist *kvs, const char *key, const char *val)
219 {
220     size_t i;
221     if (!kvs||!key||!val) return;
222 
223     for (i=0; i < kvs->num; i++) {
224         if (!strcmp(kvs->key[i], key)) {
225             break;
226         }
227     }
228 
229     if (i < kvs->num) {
230         char * v = ld_strdup(val);
231         if (v) {
232             __libc_free(kvs->val[i]);
233             kvs->val[i] = v;
234         }
235         return;
236     }
237     if (kvs->num == kvs->size) {
238         kvlist_realloc(kvs);
239     }
240     if (kvs->num < kvs->size) {
241         kvs->key[kvs->num] = ld_strdup(key);
242         kvs->val[kvs->num] = ld_strdup(val);
243         if (kvs->key[kvs->num] && kvs->val[kvs->num]) {
244             kvs->num++;
245         } else {
246             __libc_free(kvs->key[kvs->num]);
247             __libc_free(kvs->val[kvs->num]);
248         }
249     }
250     return;
251 }
252 
sections_set(section_list * sections,const char * name,const char * key,const char * val)253 static void sections_set(section_list *sections, const char *name, const char *key, const char *val)
254 {
255     kvlist* kvs = NULL;
256     if (!sections||!name||!key||!val) return;
257 
258     for(size_t i=0; i < sections->num; i++) {
259         if (!strcmp(sections->names[i], name)) {
260             kvs = sections->kvs[i];
261             break;
262         }
263     }
264     if (kvs) {
265         kvlist_set(kvs,key,val);
266         return;
267     }
268 
269     if (sections->num == sections->size) {
270        sections_realloc(sections);
271     }
272 
273     if (sections->num < sections->size) {
274         kvs = kvlist_alloc(0);
275         sections->names[sections->num] = ld_strdup(name);
276         sections->kvs[sections->num] = kvs;
277         if (sections->names[sections->num] && kvs) {
278             sections->num++;
279             kvlist_set(kvs,key,val);
280         } else {
281             __libc_free(sections->names[sections->num]);
282             kvlist_free(kvs);
283         }
284     }
285 }
286 
config_load(const char * filepath)287 static section_list *config_load(const char *filepath)
288 {
289     FILE *file;
290     char line[MAX_LINE_SIZE+1];
291     char section[MAX_LINE_SIZE+1];
292     char key[MAX_LINE_SIZE+1];
293     char val[MAX_LINE_SIZE+1];
294 
295     size_t  len;
296     int  lineno = 0;
297 
298     section_list *sections;
299 
300     if ((file = fopen(filepath, "r")) == NULL) {
301         config_error_callback("config: cannot open %s\n", filepath);
302         return NULL;
303     }
304 
305     sections = sections_alloc(0);
306     if (!sections) {
307         fclose(file);
308         return NULL;
309     }
310 
311     memset(line, 0, sizeof line);
312     memset(section, 0, sizeof section);
313     memset(key, 0, sizeof key);
314     memset(val, 0, sizeof val);
315 
316     while (fgets(line, sizeof line, file)) {
317         lineno++;
318         len = strlen(line);
319         if (len == 0) continue;
320 
321         if (line[len-1]!='\n' && !feof(file)) {
322             config_error_callback(
323               "config: input line too long in %s (%d)\n", filepath, lineno);
324             sections_free(sections);
325             fclose(file);
326             return NULL;
327         }
328 
329         if (line[len-1] == '\n') {
330             line[len-1] = 0;
331             len--;
332         }
333 
334         switch (config_line(line, section, key, val)) {
335             case LINE_EMPTY:
336             case LINE_COMMENT:
337             case LINE_SECTION:
338                 break;
339             case LINE_VALUE:
340                 sections_set(sections, section, key, val);
341                 break;
342             case LINE_ERROR:
343                 config_error_callback(
344                     "config: syntax error in %s (%d):\n-> %s\n",
345                     filepath,
346                     lineno,
347                     line);
348                 break;
349             default:
350                 break;
351         }
352     }
353     fclose(file);
354     return sections;
355 }
356 
357 static ns_configor g_configor;
358 
359 /* const define */
360 #define CONFIG_DEFAULT_FILE "/etc/ld-musl-namespace-arm.ini"        /* default config file pathname */
361 #define SECTION_DIR_MAP "section.dir.map"   /* map of section and directory of app */
362 #define ATTR_NS_PREFIX "namespace"         /* prefix of namespace attribute */
363 #define ATTR_NS_ASAN "asan"                /* asan */
364 #define ATTR_NS_LIB_PATHS "lib.paths"         /* library search paths */
365 #define ATTR_NS_PERMITTED_PATHS "permitted.paths"         /* when separated, permitted dir paths of libs, including sub dirs */
366 #define ATTR_NS_INHERITS "inherits"          /* inherited namespace */
367 #define ATTR_NS_SEPARATED "separated"         /* if separated */
368 #define ATTR_ADDED_NSLIST "added.nslist"      /* all namespace names except default */
369 #define ATTR_NS_DEFAULT "default"           /* default namespace name */
370 #define ATTR_NS_ACQUIESCENCE "acquiescence"           /* acquiescence section name */
371 #define ATTR_NS_ALLOWED_LIBS "allowed.libs"      /* when separated, allowed library names */
372 #define ATTR_NS_INHERIT_SHARED_LIBS "shared.libs"      /* when inherited, shared library names */
373 #define SECTION_DIR_MAP_SYSTEM "system"      /* system path */
374 #define SECTION_DIR_MAP_ASAN_SYSTEM "asan_system"      /* asan system path */
375 
376 /* get key-value list of section */
config_get_kvs(const char * sname)377 static kvlist *config_get_kvs(const char *sname)
378 {
379     size_t  i;
380     for (i=0; i<g_configor.sections->num; i++) {
381         if (!strcmp(g_configor.sections->names[i], sname)) {
382             return g_configor.sections->kvs[i];
383         }
384     }
385     return NULL;
386 }
387 
388 /* get value by acquiescence */
config_get_value_by_acquiescence(kvlist * acquiescence_kvs,const char * key)389 static char *config_get_value_by_acquiescence(kvlist *acquiescence_kvs, const char *key)
390 {
391     if (!acquiescence_kvs) {
392         return NULL;
393     }
394     size_t i;
395     for (i=0; i<acquiescence_kvs->num; i++) {
396         if (!strcmp(acquiescence_kvs->key[i], key)) {
397             return acquiescence_kvs->val[i];
398         }
399     }
400     return NULL;
401 }
402 
403 /* get value by acquiescence lib path */
config_get_acquiescence_lib_path(kvlist * acquiescence_kvs)404 static char *config_get_acquiescence_lib_path(kvlist *acquiescence_kvs)
405 {
406     if (!acquiescence_kvs) {
407         return NULL;
408     }
409     config_key_join(ATTR_NS_PREFIX, true);
410     config_key_join(".", false);
411     config_key_join(ATTR_NS_DEFAULT, false);
412     config_key_join(".", false);
413     char *key = config_key_join(ATTR_NS_LIB_PATHS, false);
414     return config_get_value_by_acquiescence(acquiescence_kvs, key);
415 }
416 
417 /* get value by acquiescence asan lib path */
config_get_acquiescence_asan_lib_path(kvlist * acquiescence_kvs)418 static char *config_get_acquiescence_asan_lib_path(kvlist *acquiescence_kvs)
419 {
420     if (!acquiescence_kvs) {
421         return NULL;
422     }
423     config_key_join(ATTR_NS_PREFIX, true);
424     config_key_join(".", false);
425     config_key_join(ATTR_NS_DEFAULT, false);
426     config_key_join(".", false);
427     config_key_join(ATTR_NS_ASAN, false);
428     config_key_join(".", false);
429     char *key = config_key_join(ATTR_NS_LIB_PATHS, false);
430     return config_get_value_by_acquiescence(acquiescence_kvs, key);
431 }
432 
433 /* get value by key */
config_get_value(const char * key)434 static char *config_get_value(const char *key)
435 {
436     if (!g_configor.kvs) {
437         return NULL;
438     }
439     size_t i;
440     for (i=0; i<g_configor.kvs->num; i++) {
441         if (!strcmp(g_configor.kvs->key[i], key)) return g_configor.kvs->val[i];
442     }
443     return NULL;
444 }
445 
446 /* get library search paths */
config_get_lib_paths(const char * ns_name)447 static char *config_get_lib_paths(const char *ns_name)
448 {
449     if (ns_name == NULL) {
450         return NULL;
451     }
452     config_key_join(ATTR_NS_PREFIX, true);
453     config_key_join(".", false);
454     config_key_join(ns_name, false);
455     config_key_join(".", false);
456     char *key = config_key_join(ATTR_NS_LIB_PATHS, false);
457     return config_get_value(key);
458 }
459 
460 /* get asan library search paths */
config_get_asan_lib_paths(const char * ns_name)461 static char *config_get_asan_lib_paths(const char *ns_name)
462 {
463     if (ns_name == NULL) {
464         return NULL;
465     }
466     config_key_join(ATTR_NS_PREFIX, true);
467     config_key_join(".", false);
468     config_key_join(ns_name, false);
469     config_key_join(".", false);
470     config_key_join(ATTR_NS_ASAN, false);
471     config_key_join(".", false);
472     char *key = config_key_join(ATTR_NS_LIB_PATHS, false);
473     return config_get_value(key);
474 }
475 
476 /* parse config, success 0, failure <0 */
config_parse(const char * file_path,const char * exe_path)477 static int config_parse(const char *file_path, const char *exe_path)
478 {
479     kvlist* dirkvs;
480     kvlist* acquiescence_kvs;
481     if (!exe_path) return -1;
482     g_configor.exe_path = ld_strdup(exe_path);
483     const char * fpath = CONFIG_DEFAULT_FILE;
484     if (file_path) fpath = file_path;
485     g_configor.file_path = ld_strdup(fpath);
486     g_configor.sections = config_load(fpath);
487 
488     if (!g_configor.sections) {
489         LD_LOGD("config_parse load ini config fail!");
490         return -2;
491     }
492     dirkvs = config_get_kvs(SECTION_DIR_MAP);
493     acquiescence_kvs = config_get_kvs(ATTR_NS_ACQUIESCENCE);
494     if (!dirkvs||!acquiescence_kvs) {
495         LD_LOGD("config_parse get dirkvs or acquiescence_kvs fail!");
496         return -3; /* no section directory map or acquiescence section found */
497     }
498     g_configor.config_sys_path = config_get_acquiescence_lib_path(acquiescence_kvs);
499     g_configor.config_asan_sys_path = config_get_acquiescence_asan_lib_path(acquiescence_kvs);
500     size_t i;
501     char * sname = NULL;
502     for (i=0; i<dirkvs->num; i++) {
503        strlist * paths = strsplit(dirkvs->val[i], ":");
504        if (paths) {
505            size_t j;
506            for (j=0; j<paths->num; j++) {
507                if (!strcmp(paths->strs[j], exe_path)) break;
508            }
509            if (j<paths->num) sname = dirkvs->key[i];
510         }
511         strlist_free(paths);
512         if (sname) break;
513     }
514     if (!sname) {
515         /* No matched section found, use the default section. */
516         sname = ATTR_NS_ACQUIESCENCE;
517         LD_LOGD("config_parse no section found!");
518     }
519     if (!(g_configor.kvs = config_get_kvs(sname))) {
520         LD_LOGD("config_parse no section key-value list found!");
521         return -5;/* no section key-value list found */
522     }
523 
524     char *default_lib_paths = config_get_lib_paths(ATTR_NS_DEFAULT);
525     if (default_lib_paths) {
526         g_configor.config_sys_path = default_lib_paths;
527     } else {
528         LD_LOGW("config_parse get default lib paths fail! Config namespace default lib paths,please!");
529     }
530     char *default_asan_lib_paths = config_get_asan_lib_paths(ATTR_NS_DEFAULT);
531     if (default_asan_lib_paths) {
532         g_configor.config_asan_sys_path = default_asan_lib_paths;
533     } else {
534         LD_LOGW("config_parse get default asan lib paths fail! Config namespace default asan lib paths,please!");
535     }
536     return 0;
537 }
538 
539 /* get namespace names except default */
config_get_namespaces()540 static strlist *config_get_namespaces()
541 {
542     char *key = config_key_join(ATTR_ADDED_NSLIST, true);
543     char *val = config_get_value(key);
544     return strsplit(val, ",");
545 }
546 
547 /* get permitted paths */
config_get_permitted_paths(const char * ns_name)548 static char *config_get_permitted_paths(const char *ns_name)
549 {
550     if (ns_name == NULL) {
551         return NULL;
552     }
553     config_key_join(ATTR_NS_PREFIX, true);
554     config_key_join(".", false);
555     config_key_join(ns_name, false);
556     config_key_join(".", false);
557     char *key = config_key_join(ATTR_NS_PERMITTED_PATHS, false);
558     return config_get_value(key);
559 }
560 
561 /* get asan permitted paths */
config_get_asan_permitted_paths(const char * ns_name)562 static char *config_get_asan_permitted_paths(const char *ns_name)
563 {
564     if (ns_name == NULL) {
565         return NULL;
566     }
567     config_key_join(ATTR_NS_PREFIX, true);
568     config_key_join(".", false);
569     config_key_join(ns_name, false);
570     config_key_join(".", false);
571     config_key_join(ATTR_NS_ASAN, false);
572     config_key_join(".", false);
573     char *key = config_key_join(ATTR_NS_PERMITTED_PATHS, false);
574     return config_get_value(key);
575 }
576 /* get inherited namespace names */
config_get_inherits(const char * ns_name)577 static strlist *config_get_inherits(const char *ns_name)
578 {
579     if (ns_name == NULL) {
580         return NULL;
581     }
582     config_key_join(ATTR_NS_PREFIX, true);
583     config_key_join(".", false);
584     config_key_join(ns_name, false);
585     config_key_join(".", false);
586     char *key = config_key_join(ATTR_NS_INHERITS, false);
587     char *val = config_get_value(key);
588     return strsplit(val, ",");
589 }
590 /* get separated */
config_get_separated(const char * ns_name)591 static bool config_get_separated(const char *ns_name)
592 {
593     if (ns_name == NULL) {
594         return false;
595     }
596     config_key_join(ATTR_NS_PREFIX, true);
597     config_key_join(".", false);
598     config_key_join(ns_name, false);
599     config_key_join(".", false);
600     char *key = config_key_join(ATTR_NS_SEPARATED, false);
601     char *val = config_get_value(key);
602     strlwc(val);
603     if (val && !strcmp("true", val)) return true;
604     return false;  /* default false */
605 }
606 
607 /* get allowed libs */
config_get_allowed_libs(const char * ns_name)608 static char *config_get_allowed_libs(const char *ns_name)
609 {
610     if (ns_name == NULL) {
611         return NULL;
612     }
613     config_key_join(ATTR_NS_PREFIX, true);
614     config_key_join(".", false);
615     config_key_join(ns_name, false);
616     config_key_join(".", false);
617     char *key = config_key_join(ATTR_NS_ALLOWED_LIBS, false);
618     return config_get_value(key);
619 }
620 /* get shared libs by inherited namespace */
config_get_inherit_shared_libs(const char * ns_name,const char * inherited_ns_name)621 static char *config_get_inherit_shared_libs(const char *ns_name, const char *inherited_ns_name)
622 {
623     if (ns_name == NULL || inherited_ns_name == NULL) {
624         return NULL;
625     }
626     config_key_join(ATTR_NS_PREFIX, true);
627     config_key_join(".", false);
628     config_key_join(ns_name, false);
629     config_key_join(".inherit.", false);
630     config_key_join(inherited_ns_name, false);
631     config_key_join(".", false);
632     char *key = config_key_join(ATTR_NS_INHERIT_SHARED_LIBS, false);
633     return config_get_value(key);
634 }
635 
636 /* The call time is after parse */
config_get_sys_paths(void)637 static char *config_get_sys_paths(void)
638 {
639     return g_configor.config_sys_path;
640 }
config_get_asan_sys_paths(void)641 static char *config_get_asan_sys_paths(void)
642 {
643     return g_configor.config_asan_sys_path;
644 }
configor_init()645 ns_configor *configor_init()
646 {
647     memset(&g_configor, 0, sizeof g_configor);
648     g_configor.set_error_callback = config_set_error_callback;
649     g_configor.parse = config_parse;
650     g_configor.get_namespaces = config_get_namespaces;
651     g_configor.get_lib_paths = config_get_lib_paths;
652     g_configor.get_asan_lib_paths = config_get_asan_lib_paths;
653     g_configor.get_permitted_paths = config_get_permitted_paths;
654     g_configor.get_asan_permitted_paths = config_get_asan_permitted_paths;
655     g_configor.get_separated = config_get_separated;
656     g_configor.get_inherits = config_get_inherits;
657     g_configor.get_allowed_libs = config_get_allowed_libs;
658     g_configor.get_inherit_shared_libs = config_get_inherit_shared_libs;
659     g_configor.get_sys_paths = config_get_sys_paths;
660     g_configor.get_asan_sys_paths = config_get_asan_sys_paths;
661     g_configor.config_sys_path = NULL; // init it in config_parse.
662     g_configor.config_asan_sys_path = NULL; // init it in config_parse.
663     return &g_configor;
664 }
665 
configor_free()666 void configor_free()
667 {
668     if (g_configor.sections) {
669         sections_free(g_configor.sections);
670         g_configor.sections = NULL;
671     }
672     if (g_configor.file_path) {
673         __libc_free(g_configor.file_path);
674         g_configor.file_path = NULL;
675     }
676     if (g_configor.exe_path) {
677         __libc_free(g_configor.exe_path);
678         g_configor.exe_path = NULL;
679     }
680 }