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