9fbdd811ab5f0367f8e0b531c03ed23444e84ae8
[samba.git] / source3 / printing / queue_process.c
1 /*
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    printing backend routines
5    Copyright (C) Andrew Tridgell 1992-2000
6    Copyright (C) Jeremy Allison 2002
7    Copyright (C) Simo Sorce 2011
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "smbd/globals.h"
25 #include "include/messages.h"
26 #include "printing.h"
27 #include "printing/pcap.h"
28 #include "serverid.h"
29 #include "locking/proto.h"
30 #include "smbd/proto.h"
31
32 /****************************************************************************
33  Notify smbds of new printcap data
34 **************************************************************************/
35 static void reload_pcap_change_notify(struct tevent_context *ev,
36                                struct messaging_context *msg_ctx)
37 {
38         message_send_all(msg_ctx, MSG_PRINTER_PCAP, NULL, 0, NULL);
39 }
40
41 static bool print_queue_housekeeping(const struct timeval *now, void *pvt)
42 {
43         struct messaging_context *msg_ctx =
44                 talloc_get_type_abort(pvt, struct messaging_context);
45         time_t printcap_cache_time = (time_t)lp_printcap_cache_time();
46         time_t t = time_mono(NULL);
47
48         DEBUG(5, ("print queue housekeeping\n"));
49
50         /* if periodic printcap rescan is enabled,
51          * see if it's time to reload */
52         if ((printcap_cache_time != 0) &&
53             (t >= (last_printer_reload_time + printcap_cache_time))) {
54                 DEBUG( 3,( "Printcap cache time expired.\n"));
55                 pcap_cache_reload(messaging_event_context(msg_ctx),
56                                   msg_ctx,
57                                   &reload_pcap_change_notify);
58                 last_printer_reload_time = t;
59         }
60
61         return true;
62 }
63
64 static bool printing_subsystem_queue_tasks(struct tevent_context *ev_ctx,
65                                            struct messaging_context *msg_ctx)
66 {
67         if (!(event_add_idle(ev_ctx, NULL,
68                              timeval_set(SMBD_HOUSEKEEPING_INTERVAL, 0),
69                              "print_queue_housekeeping",
70                              print_queue_housekeeping,
71                              msg_ctx))) {
72                 DEBUG(0, ("Could not add print_queue_housekeeping event\n"));
73                 return false;
74         }
75
76         return true;
77 }
78
79 static void bq_sig_term_handler(struct tevent_context *ev,
80                                 struct tevent_signal *se,
81                                 int signum,
82                                 int count,
83                                 void *siginfo,
84                                 void *private_data)
85 {
86         exit_server_cleanly("termination signal");
87 }
88
89 void bq_setup_sig_term_handler(void)
90 {
91         struct tevent_signal *se;
92
93         se = tevent_add_signal(server_event_context(),
94                                server_event_context(),
95                                SIGTERM, 0,
96                                bq_sig_term_handler,
97                                NULL);
98         if (!se) {
99                 exit_server("failed to setup SIGTERM handler");
100         }
101 }
102
103 static void bq_sig_hup_handler(struct tevent_context *ev,
104                                 struct tevent_signal *se,
105                                 int signum,
106                                 int count,
107                                 void *siginfo,
108                                 void *pvt)
109 {
110         struct messaging_context *msg_ctx;
111
112         msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
113         change_to_root_user();
114
115         DEBUG(1, ("Reloading pcap cache after SIGHUP\n"));
116         pcap_cache_reload(ev, msg_ctx, &reload_pcap_change_notify);
117 }
118
119 static void bq_setup_sig_hup_handler(struct tevent_context *ev,
120                                      struct messaging_context *msg_ctx)
121 {
122         struct tevent_signal *se;
123
124         se = tevent_add_signal(ev, ev, SIGHUP, 0, bq_sig_hup_handler,
125                                msg_ctx);
126         if (!se) {
127                 exit_server("failed to setup SIGHUP handler");
128         }
129 }
130
131 static void bq_smb_conf_updated(struct messaging_context *msg_ctx,
132                                 void *private_data,
133                                 uint32_t msg_type,
134                                 struct server_id server_id,
135                                 DATA_BLOB *data)
136 {
137         struct tevent_context *ev_ctx =
138                 talloc_get_type_abort(private_data, struct tevent_context);
139
140         DEBUG(10,("smb_conf_updated: Got message saying smb.conf was "
141                   "updated. Reloading.\n"));
142         change_to_root_user();
143         pcap_cache_reload(ev_ctx, msg_ctx, &reload_pcap_change_notify);
144 }
145
146 static void printing_pause_fd_handler(struct tevent_context *ev,
147                                       struct tevent_fd *fde,
148                                       uint16_t flags,
149                                       void *private_data)
150 {
151         /*
152          * If pause_pipe[1] is closed it means the parent smbd
153          * and children exited or aborted.
154          */
155         exit_server_cleanly(NULL);
156 }
157
158 extern struct child_pid *children;
159 extern int num_children;
160
161 static void add_child_pid(pid_t pid)
162 {
163         struct child_pid *child;
164
165         child = SMB_MALLOC_P(struct child_pid);
166         if (child == NULL) {
167                 DEBUG(0, ("Could not add child struct -- malloc failed\n"));
168                 return;
169         }
170         child->pid = pid;
171         DLIST_ADD(children, child);
172         num_children += 1;
173 }
174
175 pid_t background_lpq_updater_pid = -1;
176
177 /****************************************************************************
178 main thread of the background lpq updater
179 ****************************************************************************/
180 static void start_background_queue(struct tevent_context *ev,
181                                    struct messaging_context *msg_ctx)
182 {
183         /* Use local variables for this as we don't
184          * need to save the parent side of this, just
185          * ensure it closes when the process exits.
186          */
187         int pause_pipe[2];
188
189         DEBUG(3,("start_background_queue: Starting background LPQ thread\n"));
190
191         if (pipe(pause_pipe) == -1) {
192                 DEBUG(5,("start_background_queue: cannot create pipe. %s\n", strerror(errno) ));
193                 exit(1);
194         }
195
196         background_lpq_updater_pid = sys_fork();
197
198         if (background_lpq_updater_pid == -1) {
199                 DEBUG(5,("start_background_queue: background LPQ thread failed to start. %s\n", strerror(errno) ));
200                 exit(1);
201         }
202
203         /* Track the printing pid along with other smbd children */
204         add_child_pid(background_lpq_updater_pid);
205
206         if(background_lpq_updater_pid == 0) {
207                 struct tevent_fd *fde;
208                 int ret;
209                 NTSTATUS status;
210
211                 /* Child. */
212                 DEBUG(5,("start_background_queue: background LPQ thread started\n"));
213
214                 close(pause_pipe[0]);
215                 pause_pipe[0] = -1;
216
217                 status = reinit_after_fork(msg_ctx, ev, procid_self(), true);
218
219                 if (!NT_STATUS_IS_OK(status)) {
220                         DEBUG(0,("reinit_after_fork() failed\n"));
221                         smb_panic("reinit_after_fork() failed");
222                 }
223
224                 bq_setup_sig_term_handler();
225                 bq_setup_sig_hup_handler(ev, msg_ctx);
226
227                 if (!printing_subsystem_queue_tasks(ev, msg_ctx)) {
228                         exit(1);
229                 }
230
231                 if (!serverid_register(procid_self(),
232                                        FLAG_MSG_GENERAL|FLAG_MSG_SMBD
233                                        |FLAG_MSG_PRINT_GENERAL)) {
234                         exit(1);
235                 }
236
237                 if (!locking_init()) {
238                         exit(1);
239                 }
240
241                 messaging_register(msg_ctx, ev, MSG_SMB_CONF_UPDATED,
242                                    bq_smb_conf_updated);
243                 messaging_register(msg_ctx, NULL, MSG_PRINTER_UPDATE,
244                                    print_queue_receive);
245
246                 fde = tevent_add_fd(ev, ev, pause_pipe[1], TEVENT_FD_READ,
247                                     printing_pause_fd_handler,
248                                     NULL);
249                 if (!fde) {
250                         DEBUG(0,("tevent_add_fd() failed for pause_pipe\n"));
251                         smb_panic("tevent_add_fd() failed for pause_pipe");
252                 }
253
254                 DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n"));
255                 ret = tevent_loop_wait(ev);
256                 /* should not be reached */
257                 DEBUG(0,("background_queue: tevent_loop_wait() exited with %d - %s\n",
258                          ret, (ret == 0) ? "out of events" : strerror(errno)));
259                 exit(1);
260         }
261
262         close(pause_pipe[1]);
263 }
264
265 static bool use_background_queue;
266
267 /* Run before the parent forks */
268 bool printing_subsystem_init(struct tevent_context *ev_ctx,
269                              struct messaging_context *msg_ctx,
270                              bool background_queue)
271 {
272         bool ret = true;
273
274         use_background_queue = background_queue;
275
276         /* Publish nt printers, this requires a working winreg pipe */
277         pcap_cache_reload(ev_ctx, msg_ctx, &reload_printers);
278
279         if (background_queue) {
280                 start_background_queue(ev_ctx, msg_ctx);
281         } else {
282                 ret = printing_subsystem_queue_tasks(ev_ctx, msg_ctx);
283         }
284
285         return ret;
286 }
287
288 void printing_subsystem_update(struct tevent_context *ev_ctx,
289                                struct messaging_context *msg_ctx)
290 {
291         if (use_background_queue) return;
292
293         pcap_cache_reload(ev_ctx, msg_ctx, &reload_pcap_change_notify);
294 }