Coverage Report

Created: 2026-09-01 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/proftpd/src/child.c
Line
Count
Source
1
/*
2
 * ProFTPD - FTP server daemon
3
 * Copyright (c) 2004-2026 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, see <https://www.gnu.org/licenses/>.
17
 *
18
 * As a special exemption, The ProFTPD Project team and other respective
19
 * copyright holders give permission to link this program with OpenSSL, and
20
 * distribute the resulting executable, without including the source code for
21
 * OpenSSL in the source distribution.
22
 */
23
24
/* Children management code */
25
26
#include "conf.h"
27
28
static pool *child_pool = NULL;
29
static xaset_t *child_list = NULL;
30
static unsigned long child_listlen = 0;
31
32
0
static void child_list_cleanup(void *user_data) {
33
0
  child_list = NULL;
34
0
  child_listlen = 0;
35
0
}
36
37
0
int child_add(pid_t pid, int fd) {
38
0
  pool *p;
39
0
  pr_child_t *ch;
40
41
  /* If no child-tracking list has been allocated, create one. */
42
0
  if (child_pool == NULL) {
43
0
    child_pool = make_sub_pool(permanent_pool);
44
0
    pr_pool_tag(child_pool, "Child Pool");
45
0
  }
46
47
0
  if (child_list == NULL) {
48
0
    pool *list_pool;
49
50
0
    list_pool = make_sub_pool(child_pool);
51
0
    pr_pool_tag(list_pool, "Child List Pool");
52
0
    register_cleanup2(list_pool, NULL, child_list_cleanup);
53
54
0
    child_list = xaset_create(list_pool, NULL);
55
0
  }
56
57
0
  p = make_sub_pool(child_pool);
58
0
  pr_pool_tag(p, "child session pool");
59
60
0
  ch = pcalloc(p, sizeof(pr_child_t));
61
0
  ch->ch_pool = p;
62
0
  ch->ch_pid = pid;
63
0
  time(&ch->ch_when);
64
0
  ch->ch_pipefd = fd;
65
0
  ch->ch_dead = FALSE;
66
67
0
  xaset_insert(child_list, (xasetmember_t *) ch);
68
0
  child_listlen++;
69
70
0
  return 0;
71
0
}
72
73
0
unsigned long child_count(void) {
74
0
  return child_listlen;
75
0
}
76
77
0
pr_child_t *child_get(pr_child_t *ch) {
78
0
  if (ch == NULL) {
79
0
    return (pr_child_t *) child_list->xas_list;
80
0
  }
81
82
0
  return ch->next;
83
0
}
84
85
0
int child_remove(pid_t pid) {
86
0
  pr_child_t *ch;
87
88
0
  if (child_list == NULL) {
89
0
    errno = EPERM;
90
0
    return -1;
91
0
  }
92
93
0
  for (ch = (pr_child_t *) child_list->xas_list; ch; ch = ch->next) {
94
0
    if (ch->ch_pid == pid) {
95
0
      ch->ch_dead = TRUE;
96
0
      child_listlen--;
97
0
      return 0;
98
0
    }
99
0
  }
100
101
0
  errno = ENOENT;
102
0
  return -1;
103
0
}
104
105
0
void child_signal(int signo) {
106
0
  pr_child_t *ch;
107
108
0
  if (child_list == NULL) {
109
0
    return;
110
0
  }
111
112
0
  for (ch = (pr_child_t *) child_list->xas_list; ch; ch = ch->next) {
113
0
    if (kill(ch->ch_pid, signo) < 0) {
114
0
      pr_trace_msg("signal", 1, "error sending signal %d to PID %lu: %s",
115
0
        signo, (unsigned long) ch->ch_pid, strerror(errno));
116
0
    }
117
0
  }
118
0
}
119
120
0
void child_update(void) {
121
0
  pr_child_t *ch, *chn = NULL;
122
123
0
  if (child_list == NULL) {
124
0
    return;
125
0
  }
126
127
  /* Scan the child list, removing those entries marked as 'dead'. */
128
0
  for (ch = (pr_child_t *) child_list->xas_list; ch; ch = chn) {
129
0
    chn = ch->next;
130
131
0
    if (ch->ch_dead) {
132
0
      if (ch->ch_pipefd != -1) {
133
0
        (void) close(ch->ch_pipefd);
134
0
      }
135
136
0
      xaset_remove(child_list, (xasetmember_t *) ch);
137
0
      destroy_pool(ch->ch_pool);
138
0
    }
139
0
  }
140
141
  /* If the child list is empty, recover the list pool memory. */
142
0
  if (child_list->xas_list == NULL) {
143
0
    destroy_pool(child_list->pool);
144
    child_list = NULL;
145
0
    child_listlen = 0;
146
0
  }
147
0
}