OpenDNSSEC-signer  1.4.3
cmdhandler.c
Go to the documentation of this file.
1 /*
2  * $Id: cmdhandler.c 7416 2013-11-21 08:34:02Z matthijs $
3  *
4  * Copyright (c) 2009 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "daemon/cmdhandler.h"
35 #include "daemon/engine.h"
36 #include "shared/allocator.h"
37 #include "shared/file.h"
38 #include "shared/locks.h"
39 #include "shared/log.h"
40 #include "shared/status.h"
41 #include "shared/util.h"
42 
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <ldns/ldns.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <sys/select.h>
51 #include <sys/socket.h>
52 #ifdef HAVE_SYS_TYPES_H
53 # include <sys/types.h>
54 #endif
55 #include <unistd.h>
56 /* According to earlier standards: select() sys/time.h sys/types.h unistd.h */
57 #include <sys/time.h>
58 #include <sys/types.h>
59 
60 #define SE_CMDH_CMDLEN 7
61 
62 #ifndef SUN_LEN
63 #define SUN_LEN(su) (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
64 #endif
65 
66 static int count = 0;
67 static char* cmdh_str = "cmdhandler";
68 
69 
74 static void
75 cmdhandler_handle_cmd_help(int sockfd)
76 {
77  char buf[ODS_SE_MAXLINE];
78 
79  (void) snprintf(buf, ODS_SE_MAXLINE,
80  "Commands:\n"
81  "zones Show the currently known zones.\n"
82  "sign <zone> [--serial <nr>] Read zone and schedule for immediate "
83  "(re-)sign.\n"
84  " If a serial is given, that serial is used "
85  "in the output zone.\n"
86  "sign --all Read all zones and schedule all for "
87  "immediate (re-)sign.\n"
88  );
89  ods_writen(sockfd, buf, strlen(buf));
90 
91  (void) snprintf(buf, ODS_SE_MAXLINE,
92  "clear <zone> Delete the internal storage of this "
93  "zone.\n"
94  " All signatures will be regenerated "
95  "on the next re-sign.\n"
96  "queue Show the current task queue.\n"
97  "flush Execute all scheduled tasks "
98  "immediately.\n"
99  );
100  ods_writen(sockfd, buf, strlen(buf));
101 
102  (void) snprintf(buf, ODS_SE_MAXLINE,
103  "update <zone> Update this zone signer "
104  "configurations.\n"
105  "update [--all] Update zone list and all signer "
106  "configurations.\n"
107  "start Start the engine.\n"
108  "running Check if the engine is running.\n"
109  "reload Reload the engine.\n"
110  "stop Stop the engine.\n"
111  "verbosity <nr> Set verbosity.\n"
112  );
113  ods_writen(sockfd, buf, strlen(buf));
114  return;
115 }
116 
117 
122 static void
123 cmdhandler_handle_cmd_zones(int sockfd, cmdhandler_type* cmdc)
124 {
125  engine_type* engine = NULL;
126  char buf[ODS_SE_MAXLINE];
127  size_t i;
128  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
129  zone_type* zone = NULL;
130  ods_log_assert(cmdc);
131  ods_log_assert(cmdc->engine);
132  engine = (engine_type*) cmdc->engine;
133  if (!engine->zonelist || !engine->zonelist->zones) {
134  (void)snprintf(buf, ODS_SE_MAXLINE, "I have no zones configured\n");
135  ods_writen(sockfd, buf, strlen(buf));
136  return;
137  }
138  /* how many zones */
139  lock_basic_lock(&engine->zonelist->zl_lock);
140  (void)snprintf(buf, ODS_SE_MAXLINE, "I have %i zones configured\n",
141  (int) engine->zonelist->zones->count);
142  ods_writen(sockfd, buf, strlen(buf));
143  /* list zones */
144  node = ldns_rbtree_first(engine->zonelist->zones);
145  while (node && node != LDNS_RBTREE_NULL) {
146  zone = (zone_type*) node->data;
147  for (i=0; i < ODS_SE_MAXLINE; i++) {
148  buf[i] = 0;
149  }
150  (void)snprintf(buf, ODS_SE_MAXLINE, "- %s\n", zone->name);
151  ods_writen(sockfd, buf, strlen(buf));
152  node = ldns_rbtree_next(node);
153  }
155  return;
156 }
157 
158 
163 static void
164 cmdhandler_handle_cmd_update(int sockfd, cmdhandler_type* cmdc,
165  const char* tbd)
166 {
167  engine_type* engine = NULL;
168  char buf[ODS_SE_MAXLINE];
169  ods_status status = ODS_STATUS_OK;
170  zone_type* zone = NULL;
171  ods_status zl_changed = ODS_STATUS_OK;
172  ods_log_assert(tbd);
173  ods_log_assert(cmdc);
174  ods_log_assert(cmdc->engine);
175  engine = (engine_type*) cmdc->engine;
176  ods_log_assert(engine->taskq);
177  if (ods_strcmp(tbd, "--all") == 0) {
178  lock_basic_lock(&engine->zonelist->zl_lock);
179  zl_changed = zonelist_update(engine->zonelist,
180  engine->config->zonelist_filename);
181  if (zl_changed == ODS_STATUS_UNCHANGED) {
182  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has not changed."
183  " Signer configurations updated.\n");
184  ods_writen(sockfd, buf, strlen(buf));
185  } else if (zl_changed == ODS_STATUS_OK) {
186  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list updated: %i "
187  "removed, %i added, %i updated.\n",
188  engine->zonelist->just_removed,
189  engine->zonelist->just_added,
190  engine->zonelist->just_updated);
191  ods_writen(sockfd, buf, strlen(buf));
192  } else {
194  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has errors.\n");
195  ods_writen(sockfd, buf, strlen(buf));
196  }
197  if (zl_changed == ODS_STATUS_OK ||
198  zl_changed == ODS_STATUS_UNCHANGED) {
199  engine->zonelist->just_removed = 0;
200  engine->zonelist->just_added = 0;
201  engine->zonelist->just_updated = 0;
208  }
209  return;
210  } else {
211  /* look up zone */
212  lock_basic_lock(&engine->zonelist->zl_lock);
213  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
214  LDNS_RR_CLASS_IN);
215  /* If this zone is just added, don't update (it might not have a
216  * task yet) */
217  if (zone && zone->zl_status == ZONE_ZL_ADDED) {
218  zone = NULL;
219  }
221 
222  if (!zone) {
223  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Zone %s not found.\n",
224  tbd);
225  ods_writen(sockfd, buf, strlen(buf));
226  /* update all */
227  cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
228  return;
229  }
230 
231  lock_basic_lock(&zone->zone_lock);
232  status = zone_reschedule_task(zone, engine->taskq, TASK_SIGNCONF);
234 
235  if (status != ODS_STATUS_OK) {
236  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
237  "task for zone %s.\n", tbd);
238  ods_writen(sockfd, buf, strlen(buf));
239  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
240  cmdh_str, zone->name, ods_status2str(status));
241  } else {
242  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s config being updated.\n",
243  tbd);
244  ods_writen(sockfd, buf, strlen(buf));
245  ods_log_verbose("[%s] zone %s scheduled for immediate update signconf",
246  cmdh_str, tbd);
247  engine_wakeup_workers(engine);
248  }
249  }
250  return;
251 }
252 
253 
254 static uint32_t
255 max(uint32_t a, uint32_t b)
256 {
257  return (a<b?b:a);
258 }
259 
260 
265 static void
266 cmdhandler_handle_cmd_sign(int sockfd, cmdhandler_type* cmdc, const char* tbd)
267 {
268  engine_type* engine = NULL;
269  zone_type* zone = NULL;
270  ods_status status = ODS_STATUS_OK;
271  char buf[ODS_SE_MAXLINE];
272 
273  ods_log_assert(tbd);
274  ods_log_assert(cmdc);
275  ods_log_assert(cmdc->engine);
276  engine = (engine_type*) cmdc->engine;
277  ods_log_assert(engine->taskq);
278  if (ods_strcmp(tbd, "--all") == 0) {
280  schedule_flush(engine->taskq, TASK_READ);
282  engine_wakeup_workers(engine);
283  (void)snprintf(buf, ODS_SE_MAXLINE, "All zones scheduled for "
284  "immediate re-sign.\n");
285  ods_writen(sockfd, buf, strlen(buf));
286  ods_log_verbose("[%s] all zones scheduled for immediate re-sign",
287  cmdh_str);
288  return;
289  } else {
290  char* delim1 = strchr(tbd, ' ');
291  char* delim2 = NULL;
292  int force_serial = 0;
293  uint32_t serial = 0;
294  if (delim1) {
295  char* end = NULL;
297  if (strncmp(delim1+1, "--serial ", 9) != 0) {
298  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting <zone> "
299  "--serial <nr>, got %s.\n", tbd);
300  ods_writen(sockfd, buf, strlen(buf));
301  return;
302  }
303  delim2 = strchr(delim1+1, ' ');
304  if (!delim2) {
305  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting serial.\n");
306  ods_writen(sockfd, buf, strlen(buf));
307  return;
308  }
309  serial = (uint32_t) strtol(delim2+1, &end, 10);
310  if (*end != '\0') {
311  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting serial, "
312  "got %s.\n", delim2+1);
313  ods_writen(sockfd, buf, strlen(buf));
314  return;
315  }
316  force_serial = 1;
317  *delim1 = '\0';
318  }
319  lock_basic_lock(&engine->zonelist->zl_lock);
320  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
321  LDNS_RR_CLASS_IN);
322  /* If this zone is just added, don't update (it might not have a task
323  * yet).
324  */
325  if (zone && zone->zl_status == ZONE_ZL_ADDED) {
326  zone = NULL;
327  }
329 
330  if (!zone) {
331  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Zone %s not found.\n",
332  tbd);
333  ods_writen(sockfd, buf, strlen(buf));
334  return;
335  }
336 
337  lock_basic_lock(&zone->zone_lock);
338  if (force_serial) {
339  ods_log_assert(zone->db);
340  if (!util_serial_gt(serial, max(zone->db->outserial,
341  zone->db->inbserial))) {
343  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to enforce "
344  "serial %u for zone %s.\n", serial, tbd);
345  ods_writen(sockfd, buf, strlen(buf));
346  return;
347  }
348  zone->db->altserial = serial;
349  zone->db->force_serial = 1;
350  }
351  status = zone_reschedule_task(zone, engine->taskq, TASK_READ);
353 
354  if (status != ODS_STATUS_OK) {
355  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
356  "task for zone %s.\n", tbd);
357  ods_writen(sockfd, buf, strlen(buf));
358  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
359  cmdh_str, zone->name, ods_status2str(status));
360  } else {
361  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s scheduled for "
362  "immediate re-sign.\n", tbd);
363  ods_writen(sockfd, buf, strlen(buf));
364  ods_log_verbose("[%s] zone %s scheduled for immediate re-sign",
365  cmdh_str, tbd);
366  engine_wakeup_workers(engine);
367  }
368  }
369  return;
370 }
371 
372 
377 static void
378 unlink_backup_file(const char* filename, const char* extension)
379 {
380  char* tmpname = ods_build_path(filename, extension, 0, 1);
381  if (tmpname) {
382  ods_log_debug("[%s] unlink file %s", cmdh_str, tmpname);
383  unlink(tmpname);
384  free((void*)tmpname);
385  }
386  return;
387 }
388 
393 static void
394 cmdhandler_handle_cmd_clear(int sockfd, cmdhandler_type* cmdc, const char* tbd)
395 {
396  ods_status status = ODS_STATUS_OK;
397  engine_type* engine = NULL;
398  char buf[ODS_SE_MAXLINE];
399  zone_type* zone = NULL;
400  task_type* task = NULL;
401  uint32_t inbserial = 0;
402  uint32_t intserial = 0;
403  uint32_t outserial = 0;
404  ods_log_assert(tbd);
405  ods_log_assert(cmdc);
406  ods_log_assert(cmdc->engine);
407  engine = (engine_type*) cmdc->engine;
408  unlink_backup_file(tbd, ".inbound");
409  unlink_backup_file(tbd, ".backup");
410  unlink_backup_file(tbd, ".axfr");
411  unlink_backup_file(tbd, ".ixfr");
412  lock_basic_lock(&engine->zonelist->zl_lock);
413  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
414  LDNS_RR_CLASS_IN);
416  if (zone) {
417  lock_basic_lock(&zone->zone_lock);
418  inbserial = zone->db->inbserial;
419  intserial = zone->db->intserial;
420  outserial = zone->db->outserial;
421  namedb_cleanup(zone->db);
422  ixfr_cleanup(zone->ixfr);
423  signconf_cleanup(zone->signconf);
424 
425  zone->db = namedb_create((void*)zone);
426  zone->ixfr = ixfr_create((void*)zone);
427  zone->signconf = signconf_create();
428 
429  if (!zone->signconf || !zone->ixfr || !zone->db) {
430  ods_fatal_exit("[%s] unable to clear zone %s: failed to recreate"
431  "signconf, ixfr of db structure (out of memory?)", cmdh_str, tbd);
432  return;
433  }
434  /* restore serial management */
435  zone->db->inbserial = inbserial;
436  zone->db->intserial = intserial;
437  zone->db->outserial = outserial;
438  zone->db->have_serial = 1;
439 
440  status = zone_reschedule_task(zone, engine->taskq, TASK_SIGNCONF);
442 
443  if (status != ODS_STATUS_OK) {
444  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
445  "task for zone %s.\n", tbd);
446  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
447  cmdh_str, zone->name, ods_status2str(status));
448  } else {
449  (void)snprintf(buf, ODS_SE_MAXLINE, "Internal zone information about "
450  "%s cleared", tbd?tbd:"(null)");
451  ods_log_info("[%s] internal zone information about %s cleared",
452  cmdh_str, tbd?tbd:"(null)");
453  }
454  } else {
455  (void)snprintf(buf, ODS_SE_MAXLINE, "Cannot clear zone %s, zone not "
456  "found", tbd?tbd:"(null)");
457  ods_log_warning("[%s] cannot clear zone %s, zone not found",
458  cmdh_str, tbd?tbd:"(null)");
459  }
460  ods_writen(sockfd, buf, strlen(buf));
461  return;
462 }
463 
464 
469 static void
470 cmdhandler_handle_cmd_queue(int sockfd, cmdhandler_type* cmdc)
471 {
472  engine_type* engine = NULL;
473  char* strtime = NULL;
474  char buf[ODS_SE_MAXLINE];
475  size_t i = 0;
476  time_t now = 0;
477  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
478  task_type* task = NULL;
479  ods_log_assert(cmdc);
480  ods_log_assert(cmdc->engine);
481  engine = (engine_type*) cmdc->engine;
482  if (!engine->taskq || !engine->taskq->tasks) {
483  (void)snprintf(buf, ODS_SE_MAXLINE, "I have no tasks scheduled.\n");
484  ods_writen(sockfd, buf, strlen(buf));
485  return;
486  }
487  /* current time */
488  now = time_now();
489  strtime = ctime(&now);
490  (void)snprintf(buf, ODS_SE_MAXLINE, "It is now %s",
491  strtime?strtime:"(null)");
492  ods_writen(sockfd, buf, strlen(buf));
493  /* current work */
495  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
496  task = engine->workers[i]->task;
497  if (task) {
498  (void)snprintf(buf, ODS_SE_MAXLINE, "Working with task %s on "
499  "zone %s\n",
500  task_what2str(engine->workers[i]->working_with),
501  task_who2str(task));
502  ods_writen(sockfd, buf, strlen(buf));
503  }
504  }
505  /* how many tasks */
506  (void)snprintf(buf, ODS_SE_MAXLINE, "\nI have %i tasks scheduled.\n",
507  (int) engine->taskq->tasks->count);
508  ods_writen(sockfd, buf, strlen(buf));
509  /* list tasks */
510  node = ldns_rbtree_first(engine->taskq->tasks);
511  while (node && node != LDNS_RBTREE_NULL) {
512  task = (task_type*) node->data;
513  for (i=0; i < ODS_SE_MAXLINE; i++) {
514  buf[i] = 0;
515  }
516  (void)task2str(task, (char*) &buf[0]);
517  ods_writen(sockfd, buf, strlen(buf));
518  node = ldns_rbtree_next(node);
519  }
521  return;
522 }
523 
524 
529 static void
530 cmdhandler_handle_cmd_flush(int sockfd, cmdhandler_type* cmdc)
531 {
532  engine_type* engine = NULL;
533  char buf[ODS_SE_MAXLINE];
534  ods_log_assert(cmdc);
535  ods_log_assert(cmdc->engine);
536  engine = (engine_type*) cmdc->engine;
537  ods_log_assert(engine->taskq);
539  schedule_flush(engine->taskq, TASK_NONE);
541  engine_wakeup_workers(engine);
542  (void)snprintf(buf, ODS_SE_MAXLINE, "All tasks scheduled immediately.\n");
543  ods_writen(sockfd, buf, strlen(buf));
544  ods_log_verbose("[%s] all tasks scheduled immediately", cmdh_str);
545  return;
546 }
547 
548 
553 static void
554 cmdhandler_handle_cmd_reload(int sockfd, cmdhandler_type* cmdc)
555 {
556  engine_type* engine = NULL;
557  char buf[ODS_SE_MAXLINE];
558  ods_log_assert(cmdc);
559  ods_log_assert(cmdc->engine);
560  engine = (engine_type*) cmdc->engine;
561  engine->need_to_reload = 1;
562  lock_basic_lock(&engine->signal_lock);
563  lock_basic_alarm(&engine->signal_cond);
564  lock_basic_unlock(&engine->signal_lock);
565  (void)snprintf(buf, ODS_SE_MAXLINE, "Reloading engine.\n");
566  ods_writen(sockfd, buf, strlen(buf));
567  return;
568 }
569 
570 
575 static void
576 cmdhandler_handle_cmd_stop(int sockfd, cmdhandler_type* cmdc)
577 {
578  engine_type* engine = NULL;
579  char buf[ODS_SE_MAXLINE];
580  ods_log_assert(cmdc);
581  ods_log_assert(cmdc->engine);
582  engine = (engine_type*) cmdc->engine;
583  engine->need_to_exit = 1;
584  lock_basic_lock(&engine->signal_lock);
585  lock_basic_alarm(&engine->signal_cond);
586  lock_basic_unlock(&engine->signal_lock);
587  (void)snprintf(buf, ODS_SE_MAXLINE, ODS_SE_STOP_RESPONSE);
588  ods_writen(sockfd, buf, strlen(buf));
589  return;
590 }
591 
592 
597 static void
598 cmdhandler_handle_cmd_start(int sockfd)
599 {
600  char buf[ODS_SE_MAXLINE];
601  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine already running.\n");
602  ods_writen(sockfd, buf, strlen(buf));
603  return;
604 }
605 
606 
611 static void
612 cmdhandler_handle_cmd_running(int sockfd)
613 {
614  char buf[ODS_SE_MAXLINE];
615  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine running.\n");
616  ods_writen(sockfd, buf, strlen(buf));
617  return;
618 }
619 
620 
625 static void
626 cmdhandler_handle_cmd_verbosity(int sockfd, cmdhandler_type* cmdc, int val)
627 {
628  engine_type* engine = NULL;
629  char buf[ODS_SE_MAXLINE];
630  ods_log_assert(cmdc);
631  ods_log_assert(cmdc->engine);
632  engine = (engine_type*) cmdc->engine;
633  ods_log_assert(engine->config);
634  ods_log_init(engine->config->log_filename, engine->config->use_syslog,
635  val);
636  (void)snprintf(buf, ODS_SE_MAXLINE, "Verbosity level set to %i.\n", val);
637  ods_writen(sockfd, buf, strlen(buf));
638  return;
639 }
640 
641 
646 static void
647 cmdhandler_handle_cmd_error(int sockfd, const char* str)
648 {
649  char buf[ODS_SE_MAXLINE];
650  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: %s.\n", str?str:"(null)");
651  ods_writen(sockfd, buf, strlen(buf));
652  return;
653 }
654 
655 
660 static void
661 cmdhandler_handle_cmd_unknown(int sockfd, const char* str)
662 {
663  char buf[ODS_SE_MAXLINE];
664  (void)snprintf(buf, ODS_SE_MAXLINE, "Unknown command %s.\n",
665  str?str:"(null)");
666  ods_writen(sockfd, buf, strlen(buf));
667  return;
668 }
669 
670 
689 static void
690 cmdhandler_handle_cmd(cmdhandler_type* cmdc)
691 {
692  ssize_t n = 0;
693  int sockfd = 0;
694  char buf[ODS_SE_MAXLINE];
695 
696  ods_log_assert(cmdc);
697  sockfd = cmdc->client_fd;
698 
699 again:
700  while ((n = read(sockfd, buf, ODS_SE_MAXLINE)) > 0) {
701  /* what if this number is smaller than the number of bytes requested? */
702  buf[n-1] = '\0';
703  n--;
704  ods_log_verbose("[%s] received command %s[%i]", cmdh_str, buf, n);
705  ods_str_trim(buf);
706  n = strlen(buf);
707 
708  if (n == 4 && strncmp(buf, "help", n) == 0) {
709  ods_log_debug("[%s] help command", cmdh_str);
710  cmdhandler_handle_cmd_help(sockfd);
711  } else if (n == 5 && strncmp(buf, "zones", n) == 0) {
712  ods_log_debug("[%s] list zones command", cmdh_str);
713  cmdhandler_handle_cmd_zones(sockfd, cmdc);
714  } else if (n >= 4 && strncmp(buf, "sign", 4) == 0) {
715  ods_log_debug("[%s] sign zone command", cmdh_str);
716  if (buf[4] == '\0') {
717  /* NOTE: wouldn't it be nice that we default to --all? */
718  cmdhandler_handle_cmd_error(sockfd, "sign command needs "
719  "an argument (either '--all' or a zone name)");
720  } else if (buf[4] != ' ') {
721  cmdhandler_handle_cmd_unknown(sockfd, buf);
722  } else {
723  cmdhandler_handle_cmd_sign(sockfd, cmdc, &buf[5]);
724  }
725  } else if (n >= 5 && strncmp(buf, "clear", 5) == 0) {
726  ods_log_debug("[%s] clear zone command", cmdh_str);
727  if (buf[5] == '\0') {
728  cmdhandler_handle_cmd_error(sockfd, "clear command needs "
729  "a zone name");
730  } else if (buf[5] != ' ') {
731  cmdhandler_handle_cmd_unknown(sockfd, buf);
732  } else {
733  cmdhandler_handle_cmd_clear(sockfd, cmdc, &buf[6]);
734  }
735  } else if (n == 5 && strncmp(buf, "queue", n) == 0) {
736  ods_log_debug("[%s] list tasks command", cmdh_str);
737  cmdhandler_handle_cmd_queue(sockfd, cmdc);
738  } else if (n == 5 && strncmp(buf, "flush", n) == 0) {
739  ods_log_debug("[%s] flush tasks command", cmdh_str);
740  cmdhandler_handle_cmd_flush(sockfd, cmdc);
741  } else if (n >= 6 && strncmp(buf, "update", 6) == 0) {
742  ods_log_debug("[%s] update command", cmdh_str);
743  if (buf[6] == '\0') {
744  cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
745  } else if (buf[6] != ' ') {
746  cmdhandler_handle_cmd_unknown(sockfd, buf);
747  } else {
748  cmdhandler_handle_cmd_update(sockfd, cmdc, &buf[7]);
749  }
750  } else if (n == 4 && strncmp(buf, "stop", n) == 0) {
751  ods_log_debug("[%s] shutdown command", cmdh_str);
752  cmdhandler_handle_cmd_stop(sockfd, cmdc);
753  return;
754  } else if (n == 5 && strncmp(buf, "start", n) == 0) {
755  ods_log_debug("[%s] start command", cmdh_str);
756  cmdhandler_handle_cmd_start(sockfd);
757  } else if (n == 6 && strncmp(buf, "reload", n) == 0) {
758  ods_log_debug("[%s] reload command", cmdh_str);
759  cmdhandler_handle_cmd_reload(sockfd, cmdc);
760  } else if (n == 7 && strncmp(buf, "running", n) == 0) {
761  ods_log_debug("[%s] running command", cmdh_str);
762  cmdhandler_handle_cmd_running(sockfd);
763  } else if (n >= 9 && strncmp(buf, "verbosity", 9) == 0) {
764  ods_log_debug("[%s] verbosity command", cmdh_str);
765  if (buf[9] == '\0') {
766  cmdhandler_handle_cmd_error(sockfd, "verbosity command "
767  "an argument (verbosity level)");
768  } else if (buf[9] != ' ') {
769  cmdhandler_handle_cmd_unknown(sockfd, buf);
770  } else {
771  cmdhandler_handle_cmd_verbosity(sockfd, cmdc, atoi(&buf[10]));
772  }
773  } else if (n > 0) {
774  ods_log_debug("[%s] unknown command", cmdh_str);
775  cmdhandler_handle_cmd_unknown(sockfd, buf);
776  }
777  ods_log_debug("[%s] done handling command %s[%i]", cmdh_str, buf, n);
778  (void)snprintf(buf, SE_CMDH_CMDLEN, "\ncmd> ");
779  ods_writen(sockfd, buf, strlen(buf));
780  }
781 
782  if (n < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) ) {
783  goto again;
784  } else if (n < 0 && errno == ECONNRESET) {
785  ods_log_debug("[%s] done handling client: %s", cmdh_str,
786  strerror(errno));
787  } else if (n < 0 ) {
788  ods_log_error("[%s] read error: %s", cmdh_str, strerror(errno));
789  }
790  return;
791 }
792 
793 
798 static void*
799 cmdhandler_accept_client(void* arg)
800 {
801  cmdhandler_type* cmdc = (cmdhandler_type*) arg;
802 
805 
806  ods_log_debug("[%s] accept client %i", cmdh_str, cmdc->client_fd);
807  cmdhandler_handle_cmd(cmdc);
808  if (cmdc->client_fd) {
809  shutdown(cmdc->client_fd, SHUT_RDWR);
810  close(cmdc->client_fd);
811  }
812  free(cmdc);
813  count--;
814  return NULL;
815 }
816 
817 
823 cmdhandler_create(allocator_type* allocator, const char* filename)
824 {
825  cmdhandler_type* cmdh = NULL;
826  struct sockaddr_un servaddr;
827  int listenfd = 0;
828  int flags = 0;
829  int ret = 0;
830 
831  if (!allocator || !filename) {
832  return NULL;
833  }
834  /* new socket */
835  ods_log_debug("[%s] create socket %s", cmdh_str, filename);
836  listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
837  if (listenfd < 0) {
838  ods_log_error("[%s] unable to create cmdhandler: "
839  "socket() failed (%s)", cmdh_str, strerror(errno));
840  return NULL;
841  }
842  /* set it to non-blocking */
843  flags = fcntl(listenfd, F_GETFL, 0);
844  if (flags < 0) {
845  ods_log_error("[%s] unable to create cmdhandler: "
846  "fcntl(F_GETFL) failed (%s)", cmdh_str, strerror(errno));
847  close(listenfd);
848  return NULL;
849  }
850  flags |= O_NONBLOCK;
851  if (fcntl(listenfd, F_SETFL, flags) < 0) {
852  ods_log_error("[%s] unable to create cmdhandler: "
853  "fcntl(F_SETFL) failed (%s)", cmdh_str, strerror(errno));
854  close(listenfd);
855  return NULL;
856  }
857  /* no surprises so far */
858  if (filename) {
859  (void)unlink(filename);
860  }
861  bzero(&servaddr, sizeof(servaddr));
862  servaddr.sun_family = AF_UNIX;
863  strncpy(servaddr.sun_path, filename, sizeof(servaddr.sun_path) - 1);
864 #ifdef HAVE_SOCKADDR_SUN_LEN
865  servaddr.sun_len = strlen(servaddr.sun_path);
866 #endif
867  /* bind and listen... */
868  ret = bind(listenfd, (const struct sockaddr*) &servaddr,
869  SUN_LEN(&servaddr));
870  if (ret != 0) {
871  ods_log_error("[%s] unable to create cmdhandler: "
872  "bind() failed (%s)", cmdh_str, strerror(errno));
873  close(listenfd);
874  return NULL;
875  }
876  ret = listen(listenfd, ODS_SE_MAX_HANDLERS);
877  if (ret != 0) {
878  ods_log_error("[%s] unable to create cmdhandler: "
879  "listen() failed (%s)", cmdh_str, strerror(errno));
880  close(listenfd);
881  return NULL;
882  }
883  /* all ok */
884  cmdh = (cmdhandler_type*) allocator_alloc(allocator,
885  sizeof(cmdhandler_type));
886  if (!cmdh) {
887  ods_log_error("[%s] unable to create cmdhandler: "
888  "allocator_alloc() failed", cmdh_str);
889  close(listenfd);
890  return NULL;
891  }
892  cmdh->allocator = allocator;
893  cmdh->listen_fd = listenfd;
894  cmdh->listen_addr = servaddr;
895  cmdh->need_to_exit = 0;
896  return cmdh;
897 }
898 
899 
904 void
906 {
907  struct sockaddr_un cliaddr;
908  socklen_t clilen;
909  cmdhandler_type* cmdc = NULL;
910  engine_type* engine = NULL;
911  fd_set rset;
912  int connfd = 0;
913  int ret = 0;
914  ods_log_assert(cmdhandler);
915  ods_log_assert(cmdhandler->engine);
916  ods_log_debug("[%s] start", cmdh_str);
917  engine = (engine_type*) cmdhandler->engine;
918  ods_thread_detach(cmdhandler->thread_id);
919  FD_ZERO(&rset);
920  while (cmdhandler->need_to_exit == 0) {
921  clilen = sizeof(cliaddr);
922  FD_SET(cmdhandler->listen_fd, &rset);
923  ret = select(cmdhandler->listen_fd+1, &rset, NULL, NULL, NULL);
924  if (ret < 0) {
925  if (errno != EINTR && errno != EWOULDBLOCK) {
926  ods_log_warning("[%s] select() error: %s", cmdh_str,
927  strerror(errno));
928  }
929  continue;
930  }
931  if (FD_ISSET(cmdhandler->listen_fd, &rset)) {
932  connfd = accept(cmdhandler->listen_fd,
933  (struct sockaddr *) &cliaddr, &clilen);
934  if (connfd < 0) {
935  if (errno != EINTR && errno != EWOULDBLOCK) {
936  ods_log_warning("[%s] accept() error: %s", cmdh_str,
937  strerror(errno));
938  }
939  continue;
940  }
941  /* client accepted, create new thread */
942  cmdc = (cmdhandler_type*) malloc(sizeof(cmdhandler_type));
943  if (!cmdc) {
944  ods_log_crit("[%s] unable to create thread for client: "
945  "malloc() failed", cmdh_str);
946  cmdhandler->need_to_exit = 1;
947  break;
948  }
949  cmdc->listen_fd = cmdhandler->listen_fd;
950  cmdc->client_fd = connfd;
951  cmdc->listen_addr = cmdhandler->listen_addr;
952  cmdc->engine = cmdhandler->engine;
953  cmdc->need_to_exit = cmdhandler->need_to_exit;
954  ods_thread_create(&cmdc->thread_id, &cmdhandler_accept_client,
955  (void*) cmdc);
956  count++;
957  ods_log_debug("[%s] %i clients in progress...", cmdh_str, count);
958  }
959  }
960  ods_log_debug("[%s] shutdown", cmdh_str);
961  engine = cmdhandler->engine;
962  engine->cmdhandler_done = 1;
963  return;
964 }
965 
966 
971 void
973 {
974  allocator_type* allocator = NULL;
975  if (!cmdhandler) {
976  return;
977  }
978  allocator = cmdhandler->allocator;
979  allocator_deallocate(allocator, (void*) cmdhandler);
980  return;
981 }
982 
signconf_type * signconf_create(void)
Definition: signconf.c:49
void ixfr_cleanup(ixfr_type *ixfr)
Definition: ixfr.c:311
Definition: task.h:43
uint32_t intserial
Definition: namedb.h:54
zonelist_type * zonelist
Definition: engine.h:62
void ods_thread_blocksigs(void)
Definition: locks.c:150
void engine_wakeup_workers(engine_type *engine)
Definition: engine.c:456
void ods_log_debug(const char *format,...)
Definition: log.c:272
int just_updated
Definition: zonelist.h:55
cond_basic_type signal_cond
Definition: engine.h:80
#define SUN_LEN(su)
Definition: cmdhandler.c:63
void * allocator_alloc(allocator_type *allocator, size_t size)
Definition: allocator.c:68
const char * zonelist_filename
Definition: cfg.h:54
void engine_update_zones(engine_type *engine, ods_status zl_changed)
Definition: engine.c:791
void signconf_cleanup(signconf_type *sc)
Definition: signconf.c:566
void namedb_cleanup(namedb_type *db)
Definition: namedb.c:1140
cmdhandler_type * cmdhandler_create(allocator_type *allocator, const char *filename)
Definition: cmdhandler.c:823
void ods_fatal_exit(const char *format,...)
Definition: log.c:384
unsigned have_serial
Definition: namedb.h:61
void ods_log_info(const char *format,...)
Definition: log.c:304
const char * task_who2str(task_type *task)
Definition: task.c:178
ldns_rbtree_t * zones
Definition: zonelist.h:52
enum ods_enum_status ods_status
Definition: status.h:91
lock_basic_type zone_lock
Definition: zone.h:97
void schedule_flush(schedule_type *schedule, task_id override)
Definition: schedule.c:83
ods_thread_type thread_id
Definition: cmdhandler.h:50
void ods_log_error(const char *format,...)
Definition: log.c:336
uint32_t outserial
Definition: namedb.h:55
const char * ods_status2str(ods_status status)
Definition: status.c:112
zone_zl_status zl_status
Definition: zone.h:81
int ods_strcmp(const char *s1, const char *s2)
Definition: file.c:317
int just_removed
Definition: zonelist.h:56
void cmdhandler_start(cmdhandler_type *cmdhandler)
Definition: cmdhandler.c:905
struct sockaddr_un listen_addr
Definition: cmdhandler.h:49
int util_serial_gt(uint32_t serial_new, uint32_t serial_old)
Definition: util.c:74
#define ODS_SE_MAX_HANDLERS
Definition: cmdhandler.h:43
void ods_log_crit(const char *format,...)
Definition: log.c:352
const char * log_filename
Definition: cfg.h:55
lock_basic_type signal_lock
Definition: engine.h:81
task_type * task
Definition: worker.h:56
#define lock_basic_lock(lock)
Definition: locks.h:93
void ods_str_trim(char *str)
Definition: file.c:538
engineconfig_type * config
Definition: engine.h:59
namedb_type * db
Definition: zone.h:88
ixfr_type * ixfr
Definition: zone.h:89
uint32_t inbserial
Definition: namedb.h:53
int num_worker_threads
Definition: cfg.h:64
Definition: task.h:45
worker_type ** workers
Definition: engine.h:60
#define SE_CMDH_CMDLEN
Definition: cmdhandler.c:60
signconf_type * signconf
Definition: zone.h:86
ssize_t ods_writen(int fd, const void *vptr, size_t n)
Definition: file.c:262
allocator_type * allocator
Definition: cmdhandler.h:47
unsigned force_serial
Definition: namedb.h:60
ods_status zone_reschedule_task(zone_type *zone, schedule_type *taskq, task_id what)
Definition: zone.c:189
namedb_type * namedb_create(void *zone)
Definition: namedb.c:126
char * ods_build_path(const char *file, const char *suffix, int dir, int no_slash)
Definition: file.c:127
#define ods_thread_detach(thr)
Definition: locks.h:104
int use_syslog
Definition: cfg.h:63
void ods_log_verbose(const char *format,...)
Definition: log.c:288
ldns_rbtree_t * tasks
Definition: schedule.h:62
zone_type * zonelist_lookup_zone_by_name(zonelist_type *zonelist, const char *name, ldns_rr_class klass)
Definition: zonelist.c:163
const char * name
Definition: zone.h:78
schedule_type * taskq
Definition: engine.h:63
uint32_t altserial
Definition: namedb.h:56
void allocator_deallocate(allocator_type *allocator, void *data)
Definition: allocator.c:137
task_id working_with
Definition: worker.h:57
ods_status zonelist_update(zonelist_type *zl, const char *zlfile)
Definition: zonelist.c:352
char * task2str(task_type *task, char *buftask)
Definition: task.c:196
lock_basic_type schedule_lock
Definition: schedule.h:65
int need_to_exit
Definition: engine.h:76
#define ods_log_assert(x)
Definition: log.h:156
#define ods_thread_create(thr, func, arg)
Definition: locks.h:103
void ods_log_init(const char *filename, int use_syslog, int verbosity)
Definition: log.c:83
int need_to_reload
Definition: engine.h:77
ixfr_type * ixfr_create(void *zone)
Definition: ixfr.c:102
#define lock_basic_alarm(cond)
Definition: locks.h:98
#define lock_basic_unlock(lock)
Definition: locks.h:94
void ods_log_warning(const char *format,...)
Definition: log.c:320
void cmdhandler_cleanup(cmdhandler_type *cmdhandler)
Definition: cmdhandler.c:972
lock_basic_type zl_lock
Definition: zonelist.h:57
int cmdhandler_done
Definition: engine.h:69
const char * task_what2str(task_id what)
Definition: task.c:148
time_t time_now(void)
Definition: duration.c:515