added adaptive step-intervals
[oweals/gnunet.git] / src / namestore / gnunet-namestore.c
1
2 /*
3      This file is part of GNUnet.
4      (C) 2012, 2013 Christian Grothoff (and other contributing authors)
5
6      GNUnet is free software; you can redistribute it and/or modify
7      it under the terms of the GNU General Public License as published
8      by the Free Software Foundation; either version 3, or (at your
9      option) any later version.
10
11      GNUnet is distributed in the hope that it will be useful, but
12      WITHOUT ANY WARRANTY; without even the implied warranty of
13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14      General Public License for more details.
15
16      You should have received a copy of the GNU General Public License
17      along with GNUnet; see the file COPYING.  If not, write to the
18      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19      Boston, MA 02111-1307, USA.
20 */
21 /**
22  * @file gnunet-namestore.c
23  * @brief command line tool to manipulate the local zone
24  * @author Christian Grothoff
25  *
26  * TODO:
27  * - test
28  */
29 #include "platform.h"
30 #include <gnunet_util_lib.h>
31 #include <gnunet_dnsparser_lib.h>
32 #include <gnunet_identity_service.h>
33 #include <gnunet_gnsrecord_lib.h>
34 #include <gnunet_namestore_service.h>
35
36
37 /**
38  * Handle to the namestore.
39  */
40 static struct GNUNET_NAMESTORE_Handle *ns;
41
42 /**
43  * Private key for the our zone.
44  */
45 static struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
46
47 /**
48  * Handle to identity lookup.
49  */
50 static struct GNUNET_IDENTITY_EgoLookup *el;
51
52 /**
53  * Name of the ego controlling the zone.
54  */
55 static char *ego_name;
56
57 /**
58  * Desired action is to add a record.
59  */
60 static int add;
61
62 /**
63  * Queue entry for the 'add-uri' operation.
64  */
65 static struct GNUNET_NAMESTORE_QueueEntry *add_qe_uri;
66
67 /**
68  * Queue entry for the 'add' operation.
69  */
70 static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
71
72 /**
73  * Queue entry for the 'reverse lookup' operation (in combination with a name).
74  */
75 static struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
76
77 /**
78  * Desired action is to list records.
79  */
80 static int list;
81
82 /**
83  * List iterator for the 'list' operation.
84  */
85 static struct GNUNET_NAMESTORE_ZoneIterator *list_it;
86
87 /**
88  * Desired action is to remove a record.
89  */
90 static int del;
91
92 /**
93  * Is record public (opposite of #GNUNET_GNSRECORD_RF_PRIVATE)
94  */
95 static int public;
96
97 /**
98  * Is record a shadow record (#GNUNET_GNSRECORD_RF_SHADOW_RECORD)
99  */
100 static int shadow;
101
102 /**
103  * Queue entry for the 'del' operation.
104  */
105 static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
106
107 /**
108  * Name of the records to add/list/remove.
109  */
110 static char *name;
111
112 /**
113  * Value of the record to add/remove.
114  */
115 static char *value;
116
117 /**
118  * URI to import.
119  */
120 static char *uri;
121
122 /**
123  * Reverse lookup to perform.
124  */
125 static char *reverse_pkey;
126
127 /**
128  * Type of the record to add/remove, NULL to remove all.
129  */
130 static char *typestring;
131
132 /**
133  * Desired expiration time.
134  */
135 static char *expirationstring;
136
137 /**
138  * Global return value
139  */
140 static int ret;
141
142 /**
143  * Type string converted to DNS type value.
144  */
145 static uint32_t type;
146
147 /**
148  * Value in binary format.
149  */
150 static void *data;
151
152 /**
153  * Number of bytes in 'data'.
154  */
155 static size_t data_size;
156
157 /**
158  * Expirationstring converted to relative time.
159  */
160 static struct GNUNET_TIME_Relative etime_rel;
161
162 /**
163  * Expirationstring converted to absolute time.
164  */
165 static struct GNUNET_TIME_Absolute etime_abs;
166
167 /**
168  * Is expiration time relative or absolute time?
169  */
170 static int etime_is_rel = GNUNET_SYSERR;
171
172 /**
173  * Monitor handle.
174  */
175 static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
176
177 /**
178  * Enables monitor mode.
179  */
180 static int monitor;
181
182
183 /**
184  * Task run on shutdown.  Cleans up everything.
185  *
186  * @param cls unused
187  * @param tc scheduler context
188  */
189 static void
190 do_shutdown (void *cls,
191              const struct GNUNET_SCHEDULER_TaskContext *tc)
192 {
193   if (NULL != el)
194   {
195     GNUNET_IDENTITY_ego_lookup_cancel (el);
196     el = NULL;
197   }
198   if (NULL != list_it)
199   {
200     GNUNET_NAMESTORE_zone_iteration_stop (list_it);
201     list_it = NULL;
202   }
203   if (NULL != add_qe)
204   {
205     GNUNET_NAMESTORE_cancel (add_qe);
206     add_qe = NULL;
207   }
208   if (NULL != add_qe_uri)
209   {
210     GNUNET_NAMESTORE_cancel (add_qe_uri);
211     add_qe_uri = NULL;
212   }
213   if (NULL != del_qe)
214   {
215     GNUNET_NAMESTORE_cancel (del_qe);
216     del_qe = NULL;
217   }
218   if (NULL != ns)
219   {
220     GNUNET_NAMESTORE_disconnect (ns);
221     ns = NULL;
222   }
223   memset (&zone_pkey, 0, sizeof (zone_pkey));
224   if (NULL != uri)
225   {
226     GNUNET_free (uri);
227     uri = NULL;
228   }
229   if (NULL != zm)
230   {
231     GNUNET_NAMESTORE_zone_monitor_stop (zm);
232     zm = NULL;
233   }
234   if (NULL != data)
235   {
236     GNUNET_free (data);
237     data = NULL;
238   }
239 }
240
241
242 /**
243  * Check if we are finished, and if so, perform shutdown.
244  */
245 static void
246 test_finished ()
247 {
248   if ( (NULL == add_qe) &&
249        (NULL == add_qe_uri) &&
250        (NULL == del_qe) &&
251        (NULL == reverse_qe) &&
252        (NULL == list_it) )
253     GNUNET_SCHEDULER_shutdown ();
254 }
255
256
257 /**
258  * Continuation called to notify client about result of the
259  * operation.
260  *
261  * @param cls closure, location of the QueueEntry pointer to NULL out
262  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
263  *                #GNUNET_NO if content was already there
264  *                #GNUNET_YES (or other positive value) on success
265  * @param emsg NULL on success, otherwise an error message
266  */
267 static void
268 add_continuation (void *cls,
269                   int32_t success,
270                   const char *emsg)
271 {
272   struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
273
274   *qe = NULL;
275   if (GNUNET_YES != success)
276   {
277     fprintf (stderr,
278              _("Adding record failed: %s\n"),
279              (GNUNET_NO == success) ? "record exists" : emsg);
280     if (GNUNET_NO != success)
281       ret = 1;
282   }
283   test_finished ();
284 }
285
286
287 /**
288  * Continuation called to notify client about result of the
289  * operation.
290  *
291  * @param cls closure, unused
292  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
293  *                #GNUNET_NO if content was already there
294  *                #GNUNET_YES (or other positive value) on success
295  * @param emsg NULL on success, otherwise an error message
296  */
297 static void
298 del_continuation (void *cls,
299                   int32_t success,
300                   const char *emsg)
301 {
302   del_qe = NULL;
303   if (GNUNET_NO == success)
304   {
305     fprintf (stderr,
306              _("Deleting record failed, record does not exist%s%s\n"),
307              (NULL != emsg) ? ": " : "",
308              (NULL != emsg) ? emsg : "");
309   }
310   if (GNUNET_SYSERR == success)
311   {
312     fprintf (stderr,
313              _("Deleting record failed%s%s\n"),
314              (NULL != emsg) ? ": " : "",
315              (NULL != emsg) ? emsg : "");
316   }
317   test_finished ();
318 }
319
320
321 /**
322  * Process a record that was stored in the namestore.
323  *
324  * @param cls closure
325  * @param zone_key private key of the zone
326  * @param rname name that is being mapped (at most 255 characters long)
327  * @param rd_len number of entries in @a rd array
328  * @param rd array of records with data to store
329  */
330 static void
331 display_record (void *cls,
332                 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
333                 const char *rname,
334                 unsigned int rd_len,
335                 const struct GNUNET_GNSRECORD_Data *rd)
336 {
337   const char *typestring;
338   char *s;
339   unsigned int i;
340   const char *ets;
341   struct GNUNET_TIME_Absolute at;
342   struct GNUNET_TIME_Relative rt;
343
344   if (NULL == rname)
345   {
346     list_it = NULL;
347     test_finished ();
348     return;
349   }
350   if ( (NULL != name) &&
351        (0 != strcmp (name, rname)) )
352   {
353     GNUNET_NAMESTORE_zone_iterator_next (list_it);
354     return;
355   }
356   FPRINTF (stdout,
357            "%s:\n",
358            rname);
359   for (i=0;i<rd_len;i++)
360   {
361     typestring = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
362     s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
363                                           rd[i].data,
364                                           rd[i].data_size);
365     if (NULL == s)
366     {
367       FPRINTF (stdout, _("\tCorrupt or unsupported record of type %u\n"),
368                (unsigned int) rd[i].record_type);
369       continue;
370     }
371     if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
372     {
373       rt.rel_value_us = rd[i].expiration_time;
374       ets = GNUNET_STRINGS_relative_time_to_string (rt, GNUNET_YES);
375     }
376     else
377     {
378       at.abs_value_us = rd[i].expiration_time;
379       ets = GNUNET_STRINGS_absolute_time_to_string (at);
380     }
381     FPRINTF (stdout,
382              "\t%s: %s (%s)\t%s\t%s\t%s\n",
383              typestring,
384              s,
385              ets,
386              (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) ? "PRIVATE" : "PUBLIC",
387              (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)) ? "SHADOW" : "",
388              (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PENDING)) ? "PENDING" : "");
389     GNUNET_free (s);
390   }
391   FPRINTF (stdout, "%s", "\n");
392   GNUNET_NAMESTORE_zone_iterator_next (list_it);
393 }
394
395
396 /**
397  * Function called once we are in sync in monitor mode.
398  *
399  * @param cls NULL
400  */
401 static void
402 sync_cb (void *cls)
403 {
404   FPRINTF (stdout, "%s", "Monitor is now in sync.\n");
405 }
406
407
408 /**
409  * We're storing a record; this function is given the existing record
410  * so that we can merge the information.
411  *
412  * @param cls closure, unused
413  * @param zone_key private key of the zone
414  * @param rec_name name that is being mapped (at most 255 characters long)
415  * @param rd_count number of entries in @a rd array
416  * @param rd array of records with data to store
417  */
418 static void
419 get_existing_record (void *cls,
420                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
421                      const char *rec_name,
422                      unsigned int rd_count,
423                      const struct GNUNET_GNSRECORD_Data *rd)
424 {
425   struct GNUNET_GNSRECORD_Data rdn[rd_count + 1];
426   struct GNUNET_GNSRECORD_Data *rde;
427
428   add_qe = NULL;
429   if ( (NULL != zone_key) &&
430        (0 != strcmp (rec_name, name)) )
431   {
432     GNUNET_break (0);
433     return;
434   }
435
436   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received %u records for name `%s'\n",
437       rd_count, rec_name);
438
439   memset (rdn, 0, sizeof (struct GNUNET_GNSRECORD_Data));
440   memcpy (&rdn[1], rd, rd_count * sizeof (struct GNUNET_GNSRECORD_Data));
441   /* FIXME: should add some logic to overwrite records if there
442      can only be one record of a particular type, and to check
443      if the combination of records is valid to begin with... */
444   rde = &rdn[0];
445   rde->data = data;
446   rde->data_size = data_size;
447   rde->record_type = type;
448   if (1 == shadow)
449     rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
450   if (1 != public)
451     rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
452   if (GNUNET_YES == etime_is_rel)
453   {
454     rde->expiration_time = etime_rel.rel_value_us;
455     rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
456   }
457   else if (GNUNET_NO == etime_is_rel)
458     rde->expiration_time = etime_abs.abs_value_us;
459   else
460     rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
461   GNUNET_assert (NULL != name);
462   add_qe = GNUNET_NAMESTORE_records_store (ns,
463                                            &zone_pkey,
464                                            name,
465                                            rd_count + 1,
466                                            rde,
467                                            &add_continuation,
468                                            &add_qe);
469 }
470
471
472 /**
473  * Function called with the result of our attempt to obtain a name for a given
474  * public key.
475  *
476  * @param cls NULL
477  * @param zone private key of the zone; NULL on disconnect
478  * @param label label of the records; NULL on disconnect
479  * @param rd_count number of entries in @a rd array, 0 if label was deleted
480  * @param rd array of records with data to store
481  */
482 static void
483 handle_reverse_lookup (void *cls,
484                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
485                        const char *label,
486                        unsigned int rd_count,
487                        const struct GNUNET_GNSRECORD_Data *rd)
488 {
489   reverse_qe = NULL;
490   if (NULL == label)
491     FPRINTF (stdout,
492              "%s.zkey\n",
493              reverse_pkey);
494   else
495     FPRINTF (stdout,
496              "%s.gnu\n",
497              label);
498   test_finished ();
499 }
500
501
502 /**
503  * Function called with the result from the check if the namestore
504  * service is actually running.  If it is, we start the actual
505  * operation.
506  *
507  * @param cls closure with our configuration
508  * @param result #GNUNET_YES if the namestore service is running
509  */
510 static void
511 testservice_task (void *cls,
512                   int result)
513 {
514   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
515   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
516   struct GNUNET_GNSRECORD_Data rd;
517
518   if (GNUNET_YES != result)
519   {
520     FPRINTF (stderr, _("Service `%s' is not running\n"),
521              "namestore");
522     return;
523   }
524   if (! (add|del|list|(NULL != uri)|(NULL != reverse_pkey)) )
525   {
526     /* nothing more to be done */
527     fprintf (stderr,
528              _("No options given\n"));
529     GNUNET_SCHEDULER_shutdown ();
530     return;
531   }
532   GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey,
533                                     &pub);
534
535   ns = GNUNET_NAMESTORE_connect (cfg);
536   if (NULL == ns)
537   {
538     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
539                 _("Failed to connect to namestore\n"));
540     return;
541   }
542   if (add)
543   {
544     if (NULL == name)
545     {
546       fprintf (stderr,
547                _("Missing option `%s' for operation `%s'\n"),
548                "-n", _("add"));
549       GNUNET_SCHEDULER_shutdown ();
550       ret = 1;
551       return;
552     }
553     if (NULL == typestring)
554     {
555       fprintf (stderr,
556                _("Missing option `%s' for operation `%s'\n"),
557                "-t", _("add"));
558       GNUNET_SCHEDULER_shutdown ();
559       ret = 1;
560       return;
561     }
562     type = GNUNET_GNSRECORD_typename_to_number (typestring);
563     if (UINT32_MAX == type)
564     {
565       fprintf (stderr, _("Unsupported type `%s'\n"), typestring);
566       GNUNET_SCHEDULER_shutdown ();
567       ret = 1;
568       return;
569     }
570     if (NULL == value)
571     {
572       fprintf (stderr,
573                _("Missing option `%s' for operation `%s'\n"),
574                "-V", _("add"));
575       ret = 1;
576       GNUNET_SCHEDULER_shutdown ();
577       return;
578     }
579     if (GNUNET_OK !=
580         GNUNET_GNSRECORD_string_to_value (type,
581                                           value,
582                                           &data,
583                                           &data_size))
584     {
585       fprintf (stderr, _("Value `%s' invalid for record type `%s'\n"),
586                value,
587                typestring);
588       GNUNET_SCHEDULER_shutdown ();
589       ret = 1;
590       return;
591     }
592     if (NULL == expirationstring)
593     {
594       fprintf (stderr,
595                _("Missing option `%s' for operation `%s'\n"),
596                "-e", _("add"));
597       GNUNET_SCHEDULER_shutdown ();
598       ret = 1;
599       return;
600     }
601     if (0 == strcmp (expirationstring, "never"))
602     {
603       etime_abs = GNUNET_TIME_UNIT_FOREVER_ABS;
604       etime_is_rel = GNUNET_NO;
605     }
606     else if (GNUNET_OK ==
607              GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
608                                                     &etime_rel))
609     {
610       etime_is_rel = GNUNET_YES;
611     }
612     else if (GNUNET_OK ==
613              GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
614                                                     &etime_abs))
615     {
616       etime_is_rel = GNUNET_NO;
617     }
618     else
619     {
620       fprintf (stderr,
621                _("Invalid time format `%s'\n"),
622                expirationstring);
623       GNUNET_SCHEDULER_shutdown ();
624       ret = 1;
625       return;
626     }
627     add_qe = GNUNET_NAMESTORE_records_lookup (ns, &zone_pkey, name,
628         &get_existing_record, NULL );
629   }
630   if (del)
631   {
632     if (NULL == name)
633     {
634       fprintf (stderr,
635                _("Missing option `%s' for operation `%s'\n"),
636                "-n", _("del"));
637       GNUNET_SCHEDULER_shutdown ();
638       ret = 1;
639       return;
640     }
641     del_qe = GNUNET_NAMESTORE_records_store (ns,
642                                              &zone_pkey,
643                                              name,
644                                              0, NULL,
645                                              &del_continuation,
646                                              NULL);
647   }
648   if (list)
649   {
650     list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
651                                                      &zone_pkey,
652                                                      &display_record,
653                                                      NULL);
654   }
655   if (NULL != reverse_pkey)
656   {
657     struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
658
659     if (GNUNET_OK !=
660         GNUNET_CRYPTO_ecdsa_public_key_from_string (reverse_pkey,
661                                                        strlen (reverse_pkey),
662                                                        &pubkey))
663     {
664       fprintf (stderr,
665                _("Invalid public key for reverse lookup `%s'\n"),
666                reverse_pkey);
667       GNUNET_SCHEDULER_shutdown ();
668     }
669     reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
670                                                 &zone_pkey,
671                                                 &pubkey,
672                                                 &handle_reverse_lookup,
673                                                 NULL);
674   }
675   if (NULL != uri)
676   {
677     char sh[105];
678     char sname[64];
679     struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
680
681     if ( (2 != (sscanf (uri,
682                         "gnunet://gns/%104s/%63s",
683                         sh,
684                         sname)) ) ||
685          (GNUNET_OK !=
686           GNUNET_CRYPTO_ecdsa_public_key_from_string (sh, strlen (sh), &pkey)) )
687     {
688       fprintf (stderr,
689                _("Invalid URI `%s'\n"),
690                uri);
691       GNUNET_SCHEDULER_shutdown ();
692       ret = 1;
693       return;
694     }
695     memset (&rd, 0, sizeof (rd));
696     rd.data = &pkey;
697     rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
698     rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
699     if (GNUNET_YES == etime_is_rel)
700     {
701       rd.expiration_time = etime_rel.rel_value_us;
702       rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
703     }
704     else if (GNUNET_NO == etime_is_rel)
705       rd.expiration_time = etime_abs.abs_value_us;
706     else
707       rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
708     if (1 != shadow)
709       rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
710     add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
711                                                  &zone_pkey,
712                                                  sname,
713                                                  1,
714                                                  &rd,
715                                                  &add_continuation,
716                                                  &add_qe_uri);
717   }
718   if (monitor)
719   {
720     zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
721                                               &zone_pkey,
722                                               GNUNET_YES,
723                                               &display_record,
724                                               &sync_cb,
725                                               NULL);
726   }
727 }
728
729
730 /**
731  * Callback invoked from identity service with ego information.
732  * An @a ego of NULL means the ego was not found.
733  *
734  * @param cls closure with the configuration
735  * @param ego an ego known to identity service, or NULL
736  */
737 static void
738 identity_cb (void *cls,
739              const struct GNUNET_IDENTITY_Ego *ego)
740 {
741   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
742
743   el = NULL;
744   if (NULL == ego)
745   {
746     fprintf (stderr,
747              _("Ego `%s' not known to identity service\n"),
748              ego_name);
749     GNUNET_SCHEDULER_shutdown ();
750     return;
751   }
752   zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
753   GNUNET_free (ego_name);
754   ego_name = NULL;
755   GNUNET_CLIENT_service_test ("namestore", cfg,
756                               GNUNET_TIME_UNIT_SECONDS,
757                               &testservice_task,
758                               (void *) cfg);
759 }
760
761
762 /**
763  * Main function that will be run.
764  *
765  * @param cls closure
766  * @param args remaining command-line arguments
767  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
768  * @param cfg configuration
769  */
770 static void
771 run (void *cls, char *const *args, const char *cfgfile,
772      const struct GNUNET_CONFIGURATION_Handle *cfg)
773 {
774   if (NULL == ego_name)
775   {
776     fprintf (stderr,
777              _("You must specify which zone should be accessed\n"));
778     return;
779   }
780   if ( (NULL != args[0]) && (NULL == uri) )
781     uri = GNUNET_strdup (args[0]);
782   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
783                                 &do_shutdown, NULL);
784   el = GNUNET_IDENTITY_ego_lookup (cfg,
785                                    ego_name,
786                                    &identity_cb,
787                                    (void *) cfg);
788 }
789
790
791 /**
792  * The main function for gnunet-namestore.
793  *
794  * @param argc number of arguments from the command line
795  * @param argv command line arguments
796  * @return 0 ok, 1 on error
797  */
798 int
799 main (int argc, char *const *argv)
800 {
801   public = -1;
802   shadow = -1;
803
804   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
805     {'a', "add", NULL,
806      gettext_noop ("add record"), 0,
807      &GNUNET_GETOPT_set_one, &add},
808     {'d', "delete", NULL,
809      gettext_noop ("delete record"), 0,
810      &GNUNET_GETOPT_set_one, &del},
811     {'D', "display", NULL,
812      gettext_noop ("display records"), 0,
813      &GNUNET_GETOPT_set_one, &list},
814     {'e', "expiration", "TIME",
815      gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"), 1,
816      &GNUNET_GETOPT_set_string, &expirationstring},
817     {'m', "monitor", NULL,
818      gettext_noop ("monitor changes in the namestore"), 0,
819      &GNUNET_GETOPT_set_one, &monitor},
820     {'n', "name", "NAME",
821      gettext_noop ("name of the record to add/delete/display"), 1,
822      &GNUNET_GETOPT_set_string, &name},
823     {'r', "reverse", "PKEY",
824      gettext_noop ("determine our name for the given PKEY"), 1,
825      &GNUNET_GETOPT_set_string, &reverse_pkey},
826     {'t', "type", "TYPE",
827      gettext_noop ("type of the record to add/delete/display"), 1,
828      &GNUNET_GETOPT_set_string, &typestring},
829     {'u', "uri", "URI",
830      gettext_noop ("URI to import into our zone"), 1,
831      &GNUNET_GETOPT_set_string, &uri},
832     {'V', "value", "VALUE",
833      gettext_noop ("value of the record to add/delete"), 1,
834      &GNUNET_GETOPT_set_string, &value},
835     {'p', "public", NULL,
836      gettext_noop ("create or list public record"), 0,
837      &GNUNET_GETOPT_set_one, &public},
838     {'s', "shadow", NULL,
839      gettext_noop ("create shadow record (only valid if all other records of the same type have expired"), 0,
840      &GNUNET_GETOPT_set_one, &shadow},
841     {'z', "zone", "EGO",
842      gettext_noop ("name of the ego controlling the zone"), 1,
843      &GNUNET_GETOPT_set_string, &ego_name},
844     GNUNET_GETOPT_OPTION_END
845   };
846
847   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
848     return 2;
849
850   GNUNET_log_setup ("gnunet-namestore", "WARNING", NULL);
851   if (GNUNET_OK !=
852       GNUNET_PROGRAM_run (argc, argv, "gnunet-namestore",
853                           _("GNUnet zone manipulation tool"),
854                           options,
855                           &run, NULL))
856   {
857     GNUNET_free ((void*) argv);
858     GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
859     return 1;
860   }
861   GNUNET_free ((void*) argv);
862   GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
863   return ret;
864 }
865
866 /* end of gnunet-namestore.c */