OpenDNSSEC-signer  1.4.1
cmdhandler.c
Go to the documentation of this file.
1 /*
2  * $Id: cmdhandler.c 7160 2013-06-17 13:22:49Z 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  "clear <zone> Delete the internal storage of this "
89  "zone.\n"
90  " All signatures will be regenerated "
91  "on the next re-sign.\n"
92  "queue Show the current task queue.\n"
93  );
94  ods_writen(sockfd, buf, strlen(buf));
95 
96  (void) snprintf(buf, ODS_SE_MAXLINE,
97  "flush Execute all scheduled tasks "
98  "immediately.\n"
99  "update <zone> Update this zone signer "
100  "configurations.\n"
101  "update [--all] Update zone list and all signer "
102  "configurations.\n"
103  "start Start the engine.\n"
104  "running Check if the engine is running.\n"
105  "reload Reload the engine.\n"
106  "stop Stop the engine.\n"
107  "verbosity <nr> Set verbosity.\n"
108  );
109  ods_writen(sockfd, buf, strlen(buf));
110  return;
111 }
112 
113 
118 static void
119 cmdhandler_handle_cmd_zones(int sockfd, cmdhandler_type* cmdc)
120 {
121  engine_type* engine = NULL;
122  char buf[ODS_SE_MAXLINE];
123  size_t i;
124  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
125  zone_type* zone = NULL;
126  ods_log_assert(cmdc);
127  ods_log_assert(cmdc->engine);
128  engine = (engine_type*) cmdc->engine;
129  if (!engine->zonelist || !engine->zonelist->zones) {
130  (void)snprintf(buf, ODS_SE_MAXLINE, "I have no zones configured\n");
131  ods_writen(sockfd, buf, strlen(buf));
132  return;
133  }
134  /* how many zones */
135  lock_basic_lock(&engine->zonelist->zl_lock);
136  (void)snprintf(buf, ODS_SE_MAXLINE, "I have %i zones configured\n",
137  (int) engine->zonelist->zones->count);
138  ods_writen(sockfd, buf, strlen(buf));
139  /* list zones */
140  node = ldns_rbtree_first(engine->zonelist->zones);
141  while (node && node != LDNS_RBTREE_NULL) {
142  zone = (zone_type*) node->data;
143  for (i=0; i < ODS_SE_MAXLINE; i++) {
144  buf[i] = 0;
145  }
146  (void)snprintf(buf, ODS_SE_MAXLINE, "- %s\n", zone->name);
147  ods_writen(sockfd, buf, strlen(buf));
148  node = ldns_rbtree_next(node);
149  }
151  return;
152 }
153 
154 
159 static void
160 cmdhandler_handle_cmd_update(int sockfd, cmdhandler_type* cmdc,
161  const char* tbd)
162 {
163  engine_type* engine = NULL;
164  char buf[ODS_SE_MAXLINE];
165  ods_status status = ODS_STATUS_OK;
166  zone_type* zone = NULL;
167  ods_status zl_changed = ODS_STATUS_OK;
168  ods_log_assert(tbd);
169  ods_log_assert(cmdc);
170  ods_log_assert(cmdc->engine);
171  engine = (engine_type*) cmdc->engine;
172  ods_log_assert(engine->taskq);
173  if (ods_strcmp(tbd, "--all") == 0) {
174  lock_basic_lock(&engine->zonelist->zl_lock);
175  zl_changed = zonelist_update(engine->zonelist,
176  engine->config->zonelist_filename);
177  if (zl_changed == ODS_STATUS_UNCHANGED) {
178  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has not changed."
179  " Signer configurations updated.\n");
180  ods_writen(sockfd, buf, strlen(buf));
181  } else if (zl_changed == ODS_STATUS_OK) {
182  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list updated: %i "
183  "removed, %i added, %i updated.\n",
184  engine->zonelist->just_removed,
185  engine->zonelist->just_added,
186  engine->zonelist->just_updated);
187  ods_writen(sockfd, buf, strlen(buf));
188  } else {
190  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone list has errors.\n");
191  ods_writen(sockfd, buf, strlen(buf));
192  }
193  if (zl_changed == ODS_STATUS_OK ||
194  zl_changed == ODS_STATUS_UNCHANGED) {
195  engine->zonelist->just_removed = 0;
196  engine->zonelist->just_added = 0;
197  engine->zonelist->just_updated = 0;
204  }
205  return;
206  } else {
207  /* look up zone */
208  lock_basic_lock(&engine->zonelist->zl_lock);
209  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
210  LDNS_RR_CLASS_IN);
211  /* If this zone is just added, don't update (it might not have a
212  * task yet) */
213  if (zone && zone->zl_status == ZONE_ZL_ADDED) {
214  zone = NULL;
215  }
217 
218  if (!zone) {
219  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Zone %s not found.\n",
220  tbd);
221  ods_writen(sockfd, buf, strlen(buf));
222  /* update all */
223  cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
224  return;
225  }
226 
227  lock_basic_lock(&zone->zone_lock);
228  status = zone_reschedule_task(zone, engine->taskq, TASK_SIGNCONF);
230 
231  if (status != ODS_STATUS_OK) {
232  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
233  "task for zone %s.\n", tbd);
234  ods_writen(sockfd, buf, strlen(buf));
235  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
236  cmdh_str, zone->name, ods_status2str(status));
237  } else {
238  engine_wakeup_workers(engine);
239  }
240  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s config being updated.\n",
241  tbd);
242  ods_writen(sockfd, buf, strlen(buf));
243  }
244  return;
245 }
246 
247 
248 static uint32_t
249 max(uint32_t a, uint32_t b)
250 {
251  return (a<b?b:a);
252 }
253 
254 
259 static void
260 cmdhandler_handle_cmd_sign(int sockfd, cmdhandler_type* cmdc, const char* tbd)
261 {
262  engine_type* engine = NULL;
263  zone_type* zone = NULL;
264  ods_status status = ODS_STATUS_OK;
265  char buf[ODS_SE_MAXLINE];
266 
267  ods_log_assert(tbd);
268  ods_log_assert(cmdc);
269  ods_log_assert(cmdc->engine);
270  engine = (engine_type*) cmdc->engine;
271  ods_log_assert(engine->taskq);
272  if (ods_strcmp(tbd, "--all") == 0) {
274  schedule_flush(engine->taskq, TASK_READ);
276  engine_wakeup_workers(engine);
277  (void)snprintf(buf, ODS_SE_MAXLINE, "All zones scheduled for "
278  "immediate re-sign.\n");
279  ods_writen(sockfd, buf, strlen(buf));
280  ods_log_verbose("[%s] all zones scheduled for immediate re-sign",
281  cmdh_str);
282  return;
283  } else {
284  char* delim1 = strchr(tbd, ' ');
285  char* delim2 = NULL;
286  int force_serial = 0;
287  uint32_t serial = 0;
288  if (delim1) {
289  char* end = NULL;
291  if (strncmp(delim1+1, "--serial ", 9) != 0) {
292  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting <zone> "
293  "--serial <nr>, got %s.\n", tbd);
294  ods_writen(sockfd, buf, strlen(buf));
295  return;
296  }
297  delim2 = strchr(delim1+1, ' ');
298  if (!delim2) {
299  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting serial.\n");
300  ods_writen(sockfd, buf, strlen(buf));
301  return;
302  }
303  serial = (uint32_t) strtol(delim2+1, &end, 10);
304  if (*end != '\0') {
305  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Expecting serial, "
306  "got %s.\n", delim2+1);
307  ods_writen(sockfd, buf, strlen(buf));
308  return;
309  }
310  force_serial = 1;
311  *delim1 = '\0';
312  }
313  lock_basic_lock(&engine->zonelist->zl_lock);
314  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
315  LDNS_RR_CLASS_IN);
316  /* If this zone is just added, don't update (it might not have a task
317  * yet).
318  */
319  if (zone && zone->zl_status == ZONE_ZL_ADDED) {
320  zone = NULL;
321  }
323 
324  if (!zone) {
325  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Zone %s not found.\n",
326  tbd);
327  ods_writen(sockfd, buf, strlen(buf));
328  return;
329  }
330 
331  lock_basic_lock(&zone->zone_lock);
332  if (force_serial) {
333  ods_log_assert(zone->db);
334  if (!util_serial_gt(serial, max(zone->db->outserial,
335  zone->db->inbserial))) {
337  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to enforce "
338  "serial %u for zone %s.\n", serial, tbd);
339  ods_writen(sockfd, buf, strlen(buf));
340  return;
341  }
342  zone->db->altserial = serial;
343  zone->db->force_serial = 1;
344  }
345  status = zone_reschedule_task(zone, engine->taskq, TASK_READ);
347 
348  if (status != ODS_STATUS_OK) {
349  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: Unable to reschedule "
350  "task for zone %s.\n", tbd);
351  ods_writen(sockfd, buf, strlen(buf));
352  ods_log_crit("[%s] unable to reschedule task for zone %s: %s",
353  cmdh_str, zone->name, ods_status2str(status));
354  } else {
355  (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s scheduled for "
356  "immediate re-sign.\n", tbd);
357  ods_writen(sockfd, buf, strlen(buf));
358  ods_log_verbose("[%s] zone %s scheduled for immediate re-sign",
359  cmdh_str, tbd);
360  engine_wakeup_workers(engine);
361  }
362  }
363  return;
364 }
365 
366 
371 static void
372 unlink_backup_file(const char* filename, const char* extension)
373 {
374  char* tmpname = ods_build_path(filename, extension, 0, 1);
375  if (tmpname) {
376  ods_log_debug("[%s] unlink file %s", cmdh_str, tmpname);
377  unlink(tmpname);
378  free((void*)tmpname);
379  }
380  return;
381 }
382 
387 static void
388 cmdhandler_handle_cmd_clear(int sockfd, cmdhandler_type* cmdc, const char* tbd)
389 {
390  engine_type* engine = NULL;
391  char buf[ODS_SE_MAXLINE];
392  zone_type* zone = NULL;
393  task_type* task = NULL;
394  uint32_t inbserial = 0;
395  uint32_t intserial = 0;
396  uint32_t outserial = 0;
397  ods_log_assert(tbd);
398  ods_log_assert(cmdc);
399  ods_log_assert(cmdc->engine);
400  engine = (engine_type*) cmdc->engine;
401  unlink_backup_file(tbd, ".inbound");
402  unlink_backup_file(tbd, ".backup");
403  unlink_backup_file(tbd, ".axfr");
404  unlink_backup_file(tbd, ".ixfr");
405  lock_basic_lock(&engine->zonelist->zl_lock);
406  zone = zonelist_lookup_zone_by_name(engine->zonelist, tbd,
407  LDNS_RR_CLASS_IN);
409  if (zone) {
410  lock_basic_lock(&zone->zone_lock);
411  inbserial = zone->db->inbserial;
412  intserial = zone->db->intserial;
413  outserial = zone->db->outserial;
414  namedb_cleanup(zone->db);
415  ixfr_cleanup(zone->ixfr);
416  signconf_cleanup(zone->signconf);
417 
418  zone->db = namedb_create((void*)zone);
419  zone->ixfr = ixfr_create((void*)zone);
420  zone->signconf = signconf_create();
421 
422  if (!zone->signconf || !zone->ixfr || !zone->db) {
423  ods_fatal_exit("[%s] unable to clear zone %s: failed to recreate"
424  "signconf, ixfr of db structure (out of memory?)", cmdh_str, tbd);
425  return;
426  }
427  /* restore serial management */
428  zone->db->inbserial = inbserial;
429  zone->db->intserial = intserial;
430  zone->db->outserial = outserial;
431 
432  task = (task_type*) zone->task;
433  task->what = TASK_SIGNCONF;
435 
436  (void)snprintf(buf, ODS_SE_MAXLINE, "Internal zone information about "
437  "%s cleared", tbd?tbd:"(null)");
438  ods_log_info("[%s] internal zone information about %s cleared",
439  cmdh_str, tbd?tbd:"(null)");
440  } else {
441  (void)snprintf(buf, ODS_SE_MAXLINE, "Cannot clear zone %s, zone not "
442  "found", tbd?tbd:"(null)");
443  ods_log_warning("[%s] cannot clear zone %s, zone not found",
444  cmdh_str, tbd?tbd:"(null)");
445  }
446  ods_writen(sockfd, buf, strlen(buf));
447  return;
448 }
449 
450 
455 static void
456 cmdhandler_handle_cmd_queue(int sockfd, cmdhandler_type* cmdc)
457 {
458  engine_type* engine = NULL;
459  char* strtime = NULL;
460  char buf[ODS_SE_MAXLINE];
461  size_t i = 0;
462  time_t now = 0;
463  ldns_rbnode_t* node = LDNS_RBTREE_NULL;
464  task_type* task = NULL;
465  ods_log_assert(cmdc);
466  ods_log_assert(cmdc->engine);
467  engine = (engine_type*) cmdc->engine;
468  if (!engine->taskq || !engine->taskq->tasks) {
469  (void)snprintf(buf, ODS_SE_MAXLINE, "I have no tasks scheduled.\n");
470  ods_writen(sockfd, buf, strlen(buf));
471  return;
472  }
473  /* current time */
474  now = time_now();
475  strtime = ctime(&now);
476  (void)snprintf(buf, ODS_SE_MAXLINE, "It is now %s",
477  strtime?strtime:"(null)");
478  ods_writen(sockfd, buf, strlen(buf));
479  /* current work */
481  for (i=0; i < (size_t) engine->config->num_worker_threads; i++) {
482  task = engine->workers[i]->task;
483  if (task) {
484  (void)snprintf(buf, ODS_SE_MAXLINE, "Working with task %s on "
485  "zone %s\n",
486  task_what2str(engine->workers[i]->working_with),
487  task_who2str(task));
488  ods_writen(sockfd, buf, strlen(buf));
489  }
490  }
491  /* how many tasks */
492  (void)snprintf(buf, ODS_SE_MAXLINE, "\nI have %i tasks scheduled.\n",
493  (int) engine->taskq->tasks->count);
494  ods_writen(sockfd, buf, strlen(buf));
495  /* list tasks */
496  node = ldns_rbtree_first(engine->taskq->tasks);
497  while (node && node != LDNS_RBTREE_NULL) {
498  task = (task_type*) node->data;
499  for (i=0; i < ODS_SE_MAXLINE; i++) {
500  buf[i] = 0;
501  }
502  (void)task2str(task, (char*) &buf[0]);
503  ods_writen(sockfd, buf, strlen(buf));
504  node = ldns_rbtree_next(node);
505  }
507  return;
508 }
509 
510 
515 static void
516 cmdhandler_handle_cmd_flush(int sockfd, cmdhandler_type* cmdc)
517 {
518  engine_type* engine = NULL;
519  char buf[ODS_SE_MAXLINE];
520  ods_log_assert(cmdc);
521  ods_log_assert(cmdc->engine);
522  engine = (engine_type*) cmdc->engine;
523  ods_log_assert(engine->taskq);
525  schedule_flush(engine->taskq, TASK_NONE);
527  engine_wakeup_workers(engine);
528  (void)snprintf(buf, ODS_SE_MAXLINE, "All tasks scheduled immediately.\n");
529  ods_writen(sockfd, buf, strlen(buf));
530  ods_log_verbose("[%s] all tasks scheduled immediately", cmdh_str);
531  return;
532 }
533 
534 
539 static void
540 cmdhandler_handle_cmd_reload(int sockfd, cmdhandler_type* cmdc)
541 {
542  engine_type* engine = NULL;
543  char buf[ODS_SE_MAXLINE];
544  ods_log_assert(cmdc);
545  ods_log_assert(cmdc->engine);
546  engine = (engine_type*) cmdc->engine;
547  engine->need_to_reload = 1;
548  lock_basic_lock(&engine->signal_lock);
549  lock_basic_alarm(&engine->signal_cond);
550  lock_basic_unlock(&engine->signal_lock);
551  (void)snprintf(buf, ODS_SE_MAXLINE, "Reloading engine.\n");
552  ods_writen(sockfd, buf, strlen(buf));
553  return;
554 }
555 
556 
561 static void
562 cmdhandler_handle_cmd_stop(int sockfd, cmdhandler_type* cmdc)
563 {
564  engine_type* engine = NULL;
565  char buf[ODS_SE_MAXLINE];
566  ods_log_assert(cmdc);
567  ods_log_assert(cmdc->engine);
568  engine = (engine_type*) cmdc->engine;
569  engine->need_to_exit = 1;
570  lock_basic_lock(&engine->signal_lock);
571  lock_basic_alarm(&engine->signal_cond);
572  lock_basic_unlock(&engine->signal_lock);
573  (void)snprintf(buf, ODS_SE_MAXLINE, ODS_SE_STOP_RESPONSE);
574  ods_writen(sockfd, buf, strlen(buf));
575  return;
576 }
577 
578 
583 static void
584 cmdhandler_handle_cmd_start(int sockfd)
585 {
586  char buf[ODS_SE_MAXLINE];
587  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine already running.\n");
588  ods_writen(sockfd, buf, strlen(buf));
589  return;
590 }
591 
592 
597 static void
598 cmdhandler_handle_cmd_running(int sockfd)
599 {
600  char buf[ODS_SE_MAXLINE];
601  (void)snprintf(buf, ODS_SE_MAXLINE, "Engine running.\n");
602  ods_writen(sockfd, buf, strlen(buf));
603  return;
604 }
605 
606 
611 static void
612 cmdhandler_handle_cmd_verbosity(int sockfd, cmdhandler_type* cmdc, int val)
613 {
614  engine_type* engine = NULL;
615  char buf[ODS_SE_MAXLINE];
616  ods_log_assert(cmdc);
617  ods_log_assert(cmdc->engine);
618  engine = (engine_type*) cmdc->engine;
619  ods_log_assert(engine->config);
620  ods_log_init(engine->config->log_filename, engine->config->use_syslog,
621  val);
622  (void)snprintf(buf, ODS_SE_MAXLINE, "Verbosity level set to %i.\n", val);
623  ods_writen(sockfd, buf, strlen(buf));
624  return;
625 }
626 
627 
632 static void
633 cmdhandler_handle_cmd_error(int sockfd, const char* str)
634 {
635  char buf[ODS_SE_MAXLINE];
636  (void)snprintf(buf, ODS_SE_MAXLINE, "Error: %s.\n", str?str:"(null)");
637  ods_writen(sockfd, buf, strlen(buf));
638  return;
639 }
640 
641 
646 static void
647 cmdhandler_handle_cmd_unknown(int sockfd, const char* str)
648 {
649  char buf[ODS_SE_MAXLINE];
650  (void)snprintf(buf, ODS_SE_MAXLINE, "Unknown command %s.\n",
651  str?str:"(null)");
652  ods_writen(sockfd, buf, strlen(buf));
653  return;
654 }
655 
656 
675 static void
676 cmdhandler_handle_cmd(cmdhandler_type* cmdc)
677 {
678  ssize_t n = 0;
679  int sockfd = 0;
680  char buf[ODS_SE_MAXLINE];
681 
682  ods_log_assert(cmdc);
683  sockfd = cmdc->client_fd;
684 
685 again:
686  while ((n = read(sockfd, buf, ODS_SE_MAXLINE)) > 0) {
687  /* what if this number is smaller than the number of bytes requested? */
688  buf[n-1] = '\0';
689  n--;
690  ods_log_verbose("[%s] received command %s[%i]", cmdh_str, buf, n);
691  ods_str_trim(buf);
692  n = strlen(buf);
693 
694  if (n == 4 && strncmp(buf, "help", n) == 0) {
695  ods_log_debug("[%s] help command", cmdh_str);
696  cmdhandler_handle_cmd_help(sockfd);
697  } else if (n == 5 && strncmp(buf, "zones", n) == 0) {
698  ods_log_debug("[%s] list zones command", cmdh_str);
699  cmdhandler_handle_cmd_zones(sockfd, cmdc);
700  } else if (n >= 4 && strncmp(buf, "sign", 4) == 0) {
701  ods_log_debug("[%s] sign zone command", cmdh_str);
702  if (buf[4] == '\0') {
703  /* NOTE: wouldn't it be nice that we default to --all? */
704  cmdhandler_handle_cmd_error(sockfd, "sign command needs "
705  "an argument (either '--all' or a zone name)");
706  } else if (buf[4] != ' ') {
707  cmdhandler_handle_cmd_unknown(sockfd, buf);
708  } else {
709  cmdhandler_handle_cmd_sign(sockfd, cmdc, &buf[5]);
710  }
711  } else if (n >= 5 && strncmp(buf, "clear", 5) == 0) {
712  ods_log_debug("[%s] clear zone command", cmdh_str);
713  if (buf[5] == '\0') {
714  cmdhandler_handle_cmd_error(sockfd, "clear command needs "
715  "a zone name");
716  } else if (buf[5] != ' ') {
717  cmdhandler_handle_cmd_unknown(sockfd, buf);
718  } else {
719  cmdhandler_handle_cmd_clear(sockfd, cmdc, &buf[6]);
720  }
721  } else if (n == 5 && strncmp(buf, "queue", n) == 0) {
722  ods_log_debug("[%s] list tasks command", cmdh_str);
723  cmdhandler_handle_cmd_queue(sockfd, cmdc);
724  } else if (n == 5 && strncmp(buf, "flush", n) == 0) {
725  ods_log_debug("[%s] flush tasks command", cmdh_str);
726  cmdhandler_handle_cmd_flush(sockfd, cmdc);
727  } else if (n >= 6 && strncmp(buf, "update", 6) == 0) {
728  ods_log_debug("[%s] update command", cmdh_str);
729  if (buf[6] == '\0') {
730  cmdhandler_handle_cmd_update(sockfd, cmdc, "--all");
731  } else if (buf[6] != ' ') {
732  cmdhandler_handle_cmd_unknown(sockfd, buf);
733  } else {
734  cmdhandler_handle_cmd_update(sockfd, cmdc, &buf[7]);
735  }
736  } else if (n == 4 && strncmp(buf, "stop", n) == 0) {
737  ods_log_debug("[%s] shutdown command", cmdh_str);
738  cmdhandler_handle_cmd_stop(sockfd, cmdc);
739  return;
740  } else if (n == 5 && strncmp(buf, "start", n) == 0) {
741  ods_log_debug("[%s] start command", cmdh_str);
742  cmdhandler_handle_cmd_start(sockfd);
743  } else if (n == 6 && strncmp(buf, "reload", n) == 0) {
744  ods_log_debug("[%s] reload command", cmdh_str);
745  cmdhandler_handle_cmd_reload(sockfd, cmdc);
746  } else if (n == 7 && strncmp(buf, "running", n) == 0) {
747  ods_log_debug("[%s] running command", cmdh_str);
748  cmdhandler_handle_cmd_running(sockfd);
749  } else if (n >= 9 && strncmp(buf, "verbosity", 9) == 0) {
750  ods_log_debug("[%s] verbosity command", cmdh_str);
751  if (buf[9] == '\0') {
752  cmdhandler_handle_cmd_error(sockfd, "verbosity command "
753  "an argument (verbosity level)");
754  } else if (buf[9] != ' ') {
755  cmdhandler_handle_cmd_unknown(sockfd, buf);
756  } else {
757  cmdhandler_handle_cmd_verbosity(sockfd, cmdc, atoi(&buf[10]));
758  }
759  } else if (n > 0) {
760  ods_log_debug("[%s] unknown command", cmdh_str);
761  cmdhandler_handle_cmd_unknown(sockfd, buf);
762  }
763  ods_log_debug("[%s] done handling command %s[%i]", cmdh_str, buf, n);
764  (void)snprintf(buf, SE_CMDH_CMDLEN, "\ncmd> ");
765  ods_writen(sockfd, buf, strlen(buf));
766  }
767 
768  if (n < 0 && (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) ) {
769  goto again;
770  } else if (n < 0 && errno == ECONNRESET) {
771  ods_log_debug("[%s] done handling client: %s", cmdh_str,
772  strerror(errno));
773  } else if (n < 0 ) {
774  ods_log_error("[%s] read error: %s", cmdh_str, strerror(errno));
775  }
776  return;
777 }
778 
779 
784 static void*
785 cmdhandler_accept_client(void* arg)
786 {
787  cmdhandler_type* cmdc = (cmdhandler_type*) arg;
788 
791 
792  ods_log_debug("[%s] accept client %i", cmdh_str, cmdc->client_fd);
793  cmdhandler_handle_cmd(cmdc);
794  if (cmdc->client_fd) {
795  shutdown(cmdc->client_fd, SHUT_RDWR);
796  close(cmdc->client_fd);
797  }
798  free(cmdc);
799  count--;
800  return NULL;
801 }
802 
803 
809 cmdhandler_create(allocator_type* allocator, const char* filename)
810 {
811  cmdhandler_type* cmdh = NULL;
812  struct sockaddr_un servaddr;
813  int listenfd = 0;
814  int flags = 0;
815  int ret = 0;
816 
817  if (!allocator || !filename) {
818  return NULL;
819  }
820  /* new socket */
821  ods_log_debug("[%s] create socket %s", cmdh_str, filename);
822  listenfd = socket(AF_UNIX, SOCK_STREAM, 0);
823  if (listenfd < 0) {
824  ods_log_error("[%s] unable to create cmdhandler: "
825  "socket() failed (%s)", cmdh_str, strerror(errno));
826  return NULL;
827  }
828  /* set it to non-blocking */
829  flags = fcntl(listenfd, F_GETFL, 0);
830  if (flags < 0) {
831  ods_log_error("[%s] unable to create cmdhandler: "
832  "fcntl(F_GETFL) failed (%s)", cmdh_str, strerror(errno));
833  close(listenfd);
834  return NULL;
835  }
836  flags |= O_NONBLOCK;
837  if (fcntl(listenfd, F_SETFL, flags) < 0) {
838  ods_log_error("[%s] unable to create cmdhandler: "
839  "fcntl(F_SETFL) failed (%s)", cmdh_str, strerror(errno));
840  close(listenfd);
841  return NULL;
842  }
843  /* no surprises so far */
844  if (filename) {
845  (void)unlink(filename);
846  }
847  bzero(&servaddr, sizeof(servaddr));
848  servaddr.sun_family = AF_UNIX;
849  strncpy(servaddr.sun_path, filename, sizeof(servaddr.sun_path) - 1);
850 #ifdef HAVE_SOCKADDR_SUN_LEN
851  servaddr.sun_len = strlen(servaddr.sun_path);
852 #endif
853  /* bind and listen... */
854  ret = bind(listenfd, (const struct sockaddr*) &servaddr,
855  SUN_LEN(&servaddr));
856  if (ret != 0) {
857  ods_log_error("[%s] unable to create cmdhandler: "
858  "bind() failed (%s)", cmdh_str, strerror(errno));
859  close(listenfd);
860  return NULL;
861  }
862  ret = listen(listenfd, ODS_SE_MAX_HANDLERS);
863  if (ret != 0) {
864  ods_log_error("[%s] unable to create cmdhandler: "
865  "listen() failed (%s)", cmdh_str, strerror(errno));
866  close(listenfd);
867  return NULL;
868  }
869  /* all ok */
870  cmdh = (cmdhandler_type*) allocator_alloc(allocator,
871  sizeof(cmdhandler_type));
872  if (!cmdh) {
873  ods_log_error("[%s] unable to create cmdhandler: "
874  "allocator_alloc() failed", cmdh_str);
875  close(listenfd);
876  return NULL;
877  }
878  cmdh->allocator = allocator;
879  cmdh->listen_fd = listenfd;
880  cmdh->listen_addr = servaddr;
881  cmdh->need_to_exit = 0;
882  return cmdh;
883 }
884 
885 
890 void
892 {
893  struct sockaddr_un cliaddr;
894  socklen_t clilen;
895  cmdhandler_type* cmdc = NULL;
896  engine_type* engine = NULL;
897  fd_set rset;
898  int connfd = 0;
899  int ret = 0;
900  ods_log_assert(cmdhandler);
901  ods_log_assert(cmdhandler->engine);
902  ods_log_debug("[%s] start", cmdh_str);
903  engine = (engine_type*) cmdhandler->engine;
904  ods_thread_detach(cmdhandler->thread_id);
905  FD_ZERO(&rset);
906  while (cmdhandler->need_to_exit == 0) {
907  clilen = sizeof(cliaddr);
908  FD_SET(cmdhandler->listen_fd, &rset);
909  ret = select(cmdhandler->listen_fd+1, &rset, NULL, NULL, NULL);
910  if (ret < 0) {
911  if (errno != EINTR && errno != EWOULDBLOCK) {
912  ods_log_warning("[%s] select() error: %s", cmdh_str,
913  strerror(errno));
914  }
915  continue;
916  }
917  if (FD_ISSET(cmdhandler->listen_fd, &rset)) {
918  connfd = accept(cmdhandler->listen_fd,
919  (struct sockaddr *) &cliaddr, &clilen);
920  if (connfd < 0) {
921  if (errno != EINTR && errno != EWOULDBLOCK) {
922  ods_log_warning("[%s] accept() error: %s", cmdh_str,
923  strerror(errno));
924  }
925  continue;
926  }
927  /* client accepted, create new thread */
928  cmdc = (cmdhandler_type*) malloc(sizeof(cmdhandler_type));
929  if (!cmdc) {
930  ods_log_crit("[%s] unable to create thread for client: "
931  "malloc() failed", cmdh_str);
932  cmdhandler->need_to_exit = 1;
933  break;
934  }
935  cmdc->listen_fd = cmdhandler->listen_fd;
936  cmdc->client_fd = connfd;
937  cmdc->listen_addr = cmdhandler->listen_addr;
938  cmdc->engine = cmdhandler->engine;
939  cmdc->need_to_exit = cmdhandler->need_to_exit;
940  ods_thread_create(&cmdc->thread_id, &cmdhandler_accept_client,
941  (void*) cmdc);
942  count++;
943  ods_log_debug("[%s] %i clients in progress...", cmdh_str, count);
944  }
945  }
946  ods_log_debug("[%s] shutdown", cmdh_str);
947  engine = cmdhandler->engine;
948  engine->cmdhandler_done = 1;
949  return;
950 }
951 
952 
957 void
959 {
960  allocator_type* allocator = NULL;
961  if (!cmdhandler) {
962  return;
963  }
964  allocator = cmdhandler->allocator;
965  allocator_deallocate(allocator, (void*) cmdhandler);
966  return;
967 }
968 
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:788
void signconf_cleanup(signconf_type *sc)
Definition: signconf.c:542
void namedb_cleanup(namedb_type *db)
Definition: namedb.c:1139
cmdhandler_type * cmdhandler_create(allocator_type *allocator, const char *filename)
Definition: cmdhandler.c:809
void ods_fatal_exit(const char *format,...)
Definition: log.c:384
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:89
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:110
zone_zl_status zl_status
Definition: zone.h:81
int ods_strcmp(const char *s1, const char *s2)
Definition: file.c:312
int just_removed
Definition: zonelist.h:56
void cmdhandler_start(cmdhandler_type *cmdhandler)
Definition: cmdhandler.c:891
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:533
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:257
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:126
#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
task_id what
Definition: task.h:58
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
void * task
Definition: zone.h:94
#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:958
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:507