Openwrt15.05 how to set environment variables for process
Table of Contents
1 reference
2 background
I am porting Bluetopia app to Openwrt15.05, and I write the Bluetopia app's boot
script according to Procd style.
The Bluetopia libs used the system environment variable for setting bluetooth
address. And the pointed system environment BTHOST_BD_ADDR should exist in the
process space.
I cannot find any desired system environment by using the following checking
code:
extern char **environ; char **env = environ; while (*env) { printf("%s\n", *env); env++; }
the result as below:
SHLVL=1
HOME=/
TERM=linux
PWD=/
PATH=/usr/sbin:/usr/bin:/sbin:/bin
Also you can check the environment variables for a running process by using
strings –a /proc/<pid_of_the_process>/environ
Even thouth, I used the setenv() api to set the pointed environment variable,
but the variable cannot be set (showing 'null' from getenv()).
3 analysis
Every process has its own copy of the environment variables. That they inherit
from parent is just a convention. If you use execve you can set them to whatever
you want. Manipulation of one process's copy never affects any other existing
process, and in particular, nothing a child process does can change its parent's
copy of the environment.
So the environment variables below are belong to the procd.
SHLVL=1
HOME=/
TERM=linux
PWD=/
PATH=/usr/sbin:/usr/bin:/sbin:/bin
the App we created inherit the environment variables from procd.
4 fix steps
change the boot script, pass the environment variables by using
procd_set_param env
sample as below:
procd_open_instance procd_set_param env BTHOST_BD_ADDR=${BTHOST_BD_ADDR} procd_set_param command "${APP}" procd_set_param respawn procd_close_instance
4.1 analysis the env related code
Analysis from the boot script:
- /etc/init.d/bluetopia
start_service() procd_open_instance procd_close_instance
- /etc/rc.common
rc_procd start_service "$@" procd_open_service "$(basename ${basescript:-$initscript})" "$initscript" procd_close_service
- search "procd_open_service" in procd src directory
- ipkg-ipq806x/procd/lib/functions/procd.sh
_procd_wrapper procd_open_service _procd_call _procd_open_service json_add_object instances
- all arguments are packed into json and send over to procd via ubus
procd_close_service _procd_close_service() _procd_ubus_call set ubus call service set "$(json_dump)"
- procd/service/service.c
UBUS_METHOD("set", service_handle_set, service_set_attrs), service_handle_set() service_alloc() vlist_init(&s->instances, avl_strcmp, service_instance_update); service_update() service_event("service.start", s->name, NULL); ubus_notify(ctx, &main_object, type, b.head, -1);
Then
service_instance_update() else if (in_n) { DEBUG(2, "Create instance %s::%s\n", in_n->srv->name, in_n->name); instance_start(in_n); }
- ubus/libubus-req.c
ubus_notify() __ubus_notify_async() ubus_start_request() ubus_send_msg()
- ubus/libubus-io.c
ubus_send_msg() writev_retry() cur_len = sendmsg(fd, &msghdr, 0);
- procd/service/instance.c
instance_start() instance_run() blobmsg_list_for_each(&in->env, var) setenv(blobmsg_name(var->data), blobmsg_data(var->data), 1); execvp(argv[0], argv);
Add some debug logs:
blobmsg_list_for_each(&in->env, var) { setenv(blobmsg_name(var->data), blobmsg_data(var->data), 1); char cmd[128]; sprintf(cmd, "echo [%s - %s] >> /tmp/xx1", blobmsg_name(var->data), (char*)blobmsg_data(var->data)); system(cmd); }
After the system booted up, I check the /tmp/xx1
root@xx:/tmp# cat xx1 [BTHOST_BD_ADDR - 0x34AA0B7FA1CF]
So, It's been verified that we pass the environment virables by using
procd_set_param env, and in the end procd use setenv and execvp start
the APP, in which has the pointed environment virable we need.
5 error fix
When I do the test, I encounter a issue that I cannot boot my process by using:
root@xx:# /etc/init.d/bluetopia start
The reason is that I add a '\' after the last line of the env. as below:
procd_open_instance procd_set_param command "${APP_SCANNER}" procd_set_param respawn procd_set_param env BTHOST_BD_ADDR=${BTHOST_BD_ADDR} \ BTHOST_XCAL_TRIM=${BTHOST_XCAL_TRIM} \ procd_close_instance
To fix this issue, we need remove the last '\', the fixed code:
procd_open_instance procd_set_param command "${APP_SCANNER}" procd_set_param respawn procd_set_param env BTHOST_BD_ADDR=${BTHOST_BD_ADDR} \ BTHOST_XCAL_TRIM=${BTHOST_XCAL_TRIM} procd_close_instance