/* We can be called as hotplug helper */ /* Kernel cannot provide suitable stdio fds for us, do it ourself */ bb_sanitize_stdio();
void FAST_FUNC bb_sanitize_stdio(void) { bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE, NULL); }
enum { DAEMON_CHDIR_ROOT = 1, DAEMON_DEVNULL_STDIO = 2, DAEMON_CLOSE_EXTRA_FDS = 4, DAEMON_ONLY_SANITIZE = 8, /* internal use */ };
void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) { int fd;
if (flags & DAEMON_CHDIR_ROOT) xchdir("/"); //切换到根目录,如果切换失败,那么进入die状态
if (flags & DAEMON_DEVNULL_STDIO) { //是否使用DEVNULL设备作为输入输出设备 close(0); //文件描述符0,标准输入,缺省是键盘 close(1); //文件描述符1,标准输出,缺省是屏幕 close(2); //文件描述符2,错误输出,缺省是屏幕 }
fd = open(bb_dev_null, O_RDWR); //bb_dev_null为"/dev/null" if (fd < 0) { /* NB: we can be called as bb_sanitize_stdio() from init * or mdev, and there /dev/null may legitimately not (yet) exist! * Do not use xopen above, but obtain _ANY_ open descriptor, * even bogus one as below. */ fd = xopen("/", O_RDONLY); /* don't believe this can fail */ }
while ((unsigned)fd < 2) fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
if (!(flags & DAEMON_ONLY_SANITIZE)) { if (fork_or_rexec(argv)) exit(EXIT_SUCCESS); /* parent */ /* if daemonizing, make sure we detach from stdio & ctty */ setsid(); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); } while (fd > 2) { close(fd--); if (!(flags & DAEMON_CLOSE_EXTRA_FDS)) return; /* else close everything after fd#2 */ } }
./include/libbb.h:extern const char bb_dev_null[]; ./libbb/messages.c:const char bb_dev_null[] ALIGN1 = "/dev/null";
// Die if we can't chdir to a new path.
void FAST_FUNC xchdir(const char *path) { if (chdir(path)) //切换到path目录。如果失败,那么进入die状态。 bb_perror_msg_and_die("chdir(%s)", path); }
void FAST_FUNC bb_perror_msg_and_die(const char *s, ...) { va_list p;
va_start(p, s); /* Guard against ": Success" */ bb_verror_msg(s, p, errno ? strerror(errno) : NULL); //如果系统出错,那么errno将是非0,strerror(errno)将把错误代码转换成字符串信息 va_end(p); xfunc_die(); }
void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) { char *msg, *msg1; int applet_len, strerr_len, msgeol_len, used;
if (!logmode) return;
if (!s) /* nomsg[_and_die] uses NULL fmt */ s = ""; /* some libc don't like printf(NULL) */
used = vasprintf(&msg, s, p); //字符串格式化 if (used < 0) return;
/* This is ugly and costs +60 bytes compared to multiple * fprintf's, but is guaranteed to do a single write. * This is needed for e.g. httpd logging, when multiple * children can produce log messages simultaneously. */
applet_len = strlen(applet_name) + 2; /* "applet: " */ strerr_len = strerr ? strlen(strerr) : 0; msgeol_len = strlen(msg_eol); /* can't use xrealloc: it calls error_msg on failure, * that may result in a recursion */ /* +3 is for ": " before strerr and for terminating NUL */ msg1 = realloc(msg, applet_len + used + strerr_len + msgeol_len + 3); //重新分配内存 if (!msg1) { msg[used++] = '\n'; /* overwrites NUL */ applet_len = 0; } else { msg = msg1; /* TODO: maybe use writev instead of memmoving? Need full_writev? */ memmove(msg + applet_len, msg, used); used += applet_len; strcpy(msg, applet_name); msg[applet_len - 2] = ':'; msg[applet_len - 1] = ' '; if (strerr) { if (s[0]) { /* not perror_nomsg? */ msg[used++] = ':'; msg[used++] = ' '; } strcpy(&msg[used], strerr); used += strerr_len; } strcpy(&msg[used], msg_eol); used += msgeol_len; } //
|