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