1 /*
2 * ProFTPD - FTP server daemon
3 * Copyright (c) 2004-2016 The ProFTPD Project team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, The ProFTPD Project team and other respective
20 * copyright holders give permission to link this program with OpenSSL, and
21 * distribute the resulting executable, without including the source code for
22 * OpenSSL in the source distribution.
23 */
24
25 /* Children management code */
26
27 #include "conf.h"
28
29 static pool *child_pool = NULL;
30 static xaset_t *child_list = NULL;
31 static unsigned long child_listlen = 0;
32
child_add(pid_t pid,int fd)33 int child_add(pid_t pid, int fd) {
34 pool *p;
35 pr_child_t *ch;
36
37 /* If no child-tracking list has been allocated, create one. */
38 if (!child_pool) {
39 child_pool = make_sub_pool(permanent_pool);
40 pr_pool_tag(child_pool, "Child Pool");
41 }
42
43 if (child_list == NULL) {
44 pool *list_pool;
45
46 list_pool = make_sub_pool(child_pool);
47 pr_pool_tag(list_pool, "Child List Pool");
48
49 child_list = xaset_create(list_pool, NULL);
50 }
51
52 p = make_sub_pool(child_pool);
53 pr_pool_tag(p, "child session pool");
54
55 ch = pcalloc(p, sizeof(pr_child_t));
56 ch->ch_pool = p;
57 ch->ch_pid = pid;
58 time(&ch->ch_when);
59 ch->ch_pipefd = fd;
60 ch->ch_dead = FALSE;
61
62 xaset_insert(child_list, (xasetmember_t *) ch);
63 child_listlen++;
64
65 return 0;
66 }
67
child_count(void)68 unsigned long child_count(void) {
69 return child_listlen;
70 }
71
child_get(pr_child_t * ch)72 pr_child_t *child_get(pr_child_t *ch) {
73 if (ch == NULL) {
74 return (pr_child_t *) child_list->xas_list;
75 }
76
77 return ch->next;
78 }
79
child_remove(pid_t pid)80 int child_remove(pid_t pid) {
81 pr_child_t *ch;
82
83 if (!child_list) {
84 errno = EPERM;
85 return -1;
86 }
87
88 for (ch = (pr_child_t *) child_list->xas_list; ch; ch = ch->next) {
89 if (ch->ch_pid == pid) {
90 ch->ch_dead = TRUE;
91 child_listlen--;
92 return 0;
93 }
94 }
95
96 errno = ENOENT;
97 return -1;
98 }
99
child_signal(int signo)100 void child_signal(int signo) {
101 pr_child_t *ch;
102
103 if (child_list == NULL) {
104 return;
105 }
106
107 for (ch = (pr_child_t *) child_list->xas_list; ch; ch = ch->next) {
108 if (kill(ch->ch_pid, signo) < 0) {
109 pr_trace_msg("signal", 1, "error sending signal %d to PID %lu: %s",
110 signo, (unsigned long) ch->ch_pid, strerror(errno));
111 }
112 }
113
114 return;
115 }
116
child_update(void)117 void child_update(void) {
118 pr_child_t *ch, *chn = NULL;
119
120 if (child_list == NULL) {
121 return;
122 }
123
124 /* Scan the child list, removing those entries marked as 'dead'. */
125 for (ch = (pr_child_t *) child_list->xas_list; ch; ch = chn) {
126 chn = ch->next;
127
128 if (ch->ch_dead) {
129 if (ch->ch_pipefd != -1) {
130 (void) close(ch->ch_pipefd);
131 }
132
133 xaset_remove(child_list, (xasetmember_t *) ch);
134 destroy_pool(ch->ch_pool);
135 }
136 }
137
138 /* If the child list is empty, recover the list pool memory. */
139 if (child_list->xas_list == NULL) {
140 destroy_pool(child_list->pool);
141 child_list = NULL;
142 child_listlen = 0;
143 }
144
145 return;
146 }
147