📄 utils.c
字号:
/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2004 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * utils.c - generally useful, non-application specific functions for Gateway * */#include "gw-config.h" #include <ctype.h>#include <errno.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <unistd.h>#include <termios.h>#include <signal.h>#include <sys/types.h>#include <sys/wait.h>#include <sys/stat.h>#include <fcntl.h>#include <pwd.h>#include <grp.h>#include "gwlib.h"/* pid of child process when parachute is used */static pid_t child_pid = -1;/* saved child signal handlers */static struct sigaction child_actions[32];/* just a flag that child signal handlers are stored */static int child_actions_init = 0;/* our pid file name */static char *pid_file = NULL;static volatile sig_atomic_t parachute_shutdown = 0;static void parachute_sig_handler(int signum){ info(0, "Signal %d received, forward to child pid (%ld)", signum, (long) child_pid); /* we do not handle any signal, just forward these to child process */ if (child_pid != -1 && getpid() != child_pid) kill(child_pid, signum); /* if signal received and no child there, terminating */ switch(signum) { case SIGTERM: case SIGINT: case SIGABRT: if (child_pid == -1) exit(0); else parachute_shutdown = 1; }}static void parachute_init_signals(int child){ struct sigaction sa; if (child_actions_init && child) { sigaction(SIGTERM, &child_actions[SIGTERM], NULL); sigaction(SIGQUIT, &child_actions[SIGQUIT], NULL); sigaction(SIGINT, &child_actions[SIGINT], NULL); sigaction(SIGABRT, &child_actions[SIGABRT], NULL); sigaction(SIGHUP, &child_actions[SIGHUP], NULL); sigaction(SIGALRM, &child_actions[SIGALRM], NULL); sigaction(SIGUSR1, &child_actions[SIGUSR1], NULL); sigaction(SIGUSR2, &child_actions[SIGUSR2], NULL); sigaction(SIGPIPE, &child_actions[SIGPIPE], NULL); } else if (!child && !child_actions_init) { sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = parachute_sig_handler; sigaction(SIGTERM, &sa, &child_actions[SIGTERM]); sigaction(SIGQUIT, &sa, &child_actions[SIGQUIT]); sigaction(SIGINT, &sa, &child_actions[SIGINT]); sigaction(SIGABRT, &sa, &child_actions[SIGABRT]); sigaction(SIGHUP, &sa, &child_actions[SIGHUP]); sigaction(SIGALRM, &sa, &child_actions[SIGALRM]); sigaction(SIGUSR1, &sa, &child_actions[SIGUSR1]); sigaction(SIGUSR2, &sa, &child_actions[SIGUSR2]); sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, &child_actions[SIGPIPE]); sigaction(SIGTTOU, &sa, NULL); sigaction(SIGTTIN, &sa, NULL); sigaction(SIGTSTP, &sa, NULL); child_actions_init = 1; } else panic(0, "Child process signal handlers not initialized before.");}static int is_executable(const char *filename){ struct stat buf; if (stat(filename, &buf)) { error(errno, "Error while stat of file `%s'", filename); return 0; } if (!S_ISREG(buf.st_mode) && !S_ISLNK(buf.st_mode)) { error(0, "File `%s' is not a regular file.", filename); return 0; } /* others has exec permission */ if (S_IXOTH & buf.st_mode) return 1; /* group has exec permission */ if ((S_IXGRP & buf.st_mode) && buf.st_gid == getgid()) return 1; /* owner has exec permission */ if ((S_IXUSR & buf.st_mode) && buf.st_uid == getuid()) return 1; return 0;}/* * become daemon. * returns 0 for father process; 1 for child process */static int become_daemon(void){ int fd; if (getppid() != 1) { signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTSTP, SIG_IGN); if (fork()) return 0; setsid(); } close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); fd = open("/dev/null", O_RDWR); /* stdin */ if (fd == -1) panic(errno, "Could not open `/dev/null'"); dup(fd); /* stdout */ dup(fd); /* stderr */ chdir("/"); return 1;}#define PANIC_SCRIPT_MAX_LEN 4096static PRINTFLIKE(2,3) void execute_panic_script(const char *panic_script, const char *format, ...){ char *args[3]; char buf[PANIC_SCRIPT_MAX_LEN + 1]; va_list ap; va_start(ap, format); vsnprintf(buf, PANIC_SCRIPT_MAX_LEN, format, ap); va_end(ap); if (fork()) return; close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); args[0] = (char*) panic_script; args[1] = buf; args[2] = NULL; execv(args[0], args);}static void parachute_start(const char *myname, const char *panic_script) { time_t last_start = 0, last_panic = 0; long respawn_count = 0; int status; if (panic_script && !is_executable(panic_script)) panic(0, "Panic script `%s' is not executable for us.", panic_script); /* setup sighandler */ parachute_init_signals(0); for (;;) { if (respawn_count > 0 && difftime(time(NULL), last_start) < 10) { error(0, "Child process died too fast, disabling for 30 sec."); gwthread_sleep(30.0); } if (!(child_pid = fork())) { /* child process */ parachute_init_signals(1); /* reset sighandlers */ return; } else if (child_pid < 0) { error(errno, "Could not start child process! Will retry in 5 sec."); gwthread_sleep(5.0); continue; } else { /* father process */ time(&last_start); info(0, "Child process with PID (%ld) started.", (long) child_pid); do { if (waitpid(child_pid, &status, 0) == child_pid) { /* check here why child terminated */ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { info(0, "Child process exited gracefully, exit..."); gwlib_shutdown(); exit(0); } else if (WIFEXITED(status)) { error(0, "Caught child PID (%ld) which died with return code %d", (long) child_pid, WEXITSTATUS(status)); child_pid = -1; } else if (WIFSIGNALED(status)) { error(0, "Caught child PID (%ld) which died due to signal %d", (long) child_pid, WTERMSIG(status)); child_pid = -1; } } else if (errno != EINTR) { error(errno, "Error while waiting of child process."); } } while(child_pid > 0); if (parachute_shutdown) { /* may only happens if child process crashed while shutdown */ info(0, "Child process crashed while shutdown. Exiting due to signal..."); info(0, "Going into gwlib_shutdown..."); gwlib_shutdown(); info(0, "gwlib_shutdown done... Bye bye..."); exit(WIFEXITED(status) ? WEXITSTATUS(status) : 0); } /* check whether it's panic while start */ if (respawn_count == 0 && difftime(time(NULL), last_start) < 2) { info(0, "Child process crashed while starting. Exiting..."); info(0, "Going into gwlib_shutdown..."); gwlib_shutdown(); info(0, "gwlib_shutdown done... Bye bye..."); exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1); } respawn_count++; if (panic_script && myname && difftime(time(NULL), last_panic) > 300) { time(&last_panic); debug("kannel", 0, "Executing panic script: %s %s %ld", panic_script, myname, respawn_count); execute_panic_script(panic_script, "%s %ld", myname, respawn_count); } /* sleep a while to get e.g. sockets released */ gwthread_sleep(5.0); } }}static void write_pid_file(void){ int fd; FILE *file; if (!pid_file) return; fd = open(pid_file, O_WRONLY|O_NOCTTY|O_TRUNC|O_CREAT|O_EXCL, 0644); if (fd == -1) panic(errno, "Could not open pid-file `%s'", pid_file); file = fdopen(fd, "w"); if (!file) panic(errno, "Could not open file-stream `%s'", pid_file); fprintf(file, "%ld\n", (long) getpid()); fclose(file);}static void remove_pid_file(void){ if (!pid_file) return; /* ensure we don't called from child process */ if (child_pid == 0) return; if (-1 == unlink(pid_file)) error(errno, "Could not unlink pid-file `%s'", pid_file);}static int change_user(const char *user){ struct passwd *pass; if (!user) return -1; pass = getpwnam(user); if (!pass) { error(0, "Could not find a user `%s' in system.", user); return -1; } if (-1 == setgid(pass->pw_gid)) { error(errno, "Could not change group id from %ld to %ld.", (long) getgid(), (long) pass->pw_gid); return -1; } if (initgroups(user, -1) == -1) { error(errno, "Could not set supplementary group ID's."); } if (-1 == setuid(pass->pw_uid)) { error(errno, "Could not change user id from %ld to %ld.", (long) getuid(), (long) pass->pw_uid); return -1; } return 0;}/* * new datatype functions */MultibyteInt get_variable_value(Octet *source, int *len){ MultibyteInt retval = 0; for(*len=1;; (*len)++, source++) { retval = retval * 0x80 + (*source & 0x7F); if (*source < 0x80) /* if the continue-bit (high bit) is not set */ break; } return retval;}int write_variable_value(MultibyteInt value, Octet *dest){ int i, loc = 0; Octet revbuffer[20]; /* we write it backwards */ for (;;) { revbuffer[loc++] = (value & 0x7F) + 0x80; if (value >= 0x80) value = value >> 7; else break; } for(i=0; i < loc; i++) /* reverse the buffer */ dest[i] = revbuffer[loc-i-1]; dest[loc-1] &= 0x7F; /* remove trailer-bit from last */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -