/*
* 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