1/* Process handling 2 * 3 * Copyright �� 2006, Thomas Bernard 4 * Copyright �� 2013, Beno��t Knecht <benoit.knecht@fsfe.org> 5 * 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * * The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30#include <sys/types.h> 31#include <sys/stat.h> 32#include <unistd.h> 33#include <fcntl.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <errno.h> 37#include <string.h> 38#include <signal.h> 39#include <sys/wait.h> 40 41#include "upnpglobalvars.h" 42#include "process.h" 43#include "config.h" 44#include "log.h" 45 46struct child *children = NULL; 47int number_of_children = 0; 48 49static void 50add_process_info(pid_t pid, struct client_cache_s *client) 51{ 52 struct child *child; 53 int i; 54 55 for (i = 0; i < runtime_vars.max_connections; i++) 56 { 57 child = children+i; 58 if (child->pid) 59 continue; 60 child->pid = pid; 61 child->client = client; 62 child->age = time(NULL); 63 break; 64 } 65} 66 67static inline void 68remove_process_info(pid_t pid) 69{ 70 struct child *child; 71 int i; 72 73 for (i = 0; i < runtime_vars.max_connections; i++) 74 { 75 child = children+i; 76 if (child->pid != pid) 77 continue; 78 child->pid = 0; 79 if (child->client) 80 child->client->connections--; 81 break; 82 } 83} 84 85pid_t 86process_fork(struct client_cache_s *client) 87{ 88 if (number_of_children >= runtime_vars.max_connections) 89 { 90 DPRINTF(E_WARN, L_GENERAL, "Exceeded max connections [%d], not forking\n", 91 runtime_vars.max_connections); 92 errno = EAGAIN; 93 return -1; 94 } 95 96 pid_t pid = fork(); 97 if (pid > 0) 98 { 99 number_of_children++; 100 if (client) 101 client->connections++; 102 add_process_info(pid, client); 103 } 104 105 return pid; 106} 107 108void 109process_handle_child_termination(int signal) 110{ 111 pid_t pid; 112 113 while ((pid = waitpid(-1, NULL, WNOHANG))) 114 { 115 if (pid == -1) 116 { 117 if (errno == EINTR) 118 continue; 119 else 120 break; 121 } 122 number_of_children--; 123 remove_process_info(pid); 124 } 125} 126 127int 128process_daemonize(void) 129{ 130 int pid; 131#ifndef USE_DAEMON 132 int i; 133 134 switch(fork()) 135 { 136 /* fork error */ 137 case -1: 138 perror("fork()"); 139 exit(1); 140 141 /* child process */ 142 case 0: 143 /* obtain a new process group */ 144 if( (pid = setsid()) < 0) 145 { 146 perror("setsid()"); 147 exit(1); 148 } 149 150 /* close all descriptors */ 151 for (i=getdtablesize();i>=0;--i) close(i); 152 153 i = open("/dev/null",O_RDWR); /* open stdin */ 154 dup(i); /* stdout */ 155 dup(i); /* stderr */ 156 157 umask(027); 158 chdir("/"); 159 160 break; 161 /* parent process */ 162 default: 163 exit(0); 164 } 165#else 166/* Foxconn modify start, Bernie 06/01/2016 */ 167/* 168 if( daemon(0, 0) < 0 ) 169 perror("daemon()"); 170*/ 171/* Foxconn modify end, Bernie 06/01/2016 */ 172 pid = getpid(); 173#endif 174 return pid; 175} 176 177int 178process_check_if_running(const char *fname) 179{ 180 char buffer[64]; 181 int pidfile; 182 pid_t pid; 183 184 if(!fname || *fname == '\0') 185 return -1; 186 187 if( (pidfile = open(fname, O_RDONLY)) < 0) 188 return 0; 189 190 memset(buffer, 0, 64); 191 192 if(read(pidfile, buffer, 63) > 0) 193 { 194 if( (pid = atol(buffer)) > 0) 195 { 196 if(!kill(pid, 0)) 197 { 198 close(pidfile); 199 return -2; 200 } 201 } 202 } 203 204 close(pidfile); 205 206 return 0; 207} 208 209void 210process_reap_children(void) 211{ 212 struct child *child; 213 int i; 214 215 for (i = 0; i < runtime_vars.max_connections; i++) 216 { 217 child = children+i; 218 if (child->pid) 219 kill(child->pid, SIGKILL); 220 } 221} 222