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