Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/lib/server_id_watch.c
Line
Count
Source
1
/*
2
 * Unix SMB/CIFS implementation.
3
 * Wait for process death
4
 * Copyright (C) Volker Lendecke 2016
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
#include "includes.h"
21
#include "serverid.h"
22
#include "server_id_watch.h"
23
#include "lib/util/server_id.h"
24
#include "lib/util/tevent_unix.h"
25
#include "lib/util/util_file.h"
26
27
struct server_id_watch_state {
28
  struct tevent_context *ev;
29
  struct server_id pid;
30
  struct timeval start;
31
  struct timeval warn;
32
  bool debug;
33
};
34
35
static void server_id_watch_waited(struct tevent_req *subreq);
36
37
struct tevent_req *server_id_watch_send(TALLOC_CTX *mem_ctx,
38
          struct tevent_context *ev,
39
          struct server_id pid)
40
0
{
41
0
  struct tevent_req *req, *subreq;
42
0
  struct server_id_watch_state *state;
43
0
  struct timeval next;
44
45
0
  req = tevent_req_create(mem_ctx, &state, struct server_id_watch_state);
46
0
  if (req == NULL) {
47
0
    return NULL;
48
0
  }
49
0
  state->ev = ev;
50
0
  state->pid = pid;
51
0
  state->start = tevent_timeval_current();
52
0
  state->warn = tevent_timeval_add(&state->start, 10, 0);
53
54
0
  state->debug = lp_parm_bool(GLOBAL_SECTION_SNUM,
55
0
            "serverid watch",
56
0
            "debug",
57
0
            CHECK_DEBUGLVL(DBGLVL_DEBUG));
58
59
0
  if (!serverid_exists(&state->pid)) {
60
0
    tevent_req_done(req);
61
0
    return tevent_req_post(req, ev);
62
0
  }
63
64
0
  next = tevent_timeval_add(&state->start, 0, 500000);
65
0
  subreq = tevent_wakeup_send(state, ev, next);
66
0
  if (tevent_req_nomem(subreq, req)) {
67
0
    return tevent_req_post(req, ev);
68
0
  }
69
0
  tevent_req_set_callback(subreq, server_id_watch_waited, req);
70
71
0
  return req;
72
0
}
73
74
static void server_id_watch_waited(struct tevent_req *subreq)
75
0
{
76
0
  struct tevent_req *req = tevent_req_callback_data(
77
0
    subreq, struct tevent_req);
78
0
  struct server_id_watch_state *state = tevent_req_data(
79
0
    req, struct server_id_watch_state);
80
0
  struct timeval now;
81
0
  struct timeval next;
82
0
  bool ok;
83
84
0
  ok = tevent_wakeup_recv(subreq);
85
0
  TALLOC_FREE(subreq);
86
0
  if (!ok) {
87
0
    tevent_req_oom(req);
88
0
    return;
89
0
  }
90
91
0
  if (!serverid_exists(&state->pid)) {
92
0
    tevent_req_done(req);
93
0
    return;
94
0
  }
95
96
0
  now = tevent_timeval_current();
97
98
0
  if (!state->debug) {
99
0
    goto next;
100
0
  }
101
102
0
  if (timeval_compare(&state->warn, &now) == -1) {
103
0
    double duration = timeval_elapsed2(&state->start, &now);
104
0
    const char *cmd = NULL;
105
0
    char proc_path[64] = { 0, };
106
0
    char *kstack = NULL;
107
0
    struct server_id_buf buf;
108
0
    const char *pid = server_id_str_buf(state->pid, &buf);
109
0
    int ret;
110
111
0
    state->warn = tevent_timeval_add(&now, 10, 0);
112
113
0
    cmd = lp_parm_const_string(GLOBAL_SECTION_SNUM,
114
0
             "serverid watch",
115
0
             "debug script",
116
0
             NULL);
117
0
    if (cmd != NULL) {
118
0
      char *cmdstr = NULL;
119
0
      char *output = NULL;
120
0
      int fd;
121
122
      /*
123
       * Note in a cluster setup pid will be
124
       * a NOTE:PID like '1:3978365'
125
       *
126
       * Without clustering it is just '3978365'
127
       */
