s3-spoolssd: Use the prefork framework in spoolssd
[Samba/gbeck.git] / source3 / printing / spoolssd.c
blobe7bee0e0ebd379b9c27d606367c1b55ce09413d4
1 /*
2 Unix SMB/Netbios implementation.
3 SPOOLSS Daemon
4 Copyright (C) Simo Sorce 2010
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.
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.
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/>.
19 #include "includes.h"
20 #include "serverid.h"
21 #include "smbd/smbd.h"
23 #include "messages.h"
24 #include "include/printing.h"
25 #include "printing/nt_printing_migrate_internal.h"
26 #include "ntdomain.h"
27 #include "librpc/gen_ndr/srv_winreg.h"
28 #include "librpc/gen_ndr/srv_spoolss.h"
29 #include "rpc_server/rpc_server.h"
30 #include "rpc_server/rpc_ep_register.h"
31 #include "rpc_server/spoolss/srv_spoolss_nt.h"
32 #include "librpc/rpc/dcerpc_ep.h"
33 #include "lib/server_prefork.h"
35 #define SPOOLSS_PIPE_NAME "spoolss"
36 #define DAEMON_NAME "spoolssd"
38 #define SPOOLSS_MIN_CHILDREN 5
39 #define SPOOLSS_MAX_CHILDREN 25
40 #define SPOOLSS_SPAWN_RATE 5
41 #define SPOOLSS_MIN_LIFE 60 /* 1 minute minimum life time */
43 void start_spoolssd(struct tevent_context *ev_ctx,
44 struct messaging_context *msg_ctx);
46 static void spoolss_reopen_logs(void)
48 char *lfile = lp_logfile();
49 int rc;
51 if (lfile == NULL || lfile[0] == '\0') {
52 rc = asprintf(&lfile, "%s/log.%s", get_dyn_LOGFILEBASE(), DAEMON_NAME);
53 if (rc > 0) {
54 lp_set_logfile(lfile);
55 SAFE_FREE(lfile);
57 } else {
58 if (strstr(lfile, DAEMON_NAME) == NULL) {
59 rc = asprintf(&lfile, "%s.%s", lp_logfile(), DAEMON_NAME);
60 if (rc > 0) {
61 lp_set_logfile(lfile);
62 SAFE_FREE(lfile);
67 reopen_logs();
70 static void smb_conf_updated(struct messaging_context *msg,
71 void *private_data,
72 uint32_t msg_type,
73 struct server_id server_id,
74 DATA_BLOB *data)
76 struct tevent_context *ev_ctx = talloc_get_type_abort(private_data,
77 struct tevent_context);
79 DEBUG(10, ("Got message saying smb.conf was updated. Reloading.\n"));
80 change_to_root_user();
81 reload_printers(ev_ctx, msg);
82 spoolss_reopen_logs();
85 static void spoolss_sig_term_handler(struct tevent_context *ev,
86 struct tevent_signal *se,
87 int signum,
88 int count,
89 void *siginfo,
90 void *private_data)
92 exit_server_cleanly("termination signal");
95 static void spoolss_setup_sig_term_handler(struct tevent_context *ev_ctx)
97 struct tevent_signal *se;
99 se = tevent_add_signal(ev_ctx,
100 ev_ctx,
101 SIGTERM, 0,
102 spoolss_sig_term_handler,
103 NULL);
104 if (!se) {
105 exit_server("failed to setup SIGTERM handler");
109 static void spoolss_sig_hup_handler(struct tevent_context *ev,
110 struct tevent_signal *se,
111 int signum,
112 int count,
113 void *siginfo,
114 void *pvt)
116 struct messaging_context *msg_ctx;
118 msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
120 change_to_root_user();
121 DEBUG(1,("Reloading printers after SIGHUP\n"));
122 reload_printers(ev, msg_ctx);
123 spoolss_reopen_logs();
126 static void spoolss_setup_sig_hup_handler(struct tevent_context *ev_ctx,
127 struct messaging_context *msg_ctx)
129 struct tevent_signal *se;
131 se = tevent_add_signal(ev_ctx,
132 ev_ctx,
133 SIGHUP, 0,
134 spoolss_sig_hup_handler,
135 msg_ctx);
136 if (!se) {
137 exit_server("failed to setup SIGHUP handler");
141 static bool spoolss_init_cb(void *ptr)
143 struct messaging_context *msg_ctx = talloc_get_type_abort(
144 ptr, struct messaging_context);
146 return nt_printing_tdb_migrate(msg_ctx);
149 static bool spoolss_shutdown_cb(void *ptr)
151 srv_spoolss_cleanup();
153 return true;
156 /* Childrens */
158 struct spoolss_chld_sig_hup_ctx {
159 struct messaging_context *msg_ctx;
160 struct pf_worker_data *pf;
163 static void spoolss_chld_sig_hup_handler(struct tevent_context *ev,
164 struct tevent_signal *se,
165 int signum,
166 int count,
167 void *siginfo,
168 void *pvt)
170 struct spoolss_chld_sig_hup_ctx *shc;
172 shc = talloc_get_type_abort(pvt, struct spoolss_chld_sig_hup_ctx);
174 /* avoid wasting CPU cycles if we are going to exit soon anyways */
175 if (shc->pf != NULL &&
176 shc->pf->cmds == PF_SRV_MSG_EXIT) {
177 return;
180 change_to_root_user();
181 DEBUG(1,("Reloading printers after SIGHUP\n"));
182 reload_printers(ev, shc->msg_ctx);
183 spoolss_reopen_logs();
186 static bool spoolss_setup_chld_hup_handler(struct tevent_context *ev_ctx,
187 struct pf_worker_data *pf,
188 struct messaging_context *msg_ctx)
190 struct spoolss_chld_sig_hup_ctx *shc;
191 struct tevent_signal *se;
193 shc = talloc(ev_ctx, struct spoolss_chld_sig_hup_ctx);
194 if (!shc) {
195 DEBUG(1, ("failed to setup SIGHUP handler"));
196 return false;
198 shc->pf = pf;
199 shc->msg_ctx = msg_ctx;
201 se = tevent_add_signal(ev_ctx,
202 ev_ctx,
203 SIGHUP, 0,
204 spoolss_chld_sig_hup_handler,
205 shc);
206 if (!se) {
207 DEBUG(1, ("failed to setup SIGHUP handler"));
208 return false;
211 return true;
214 static bool spoolss_child_init(struct tevent_context *ev_ctx,
215 struct pf_worker_data *pf)
217 NTSTATUS status;
218 struct rpc_srv_callbacks spoolss_cb;
219 struct messaging_context *msg_ctx = server_messaging_context();
220 bool ok;
222 status = reinit_after_fork(msg_ctx, ev_ctx,
223 procid_self(), true);
224 if (!NT_STATUS_IS_OK(status)) {
225 DEBUG(0,("reinit_after_fork() failed\n"));
226 smb_panic("reinit_after_fork() failed");
229 spoolss_reopen_logs();
231 ok = spoolss_setup_chld_hup_handler(ev_ctx, pf, msg_ctx);
232 if (!ok) {
233 return false;
236 if (!serverid_register(procid_self(), FLAG_MSG_GENERAL)) {
237 return false;
240 if (!locking_init()) {
241 return false;
244 messaging_register(msg_ctx, ev_ctx,
245 MSG_SMB_CONF_UPDATED, smb_conf_updated);
247 /* try to reinit rpc queues */
248 spoolss_cb.init = spoolss_init_cb;
249 spoolss_cb.shutdown = spoolss_shutdown_cb;
250 spoolss_cb.private_data = msg_ctx;
252 status = rpc_winreg_init(NULL);
253 if (!NT_STATUS_IS_OK(status)) {
254 DEBUG(0, ("Failed to register winreg rpc inteface! (%s)\n",
255 nt_errstr(status)));
256 return false;
259 status = rpc_spoolss_init(&spoolss_cb);
260 if (!NT_STATUS_IS_OK(status)) {
261 DEBUG(0, ("Failed to register spoolss rpc inteface! (%s)\n",
262 nt_errstr(status)));
263 return false;
266 reload_printers(ev_ctx, msg_ctx);
268 return true;
271 struct spoolss_children_data {
272 struct tevent_context *ev_ctx;
273 struct messaging_context *msg_ctx;
274 struct pf_worker_data *pf;
275 int listen_fd;
276 int lock_fd;
279 static void spoolss_schedule_loop(void *pvt);
280 static void spoolss_children_loop(struct tevent_context *ev_ctx,
281 struct tevent_immediate *im,
282 void *pvt);
284 static int spoolss_children_main(struct tevent_context *ev_ctx,
285 struct pf_worker_data *pf,
286 int listen_fd, int lock_fd,
287 void *private_data)
289 struct messaging_context *msg_ctx = server_messaging_context();
290 struct spoolss_children_data *data;
291 bool ok;
292 int ret;
294 ok = spoolss_child_init(ev_ctx, pf);
295 if (!ok) {
296 return 1;
299 data = talloc(ev_ctx, struct spoolss_children_data);
300 if (!data) {
301 return 1;
303 data->pf = pf;
304 data->ev_ctx = ev_ctx;
305 data->msg_ctx = msg_ctx;
306 data->lock_fd = lock_fd;
307 data->listen_fd = listen_fd;
309 spoolss_schedule_loop(data);
311 /* loop until it is time to exit */
312 while (pf->status != PF_WORKER_EXITING) {
313 ret = tevent_loop_once(ev_ctx);
314 if (ret != 0) {
315 DEBUG(0, ("tevent_loop_once() exited with %d: %s\n",
316 ret, strerror(errno)));
317 pf->status = PF_WORKER_EXITING;
321 return ret;
324 static void spoolss_client_terminated(void *pvt)
326 struct spoolss_children_data *data;
328 data = talloc_get_type_abort(pvt, struct spoolss_children_data);
330 if (data->pf->num_clients) {
331 data->pf->num_clients--;
332 } else {
333 DEBUG(2, ("Invalid num clients, aborting!\n"));
334 data->pf->status = PF_WORKER_EXITING;
335 return;
338 spoolss_schedule_loop(pvt);
341 static void spoolss_schedule_loop(void *pvt)
343 struct spoolss_children_data *data;
344 struct tevent_immediate *im;
346 data = talloc_get_type_abort(pvt, struct spoolss_children_data);
348 if (data->pf->num_clients == 0) {
349 data->pf->status = PF_WORKER_IDLE;
352 if (data->pf->cmds == PF_SRV_MSG_EXIT) {
353 DEBUG(2, ("Parent process commands we terminate!\n"));
354 return;
357 im = tevent_create_immediate(data);
358 if (!im) {
359 DEBUG(1, ("Failed to create immediate event!\n"));
360 return;
363 tevent_schedule_immediate(im, data->ev_ctx,
364 spoolss_children_loop, data);
367 static void spoolss_children_loop(struct tevent_context *ev_ctx,
368 struct tevent_immediate *im,
369 void *pvt)
371 struct spoolss_children_data *data;
372 struct sockaddr_un sunaddr;
373 socklen_t addrlen = sizeof(sunaddr);
374 int ret;
375 int sd;
377 data = talloc_get_type_abort(pvt, struct spoolss_children_data);
380 /* FIXME: this call is blocking. */
381 ret = prefork_wait_for_client(data->pf, data->lock_fd, data->listen_fd,
382 (struct sockaddr *)(void *)&sunaddr,
383 &addrlen, &sd);
384 if (ret > 0) {
385 DEBUG(1, ("Failed to accept connection!\n"));
386 return;
389 if (ret == -2) {
390 DEBUG(1, ("Server asks us to die!\n"));
391 data->pf->status = PF_WORKER_EXITING;
392 return;
395 DEBUG(2, ("Spoolss preforked child %d activated!\n",
396 (int)(data->pf->pid)));
398 named_pipe_accept_function(data->ev_ctx, data->msg_ctx,
399 SPOOLSS_PIPE_NAME, sd,
400 spoolss_client_terminated, data);
403 /* ==== Main Process Functions ==== */
405 static void spoolssd_sig_chld_handler(struct tevent_context *ev_ctx,
406 struct tevent_signal *se,
407 int signum, int count,
408 void *siginfo, void *pvt)
410 struct prefork_pool *pfp;
411 pid_t pid;
412 int status;
413 bool ok;
414 int active, total;
415 int n, r;
417 pfp = talloc_get_type_abort(pvt, struct prefork_pool);
419 while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
420 ok = prefork_mark_pid_dead(pfp, pid);
421 if (!ok) {
422 DEBUG(1, ("Pid %d was not found in children pool!\n",
423 (int)pid));
427 /* now check we do not descent below the minimum */
428 active = prefork_count_active_children(pfp, &total);
430 n = 0;
431 if (total < SPOOLSS_MIN_CHILDREN) {
432 n = total - SPOOLSS_MIN_CHILDREN;
433 } else if (total - active < (total / 4)) {
434 n = SPOOLSS_MIN_CHILDREN;
437 if (n > 0) {
438 r = prefork_add_children(ev_ctx, pfp, n);
439 if (r < n) {
440 DEBUG(10, ("Tried to start %d children but only,"
441 "%d were actually started.!\n", n, r));
448 static bool spoolssd_setup_sig_chld_handler(struct tevent_context *ev_ctx,
449 struct prefork_pool *pfp)
451 struct tevent_signal *se;
453 se = tevent_add_signal(ev_ctx, ev_ctx, SIGCHLD, 0,
454 spoolssd_sig_chld_handler, pfp);
455 if (!se) {
456 DEBUG(0, ("Failed to setup SIGCHLD handler!\n"));
457 return false;
460 return true;
463 static bool spoolssd_schedule_check(struct tevent_context *ev_ctx,
464 struct prefork_pool *pfp,
465 struct timeval current_time);
466 static void spoolssd_check_children(struct tevent_context *ev_ctx,
467 struct tevent_timer *te,
468 struct timeval current_time,
469 void *pvt);
471 static bool spoolssd_setup_children_monitor(struct tevent_context *ev_ctx,
472 struct prefork_pool *pfp)
474 bool ok;
476 ok = spoolssd_setup_sig_chld_handler(ev_ctx, pfp);
477 if (!ok) {
478 return false;
481 ok = spoolssd_schedule_check(ev_ctx, pfp, tevent_timeval_current());
482 return ok;
485 static bool spoolssd_schedule_check(struct tevent_context *ev_ctx,
486 struct prefork_pool *pfp,
487 struct timeval current_time)
489 struct tevent_timer *te;
490 struct timeval next_event;
492 /* check situation again in 10 seconds */
493 next_event = tevent_timeval_current_ofs(10, 0);
495 /* check when the socket becomes readable, so that children
496 * are checked only when there is some activity */
497 te = tevent_add_timer(ev_ctx, pfp, next_event,
498 spoolssd_check_children, pfp);
499 if (!te) {
500 DEBUG(2, ("Failed to set up children monitoring!\n"));
501 return false;
504 return true;
507 static void spoolssd_check_children(struct tevent_context *ev_ctx,
508 struct tevent_timer *te,
509 struct timeval current_time,
510 void *pvt)
512 struct prefork_pool *pfp;
513 int active, total;
514 int ret, n;
516 pfp = talloc_get_type_abort(pvt, struct prefork_pool);
518 active = prefork_count_active_children(pfp, &total);
520 if (total - active < SPOOLSS_SPAWN_RATE) {
521 n = prefork_add_children(ev_ctx, pfp, SPOOLSS_SPAWN_RATE);
522 if (n < SPOOLSS_SPAWN_RATE) {
523 DEBUG(10, ("Tried to start 5 children but only,"
524 "%d were actually started.!\n", n));
528 if (total - active > SPOOLSS_MIN_CHILDREN) {
529 if ((total - SPOOLSS_MIN_CHILDREN) >= SPOOLSS_SPAWN_RATE) {
530 prefork_retire_children(pfp, SPOOLSS_SPAWN_RATE,
531 time(NULL) - SPOOLSS_MIN_LIFE);
535 ret = spoolssd_schedule_check(ev_ctx, pfp, current_time);
538 void start_spoolssd(struct tevent_context *ev_ctx,
539 struct messaging_context *msg_ctx)
541 struct prefork_pool *pool;
542 struct rpc_srv_callbacks spoolss_cb;
543 struct dcerpc_binding_vector *v;
544 TALLOC_CTX *mem_ctx;
545 pid_t pid;
546 NTSTATUS status;
547 int listen_fd;
548 int ret;
549 bool ok;
551 DEBUG(1, ("Forking SPOOLSS Daemon\n"));
553 pid = sys_fork();
555 if (pid == -1) {
556 DEBUG(0, ("Failed to fork SPOOLSS [%s], aborting ...\n",
557 strerror(errno)));
558 exit(1);
561 if (pid) {
562 /* parent */
563 return;
566 /* child */
567 close_low_fds(false);
569 status = reinit_after_fork(msg_ctx,
570 ev_ctx,
571 procid_self(), true);
572 if (!NT_STATUS_IS_OK(status)) {
573 DEBUG(0,("reinit_after_fork() failed\n"));
574 smb_panic("reinit_after_fork() failed");
577 spoolss_reopen_logs();
579 /* the listening fd must be created before the children are actually
580 * forked out. */
581 listen_fd = create_named_pipe_socket(SPOOLSS_PIPE_NAME);
582 if (listen_fd == -1) {
583 exit(1);
586 ret = listen(listen_fd, SPOOLSS_MAX_CHILDREN);
587 if (ret == -1) {
588 DEBUG(0, ("Failed to listen on spoolss pipe - %s\n",
589 strerror(errno)));
590 exit(1);
594 /* start children before any more initialization is done */
595 ok = prefork_create_pool(ev_ctx, ev_ctx, listen_fd,
596 SPOOLSS_MIN_CHILDREN,
597 SPOOLSS_MAX_CHILDREN,
598 &spoolss_children_main, NULL,
599 &pool);
601 spoolss_setup_sig_term_handler(ev_ctx);
602 spoolss_setup_sig_hup_handler(ev_ctx, msg_ctx);
604 if (!serverid_register(procid_self(),
605 FLAG_MSG_GENERAL|FLAG_MSG_SMBD
606 |FLAG_MSG_PRINT_GENERAL)) {
607 exit(1);
610 if (!locking_init()) {
611 exit(1);
614 messaging_register(msg_ctx, NULL,
615 MSG_PRINTER_UPDATE, print_queue_receive);
616 messaging_register(msg_ctx, ev_ctx,
617 MSG_SMB_CONF_UPDATED, smb_conf_updated);
619 mem_ctx = talloc_new(NULL);
620 if (mem_ctx == NULL) {
621 exit(1);
625 * Initialize spoolss with an init function to convert printers first.
626 * static_init_rpc will try to initialize the spoolss server too but you
627 * can't register it twice.
629 spoolss_cb.init = spoolss_init_cb;
630 spoolss_cb.shutdown = spoolss_shutdown_cb;
631 spoolss_cb.private_data = msg_ctx;
633 status = rpc_winreg_init(NULL);
634 if (!NT_STATUS_IS_OK(status)) {
635 DEBUG(0, ("Failed to register winreg rpc inteface! (%s)\n",
636 nt_errstr(status)));
637 exit(1);
640 status = rpc_spoolss_init(&spoolss_cb);
641 if (!NT_STATUS_IS_OK(status)) {
642 DEBUG(0, ("Failed to register spoolss rpc inteface! (%s)\n",
643 nt_errstr(status)));
644 exit(1);
647 status = dcerpc_binding_vector_new(mem_ctx, &v);
648 if (!NT_STATUS_IS_OK(status)) {
649 DEBUG(0, ("Failed to create binding vector (%s)\n",
650 nt_errstr(status)));
651 exit(1);
654 status = dcerpc_binding_vector_add_np_default(&ndr_table_spoolss, v);
655 if (!NT_STATUS_IS_OK(status)) {
656 DEBUG(0, ("Failed to add np to binding vector (%s)\n",
657 nt_errstr(status)));
658 exit(1);
661 status = rpc_ep_register(ev_ctx, msg_ctx, &ndr_table_spoolss, v);
662 if (!NT_STATUS_IS_OK(status)) {
663 DEBUG(0, ("Failed to register spoolss endpoint! (%s)\n",
664 nt_errstr(status)));
665 exit(1);
668 talloc_free(mem_ctx);
670 ok = spoolssd_setup_children_monitor(ev_ctx, pool);
671 if (!ok) {
672 DEBUG(0, ("Failed to setup children monitoring!\n"));
673 exit(1);
676 reload_printers(ev_ctx, msg_ctx);
678 DEBUG(1, ("SPOOLSS Daemon Started (%d)\n", getpid()));
680 /* loop forever */
681 ret = tevent_loop_wait(ev_ctx);
683 /* should not be reached */
684 DEBUG(0,("background_queue: tevent_loop_wait() exited with %d - %s\n",
685 ret, (ret == 0) ? "out of events" : strerror(errno)));
686 exit(1);