udevd main
udevdのmain関数の解析メモ
int main(int argc, char *argv[], char *envp[])
{
int retval;
int fd;
struct sigaction act;
fd_set readfds;
const char *value;
int daemonize = 0;
int option;
static const struct option options[] = {
{ "daemon", 0, NULL, 'd' },
{ "debug-trace", 0, NULL, 't' },
{ "verbose", 0, NULL, 'v' },
{ "help", 0, NULL, 'h' },
{}
};
int rc = 1;
int maxfd;
logging_init("udevd");
udev_config_init(); 環境変数からconfig file名などを取得。
selinux_init(); 何もしない
dbg("version %s", UDEV_VERSION);
/* parse commandline options */
while (1) {
 コマンドオプションの解析(省略)
}
rootで実行されているかチェック
if (getuid() != 0) {
fprintf(stderr, "root privileges required\n");
err("root privileges required");
goto exit;
}
/* init sockets to receive events */
制御用のUNIXドメインソケットを作成
if (init_udevd_socket() < 0) {
if (errno == EADDRINUSE) {
fprintf(stderr, "another udev daemon already running\n");
err("another udev daemon already running");
rc = 1;
} else {
fprintf(stderr, "error initializing udevd socket\n");
err("error initializing udevd socket");
rc = 2;
}
goto exit;
}
カーネルイベント用のソケット作成
if (init_uevent_netlink_sock() < 0) {
fprintf(stderr, "error initializing netlink socket\n");
err("error initializing netlink socket");
rc = 3;
goto exit;
}
/* setup signal handler pipe */
シグナルハンドラーからの通知に使用するパイプを作成
retval = pipe(signal_pipe);
if (retval < 0) {
err("error getting pipes: %s", strerror(errno));
goto exit;
}
作成したpipeに対してfcntlが可能かどうかチェックしNONBLOCKに設定する
retval = fcntl(signal_pipe[READ_END], F_GETFL, 0);
if (retval < 0) {
err("error fcntl on read pipe: %s", strerror(errno));
goto exit;
}
retval = fcntl(signal_pipe[READ_END], F_SETFL, retval | O_NONBLOCK);
if (retval < 0) {
err("error fcntl on read pipe: %s", strerror(errno));
goto exit;
}
retval = fcntl(signal_pipe[WRITE_END], F_GETFL, 0);
if (retval < 0) {
err("error fcntl on write pipe: %s", strerror(errno));
goto exit;
}
retval = fcntl(signal_pipe[WRITE_END], F_SETFL, retval | O_NONBLOCK);
if (retval < 0) {
err("error fcntl on write pipe: %s", strerror(errno));
goto exit;
}
ルールファイルをパースしてメモリに展開する。
/* parse the rules and keep them in memory */
sysfs_init();
udev_rules_init(&rules, 1);
export_initial_seqnum();
デーモン化するために子プロセスを作成し親は終了する
if (daemonize) {
pid_t pid;
pid = fork();
switch (pid) {
case 0:
dbg("daemonized fork running");
break;
case -1:
err("fork of daemon failed: %s", strerror(errno));
rc = 4;
goto exit;
default:
dbg("child [%u] running, parent exits", pid);
rc = 0;
goto exit;
}
}
/dev/nullを標準入力と標準出力に設定
/* redirect std fd's */
fd = open("/dev/null", O_RDWR);
if (fd >= 0) {
dup2(fd, STDIN_FILENO);
if (!verbose)
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO)
close(fd);
} else
err("error opening /dev/null: %s", strerror(errno));
/* set scheduling priority for the daemon */
setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY);
chdir("/");
umask(022);
/* become session leader */
セッションリーダーになる
sid = setsid();
dbg("our session is %d", sid);
/* OOM_DISABLE == -17 */
Out Of Memory Killerを無効にするために/proc/self/oom_adに-17を書く
OOM Killerについては詳細記事を参照のこと
fd = open("/proc/self/oom_adj", O_RDWR);
if (fd < 0)
err("error disabling OOM: %s", strerror(errno));
else {
write(fd, "-17", 3);
close(fd);
}
シグナルハンドラーを設定する
/* set signal handlers */
memset(&act, 0x00, sizeof(struct sigaction));
act.sa_handler = (void (*)(int)) sig_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL);
sigaction(SIGCHLD, &act, NULL);
sigaction(SIGHUP, &act, NULL);
/* watch rules directory */
ルールディレクトリィの監視を行う。glibc経由ではなくsyscallで直接呼ぶ。
syscall(__NR_inotify_init),syscall(__NR_inotify_add_watch,・・・など
inotify_fd = inotify_init();
if (inotify_fd >= 0)
inotify_add_watch(inotify_fd, udev_rules_dir, IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
else if (errno == ENOSYS)
err("the kernel does not support inotify, udevd can't monitor configuration file changes");
else
err("inotify_init failed: %s", strerror(errno));
/* maximum limit of forked childs */
子プロセス数の設定値を取得(省略)
/* export log_priority , as called programs may want to follow that setting */
sprintf(udev_log, "UDEV_LOG=%i", udev_log_priority);
putenv(udev_log);
if (debug_trace)
putenv("DEBUG=1");
select用ファイルディスクリプタの最大値を取得
maxfd = udevd_sock;
maxfd = UDEV_MAX(maxfd, uevent_netlink_sock);
maxfd = UDEV_MAX(maxfd, signal_pipe[READ_END]);
maxfd = UDEV_MAX(maxfd, inotify_fd);
selectでイベント受信待ち
while (!udev_exit) {
struct udevd_uevent_msg *msg;
int fdcount;
FD_ZERO(&readfds);
FD_SET(signal_pipe[READ_END], &readfds);
FD_SET(udevd_sock, &readfds);
FD_SET(uevent_netlink_sock, &readfds);
if (inotify_fd >= 0)
FD_SET(inotify_fd, &readfds);
fdcount = select(maxfd+1, &readfds, NULL, NULL, NULL);
if (fdcount < 0) {
if (errno != EINTR)
err("error in select: %s", strerror(errno));
continue;
}
イベントごとの処理を行う。(省略)
}
rc = 0;
後始末を行う
exit:
udev_rules_cleanup(&rules);
sysfs_cleanup();
if (signal_pipe[READ_END] >= 0)
close(signal_pipe[READ_END]);
if (signal_pipe[WRITE_END] >= 0)
close(signal_pipe[WRITE_END]);
if (udevd_sock >= 0)
close(udevd_sock);
if (inotify_fd >= 0)
close(inotify_fd);
if (uevent_netlink_sock >= 0)
close(uevent_netlink_sock);
logging_close();
return rc;
}
{
int retval;
int fd;
struct sigaction act;
fd_set readfds;
const char *value;
int daemonize = 0;
int option;
static const struct option options[] = {
{ "daemon", 0, NULL, 'd' },
{ "debug-trace", 0, NULL, 't' },
{ "verbose", 0, NULL, 'v' },
{ "help", 0, NULL, 'h' },
{}
};
int rc = 1;
int maxfd;
logging_init("udevd");
udev_config_init(); 環境変数からconfig file名などを取得。
selinux_init(); 何もしない
dbg("version %s", UDEV_VERSION);
/* parse commandline options */
while (1) {
 コマンドオプションの解析(省略)
}
rootで実行されているかチェック
if (getuid() != 0) {
fprintf(stderr, "root privileges required\n");
err("root privileges required");
goto exit;
}
/* init sockets to receive events */
制御用のUNIXドメインソケットを作成
if (init_udevd_socket() < 0) {
if (errno == EADDRINUSE) {
fprintf(stderr, "another udev daemon already running\n");
err("another udev daemon already running");
rc = 1;
} else {
fprintf(stderr, "error initializing udevd socket\n");
err("error initializing udevd socket");
rc = 2;
}
goto exit;
}
カーネルイベント用のソケット作成
if (init_uevent_netlink_sock() < 0) {
fprintf(stderr, "error initializing netlink socket\n");
err("error initializing netlink socket");
rc = 3;
goto exit;
}
/* setup signal handler pipe */
シグナルハンドラーからの通知に使用するパイプを作成
retval = pipe(signal_pipe);
if (retval < 0) {
err("error getting pipes: %s", strerror(errno));
goto exit;
}
作成したpipeに対してfcntlが可能かどうかチェックしNONBLOCKに設定する
retval = fcntl(signal_pipe[READ_END], F_GETFL, 0);
if (retval < 0) {
err("error fcntl on read pipe: %s", strerror(errno));
goto exit;
}
retval = fcntl(signal_pipe[READ_END], F_SETFL, retval | O_NONBLOCK);
if (retval < 0) {
err("error fcntl on read pipe: %s", strerror(errno));
goto exit;
}
retval = fcntl(signal_pipe[WRITE_END], F_GETFL, 0);
if (retval < 0) {
err("error fcntl on write pipe: %s", strerror(errno));
goto exit;
}
retval = fcntl(signal_pipe[WRITE_END], F_SETFL, retval | O_NONBLOCK);
if (retval < 0) {
err("error fcntl on write pipe: %s", strerror(errno));
goto exit;
}
ルールファイルをパースしてメモリに展開する。
/* parse the rules and keep them in memory */
sysfs_init();
udev_rules_init(&rules, 1);
export_initial_seqnum();
デーモン化するために子プロセスを作成し親は終了する
if (daemonize) {
pid_t pid;
pid = fork();
switch (pid) {
case 0:
dbg("daemonized fork running");
break;
case -1:
err("fork of daemon failed: %s", strerror(errno));
rc = 4;
goto exit;
default:
dbg("child [%u] running, parent exits", pid);
rc = 0;
goto exit;
}
}
/dev/nullを標準入力と標準出力に設定
/* redirect std fd's */
fd = open("/dev/null", O_RDWR);
if (fd >= 0) {
dup2(fd, STDIN_FILENO);
if (!verbose)
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO)
close(fd);
} else
err("error opening /dev/null: %s", strerror(errno));
/* set scheduling priority for the daemon */
setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY);
chdir("/");
umask(022);
/* become session leader */
セッションリーダーになる
sid = setsid();
dbg("our session is %d", sid);
/* OOM_DISABLE == -17 */
Out Of Memory Killerを無効にするために/proc/self/oom_adに-17を書く
OOM Killerについては詳細記事を参照のこと
fd = open("/proc/self/oom_adj", O_RDWR);
if (fd < 0)
err("error disabling OOM: %s", strerror(errno));
else {
write(fd, "-17", 3);
close(fd);
}
シグナルハンドラーを設定する
/* set signal handlers */
memset(&act, 0x00, sizeof(struct sigaction));
act.sa_handler = (void (*)(int)) sig_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL);
sigaction(SIGCHLD, &act, NULL);
sigaction(SIGHUP, &act, NULL);
/* watch rules directory */
ルールディレクトリィの監視を行う。glibc経由ではなくsyscallで直接呼ぶ。
syscall(__NR_inotify_init),syscall(__NR_inotify_add_watch,・・・など
inotify_fd = inotify_init();
if (inotify_fd >= 0)
inotify_add_watch(inotify_fd, udev_rules_dir, IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
else if (errno == ENOSYS)
err("the kernel does not support inotify, udevd can't monitor configuration file changes");
else
err("inotify_init failed: %s", strerror(errno));
/* maximum limit of forked childs */
子プロセス数の設定値を取得(省略)
/* export log_priority , as called programs may want to follow that setting */
sprintf(udev_log, "UDEV_LOG=%i", udev_log_priority);
putenv(udev_log);
if (debug_trace)
putenv("DEBUG=1");
select用ファイルディスクリプタの最大値を取得
maxfd = udevd_sock;
maxfd = UDEV_MAX(maxfd, uevent_netlink_sock);
maxfd = UDEV_MAX(maxfd, signal_pipe[READ_END]);
maxfd = UDEV_MAX(maxfd, inotify_fd);
selectでイベント受信待ち
while (!udev_exit) {
struct udevd_uevent_msg *msg;
int fdcount;
FD_ZERO(&readfds);
FD_SET(signal_pipe[READ_END], &readfds);
FD_SET(udevd_sock, &readfds);
FD_SET(uevent_netlink_sock, &readfds);
if (inotify_fd >= 0)
FD_SET(inotify_fd, &readfds);
fdcount = select(maxfd+1, &readfds, NULL, NULL, NULL);
if (fdcount < 0) {
if (errno != EINTR)
err("error in select: %s", strerror(errno));
continue;
}
イベントごとの処理を行う。(省略)
}
rc = 0;
後始末を行う
exit:
udev_rules_cleanup(&rules);
sysfs_cleanup();
if (signal_pipe[READ_END] >= 0)
close(signal_pipe[READ_END]);
if (signal_pipe[WRITE_END] >= 0)
close(signal_pipe[WRITE_END]);
if (udevd_sock >= 0)
close(udevd_sock);
if (inotify_fd >= 0)
close(inotify_fd);
if (uevent_netlink_sock >= 0)
close(uevent_netlink_sock);
logging_close();
return rc;
}
■ 参考資料
JM Manpage of PIPE
JM Manpage of FCNTL
JM Manpage of SETSID
JM Manpage of SIGACTION
0 件のコメント:
コメントを投稿