128
0
      cmdstr = talloc_asprintf(state, "%s %s", cmd, pid);
129
0
      if (cmdstr == NULL) {
130
0
        DBG_ERR("Process %s hanging for %f seconds?\n"
131
0
          "talloc_asprintf failed\n",
132
0
          pid, duration);
133
0
        goto next;
134
0
      }
135
136
0
      become_root();
137
0
      ret = smbrun(cmdstr, &fd, NULL);
138
0
      unbecome_root();
139
0
      if (ret != 0) {
140
0
        DBG_ERR("Process %s hanging for %f seconds?\n"
141
0
          "smbrun('%s') failed\n",
142
0
          pid, duration, cmdstr);
143
0
        TALLOC_FREE(cmdstr);
144
0
        goto next;
145
0
      }
146
147
0
      output = fd_load(fd, NULL, 0, state);
148
0
      close(fd);
149
0
      if (output == NULL) {
150
0
        DBG_ERR("Process %s hanging for %f seconds?\n"
151
0
          "fd_load() of smbrun('%s') failed\n",
152
0
          pid, duration, cmdstr);
153
0
        TALLOC_FREE(cmdstr);
154
0
        goto next;
155
0
      }
156
0
      DBG_ERR("Process %s hanging for %f seconds?\n"
157
0
        "%s returned:\n%s",
158
0
        pid, duration, cmdstr, output);
159
0
      TALLOC_FREE(cmdstr);
160
0
      TALLOC_FREE(output);
161
0
      goto next;
162
0
    }
163
164
0
    if (!procid_is_local(&state->pid) || !sys_have_proc_fds()) {
165
0
      DBG_ERR("Process %s hanging for %f seconds?\n",
166
0
        pid, duration);
167
0
      goto next;
168
0
    }
169
170
0
    ret = snprintf(proc_path,
171
0
             ARRAY_SIZE(proc_path),
172
0
             "/proc/%" PRIu64 "/stack",
173
0
             state->pid.pid);
174
0
    if (ret < 0) {
175
0
      DBG_ERR("Process %s hanging for %f seconds?\n"
176
0
        "snprintf failed\n",
177
0
        pid, duration);
178
0
      goto next;
179
0
    }
180
181
0
    become_root();
182
0
    kstack = file_load(proc_path, NULL, 0, state);
183
0
    unbecome_root();
184
0
    if (kstack == NULL) {
185
0
      DBG_ERR("Process %s hanging for %f seconds?\n"
186
0
        "file_load [%s] failed\n",
187
0
        pid, duration, proc_path);
188
0
      goto next;
189
0
    }
190
191
0
    DBG_ERR("Process %s hanging for %f seconds?\n"
192
0
      "%s:\n%s",
193
0
      pid, duration, proc_path, kstack);
194
0
    TALLOC_FREE(kstack);
195
0
  }
196
197
0
next:
198
0
  next = tevent_timeval_add(&now, 0, 500000);
199
0
  subreq = tevent_wakeup_send(state, state->ev, next);
200
0
  if (tevent_req_nomem(subreq, req)) {
201
0
    return;
202
0
  }
203
0
  tevent_req_set_callback(subreq, server_id_watch_waited, req);
204
0
}
205
206
int server_id_watch_recv(struct tevent_req *req, struct server_id *pid)
207
0
{
208
0
  struct server_id_watch_state *state = tevent_req_data(
209
0
    req, struct server_id_watch_state);
210
0
  int err;
211
212
0
  if (tevent_req_is_unix_error(req, &err)) {
213
0
    return err;
214
0
  }
215
0
  if (pid) {
216
0
    *pid = state->pid;
217
0
  }
218
0
  return 0;
219
0
}