2 * Printing background queue helper
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 #include "system/filesys.h"
20 #include "lib/util/server_id.h"
21 #include "source3/locking/share_mode_lock.h"
22 #include "source3/param/loadparm.h"
23 #include "source3/param/param_proto.h"
24 #include "lib/cmdline/cmdline.h"
25 #include "lib/cmdline/closefrom_except.h"
26 #include "lib/util/talloc_stack.h"
27 #include "lib/util/debug.h"
28 #include "lib/util/signal.h"
29 #include "lib/util/fault.h"
30 #include "lib/util/become_daemon.h"
31 #include "lib/util/charset/charset.h"
32 #include "lib/util/samba_util.h"
33 #include "lib/util/sys_rw.h"
34 #include "lib/util/pidfile.h"
35 #include "lib/async_req/async_sock.h"
36 #include "dynconfig/dynconfig.h"
37 #include "source3/lib/global_contexts.h"
39 #include "nsswitch/winbind_client.h"
40 #include "source3/include/auth.h"
41 #include "source3/lib/util_procid.h"
42 #include "source3/auth/proto.h"
43 #include "source3/printing/queue_process.h"
44 #include "source3/lib/substitute.h"
46 static void watch_handler(struct tevent_req
*req
)
48 bool *pdone
= tevent_req_callback_data_void(req
);
52 static void bgqd_sig_term_handler(
53 struct tevent_context
*ev
,
54 struct tevent_signal
*se
,
60 bool *pdone
= private_data
;
64 static bool ready_signal_filter(
65 struct messaging_rec
*rec
, void *private_data
)
70 if (rec
->msg_type
!= MSG_DAEMON_READY_FD
) {
73 if (rec
->num_fds
!= 1) {
77 written
= sys_write(rec
->fds
[0], &pid
, sizeof(pid
));
78 if (written
!= sizeof(pid
)) {
79 DBG_ERR("Could not write pid: %s\n", strerror(errno
));
85 static int samba_bgqd_pidfile_create(
86 struct messaging_context
*msg_ctx
,
90 const char *piddir
= lp_pid_directory();
91 size_t len
= strlen(piddir
) + strlen(progname
) + 6;
101 ret
= pidfile_path_create(pidFile
, &fd
, &existing_pid
);
103 struct tevent_req
*ready_signal_req
= NULL
;
106 * Listen for fd's sent via MSG_DAEMON_READY_FD:
107 * Multiple instances of this process might have raced
108 * for creating the pidfile. Make sure the parent does
109 * not suffer from this race, reply on behalf of the
110 * loser of this race.
113 ready_signal_req
= messaging_filtered_read_send(
115 messaging_tevent_context(msg_ctx
),
119 if (ready_signal_req
== NULL
) {
120 DBG_DEBUG("messaging_filtered_read_send failed\n");
121 pidfile_unlink(piddir
, progname
);
122 pidfile_fd_close(fd
);
131 DBG_DEBUG("pidfile_path_create() failed: %s\n",
136 DBG_DEBUG("%s pid %d exists\n", progname
, (int)existing_pid
);
138 if (ready_signal_fd
!= -1) {
140 * We lost the race for the pidfile, but someone else
141 * can report readiness on our behalf.
143 NTSTATUS status
= messaging_send_iov(
145 pid_to_procid(existing_pid
),
151 if (!NT_STATUS_IS_OK(status
)) {
152 DBG_DEBUG("Could not send ready_signal_fd: %s\n",
160 int main(int argc
, const char *argv
[])
162 struct samba_cmdline_daemon_cfg
*cmdline_daemon_cfg
= NULL
;
163 const struct loadparm_substitution
*lp_sub
=
164 loadparm_s3_global_substitution();
165 const char *progname
= getprogname();
166 TALLOC_CTX
*frame
= NULL
;
168 struct messaging_context
*msg_ctx
= NULL
;
169 struct tevent_context
*ev
= NULL
;
170 struct tevent_req
*watch_req
= NULL
;
171 struct tevent_signal
*sigterm_handler
= NULL
;
172 struct bq_state
*bq
= NULL
;
174 int ready_signal_fd
= -1;
182 struct poptOption long_options
[] = {
188 * File descriptor to write the PID of the helper
192 .longName
= "ready-signal-fd",
193 .argInfo
= POPT_ARG_INT
,
194 .arg
= &ready_signal_fd
,
195 .descrip
= "Fd to signal readiness to" ,
199 * Read end of a pipe held open by the parent
200 * smbd. Exit this process when it becomes readable.
203 .longName
= "parent-watch-fd",
204 .argInfo
= POPT_ARG_INT
,
206 .descrip
= "Fd to watch for exiting",
212 const char *fd_params
[] = {
213 "ready-signal-fd", "parent-watch-fd",
216 closefrom_except_fd_params(
217 3, ARRAY_SIZE(fd_params
), fd_params
, argc
, argv
);
220 talloc_enable_null_tracking();
221 frame
= talloc_stackframe();
223 set_remote_machine_name("smbd-bgqd", true);
225 ok
= samba_cmdline_init(frame
,
226 SAMBA_CMDLINE_CONFIG_SERVER
,
227 true /* require_smbconf */);
229 DBG_ERR("Failed to setup cmdline parser!\n");
233 cmdline_daemon_cfg
= samba_cmdline_get_daemon_cfg();
235 pc
= samba_popt_get_context(progname
,
241 DBG_ERR("Failed to get popt context!\n");
245 ret
= poptGetNextOpt(pc
);
247 fprintf(stderr
, "invalid options: %s\n", poptStrerror(ret
));
253 log_stdout
= (debug_get_log_type() == DEBUG_STDOUT
);
255 /* main process will notify systemd */
256 daemon_sd_notifications(false);
258 if (!cmdline_daemon_cfg
->fork
) {
259 daemon_status(progname
, "Starting process ... ");
262 cmdline_daemon_cfg
->no_process_group
,
266 BlockSignals(true, SIGPIPE
);
269 dump_core_setup(progname
, lp_logfile(frame
, lp_sub
));
271 msg_ctx
= global_messaging_context();
272 if (msg_ctx
== NULL
) {
273 DBG_ERR("messaging_init() failed\n");
276 ev
= messaging_tevent_context(msg_ctx
);
278 ret
= samba_bgqd_pidfile_create(msg_ctx
, progname
, ready_signal_fd
);
283 if (watch_fd
!= -1) {
284 watch_req
= wait_for_read_send(ev
, ev
, watch_fd
, true);
285 if (watch_req
== NULL
) {
286 fprintf(stderr
, "tevent_add_fd failed\n");
289 tevent_req_set_callback(watch_req
, watch_handler
, &done
);
293 ok
= init_guest_session_info(frame
);
296 DBG_ERR("init_guest_session_info failed\n");
301 status
= init_system_session_info(frame
);
303 if (!NT_STATUS_IS_OK(status
)) {
304 DBG_ERR("init_system_session_info failed: %s\n",
309 sigterm_handler
= tevent_add_signal(
310 ev
, frame
, SIGTERM
, 0, bgqd_sig_term_handler
, &done
);
311 if (sigterm_handler
== NULL
) {
312 DBG_ERR("Could not install SIGTERM handler\n");
316 bq
= register_printing_bq_handlers(frame
, msg_ctx
);
318 DBG_ERR("Could not register bq handlers\n");
324 DBG_ERR("locking_init failed\n");
328 if (ready_signal_fd
!= -1) {
329 pid_t pid
= getpid();
332 written
= sys_write(ready_signal_fd
, &pid
, sizeof(pid
));
333 if (written
!= sizeof(pid
)) {
334 DBG_ERR("Reporting readiness failed\n");
337 close(ready_signal_fd
);
338 ready_signal_fd
= -1;
342 TALLOC_CTX
*tmp
= talloc_stackframe();
343 ret
= tevent_loop_once(ev
);
346 DBG_ERR("tevent_loop_once failed\n");
353 TALLOC_FREE(watch_req
);
355 TALLOC_FREE(sigterm_handler
);
356 global_messaging_context_free();