/* * Printing background queue helper * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . */ #include "replace.h" #include "system/filesys.h" #include "lib/util/server_id.h" #include "source3/locking/share_mode_lock.h" #include "source3/param/loadparm.h" #include "source3/param/param_proto.h" #include "lib/cmdline/cmdline.h" #include "lib/util/talloc_stack.h" #include "lib/util/debug.h" #include "lib/util/signal.h" #include "lib/util/fault.h" #include "lib/util/become_daemon.h" #include "lib/util/charset/charset.h" #include "lib/util/samba_util.h" #include "lib/util/sys_rw.h" #include "lib/util/pidfile.h" #include "lib/async_req/async_sock.h" #include "dynconfig/dynconfig.h" #include "source3/lib/global_contexts.h" #include "messages.h" #include "nsswitch/winbind_client.h" #include "source3/include/auth.h" #include "source3/lib/util_procid.h" #include "source3/auth/proto.h" #include "source3/printing/queue_process.h" static void watch_handler(struct tevent_req *req) { bool *pdone = tevent_req_callback_data_void(req); *pdone = true; } static void bgqd_sig_term_handler( struct tevent_context *ev, struct tevent_signal *se, int signum, int count, void *siginfo, void *private_data) { bool *pdone = private_data; *pdone = true; } static bool ready_signal_filter( struct messaging_rec *rec, void *private_data) { pid_t pid = getpid(); ssize_t written; if (rec->msg_type != MSG_DAEMON_READY_FD) { return false; } if (rec->num_fds != 1) { return false; } written = sys_write(rec->fds[0], &pid, sizeof(pid)); if (written != sizeof(pid)) { DBG_ERR("Could not write pid: %s\n", strerror(errno)); } return false; } static int samba_bgqd_pidfile_create( struct messaging_context *msg_ctx, const char *progname, int ready_signal_fd) { const char *piddir = lp_pid_directory(); size_t len = strlen(piddir) + strlen(progname) + 6; char pidFile[len]; pid_t existing_pid; int fd, ret; snprintf(pidFile, sizeof(pidFile), "%s/%s.pid", piddir, progname); ret = pidfile_path_create(pidFile, &fd, &existing_pid); if (ret == 0) { struct tevent_req *ready_signal_req = NULL; /* * Listen for fd's sent via MSG_DAEMON_READY_FD: * Multiple instances of this process might have raced * for creating the pidfile. Make sure the parent does * not suffer from this race, reply on behalf of the * loser of this race. */ ready_signal_req = messaging_filtered_read_send( msg_ctx, messaging_tevent_context(msg_ctx), msg_ctx, ready_signal_filter, NULL); if (ready_signal_req == NULL) { DBG_DEBUG("messaging_filtered_read_send failed\n"); pidfile_unlink(piddir, progname); pidfile_fd_close(fd); return ENOMEM; } /* leak fd */ return 0; } if (ret != EAGAIN) { DBG_DEBUG("pidfile_path_create() failed: %s\n", strerror(ret)); return ret; } DBG_DEBUG("%s pid %d exists\n", progname, (int)existing_pid); if (ready_signal_fd != -1) { /* * We lost the race for the pidfile, but someone else * can report readiness on our behalf. */ NTSTATUS status = messaging_send_iov( msg_ctx, pid_to_procid(existing_pid), MSG_DAEMON_READY_FD, NULL, 0, &ready_signal_fd, 1); if (!NT_STATUS_IS_OK(status)) { DBG_DEBUG("Could not send ready_signal_fd: %s\n", nt_errstr(status)); } } return EAGAIN; } static int closeall_except(int *fds, size_t num_fds) { size_t i; int max_keep = -1; int fd, ret; for (i=0; i