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#include "utils.h" 46 47struct child *children = NULL; 48int number_of_children = 0; 49 50static int 51add_process_info(pid_t pid, struct client_cache_s *client) 52{ 53 struct child *child; 54 int i; 55 56 for (i = 0; i < runtime_vars.max_connections; i++) 57 { 58 child = children+i; 59 if (child->pid) 60 continue; 61 child->pid = pid; 62 child->client = client; 63 child->age = uptime(); 64 return 1; 65 } 66 67 return 0; 68} 69 70static inline int 71remove_process_info(pid_t pid) 72{ 73 struct child *child; 74 int i; 75 76 for (i = 0; i < runtime_vars.max_connections; i++) 77 { 78 child = children+i; 79 if (child->pid != pid) 80 continue; 81 child->pid = 0; 82 if (child->client) 83 child->client->connections--; 84 return 1; 85 } 86 87 return 0; 88} 89 90pid_t 91process_fork(struct client_cache_s *client) 92{ 93 if (number_of_children >= runtime_vars.max_connections) 94 { 95 DPRINTF(E_WARN, L_GENERAL, "Exceeded max connections [%d], not forking\n", 96 runtime_vars.max_connections); 97 errno = EAGAIN; 98 return -1; 99 } 100 101 pid_t pid = fork(); 102 if (pid > 0) 103 { 104 if (client) 105 client->connections++; 106 if (add_process_info(pid, client)) 107 number_of_children++; 108 } 109 110 return pid; 111} 112 113void 114process_handle_child_termination(int signal) 115{ 116 pid_t pid; 117 118 while ((pid = waitpid(-1, NULL, WNOHANG))) 119 { 120 if (pid == -1) 121 { 122 if (errno == EINTR) 123 continue; 124 else 125 break; 126 } 127 if (remove_process_info(pid)) 128 number_of_children--; 129 } 130} 131 132int 133process_daemonize(void) 134{ 135 int pid; 136#ifndef USE_DAEMON 137 int i; 138 139 switch(fork()) 140 { 141 /* fork error */ 142 case -1: 143 perror("fork()"); 144 exit(1); 145 146 /* child process */ 147 case 0: 148 /* obtain a new process group */ 149 if( (pid = setsid()) < 0) 150 { 151 perror("setsid()"); 152 exit(1); 153 } 154 155 /* close all descriptors */ 156 for (i=getdtablesize();i>=0;--i) close(i); 157 158 i = open("/dev/null",O_RDWR); /* open stdin */ 159 dup(i); /* stdout */ 160 dup(i); /* stderr */ 161 162 umask(027); 163 chdir("/"); 164 165 break; 166 /* parent process */ 167 default: 168 exit(0); 169 } 170#else 171 if( daemon(0, 0) < 0 ) 172 perror("daemon()"); 173 pid = getpid(); 174#endif 175 return pid; 176} 177 178int 179process_check_if_running(const char *fname) 180{ 181 char buffer[64]; 182 int pidfile; 183 pid_t pid; 184 185 if(!fname || *fname == '\0') 186 return -1; 187 188 if( (pidfile = open(fname, O_RDONLY)) < 0) 189 return 0; 190 191 memset(buffer, 0, 64); 192 193 if(read(pidfile, buffer, 63) > 0) 194 { 195 if( (pid = atol(buffer)) > 0) 196 { 197 if(!kill(pid, 0)) 198 { 199 close(pidfile); 200 return -2; 201 } 202 } 203 } 204 205 close(pidfile); 206 207 return 0; 208} 209 210void 211process_reap_children(void) 212{ 213 struct child *child; 214 int i; 215 216 for (i = 0; i < runtime_vars.max_connections; i++) 217 { 218 child = children+i; 219 if (child->pid) 220 kill(child->pid, SIGKILL); 221 } 222} 223