2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2014 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
21 * @file gnunet-namestore.c
22 * @brief command line tool to manipulate the local zone
23 * @author Christian Grothoff
29 #include <gnunet_util_lib.h>
30 #include <gnunet_dnsparser_lib.h>
31 #include <gnunet_identity_service.h>
32 #include <gnunet_gnsrecord_lib.h>
33 #include <gnunet_gns_service.h>
34 #include <gnunet_namestore_service.h>
38 * Entry in record set for bulk processing.
43 * Kept in a linked list.
45 struct RecordSetEntry *next;
48 * The record to add/remove.
50 struct GNUNET_GNSRECORD_Data record;
56 * Handle to the namestore.
58 static struct GNUNET_NAMESTORE_Handle *ns;
61 * Private key for the our zone.
63 static struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
66 * Handle to identity lookup.
68 static struct GNUNET_IDENTITY_EgoLookup *el;
71 * Identity service handle
73 static struct GNUNET_IDENTITY_Handle *idh;
78 struct GNUNET_IDENTITY_Operation *get_default;
81 * Name of the ego controlling the zone.
83 static char *ego_name;
86 * Desired action is to add a record.
91 * Queue entry for the 'add-uri' operation.
93 static struct GNUNET_NAMESTORE_QueueEntry *add_qe_uri;
96 * Queue entry for the 'add' operation.
98 static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
101 * Queue entry for the 'lookup' operation.
103 static struct GNUNET_NAMESTORE_QueueEntry *get_qe;
106 * Queue entry for the 'reverse lookup' operation (in combination with a name).
108 static struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
111 * Desired action is to list records.
116 * List iterator for the 'list' operation.
118 static struct GNUNET_NAMESTORE_ZoneIterator *list_it;
121 * Desired action is to remove a record.
126 * Is record public (opposite of #GNUNET_GNSRECORD_RF_PRIVATE)
128 static int is_public;
131 * Is record a shadow record (#GNUNET_GNSRECORD_RF_SHADOW_RECORD)
133 static int is_shadow;
136 * Queue entry for the 'del' operation.
138 static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
141 * Queue entry for the 'set/replace' operation.
143 static struct GNUNET_NAMESTORE_QueueEntry *set_qe;
146 * Name of the records to add/list/remove.
151 * Value of the record to add/remove.
161 * Reverse lookup to perform.
163 static char *reverse_pkey;
166 * Type of the record to add/remove, NULL to remove all.
168 static char *typestring;
171 * Desired expiration time.
173 static char *expirationstring;
178 static char *nickstring;
181 * Global return value
186 * Type string converted to DNS type value.
188 static uint32_t type;
191 * Value in binary format.
196 * Number of bytes in #data.
198 static size_t data_size;
201 * Expiration string converted to numeric value.
203 static uint64_t etime;
206 * Is expiration time relative or absolute time?
208 static int etime_is_rel = GNUNET_SYSERR;
213 static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
216 * Enables monitor mode.
221 * Entry in record set for processing records in bulk.
223 static struct RecordSetEntry *recordset;
227 * Task run on shutdown. Cleans up everything.
232 do_shutdown (void *cls)
235 if (NULL != get_default)
237 GNUNET_IDENTITY_cancel (get_default);
242 GNUNET_IDENTITY_disconnect (idh);
247 GNUNET_IDENTITY_ego_lookup_cancel (el);
252 GNUNET_NAMESTORE_zone_iteration_stop (list_it);
257 GNUNET_NAMESTORE_cancel (add_qe);
262 GNUNET_NAMESTORE_cancel (set_qe);
265 if (NULL != add_qe_uri)
267 GNUNET_NAMESTORE_cancel (add_qe_uri);
272 GNUNET_NAMESTORE_cancel (get_qe);
277 GNUNET_NAMESTORE_cancel (del_qe);
282 GNUNET_NAMESTORE_disconnect (ns);
285 memset (&zone_pkey, 0, sizeof (zone_pkey));
293 GNUNET_NAMESTORE_zone_monitor_stop (zm);
305 * Check if we are finished, and if so, perform shutdown.
310 if ( (NULL == add_qe) &&
311 (NULL == add_qe_uri) &&
314 (NULL == reverse_qe) &&
316 GNUNET_SCHEDULER_shutdown ();
321 * Continuation called to notify client about result of the
324 * @param cls closure, location of the QueueEntry pointer to NULL out
325 * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
326 * #GNUNET_NO if content was already there
327 * #GNUNET_YES (or other positive value) on success
328 * @param emsg NULL on success, otherwise an error message
331 add_continuation (void *cls,
335 struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
338 if (GNUNET_YES != success)
341 _("Adding record failed: %s\n"),
342 (GNUNET_NO == success) ? "record exists" : emsg);
343 if (GNUNET_NO != success)
352 * Continuation called to notify client about result of the
355 * @param cls closure, unused
356 * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
357 * #GNUNET_NO if content was already there
358 * #GNUNET_YES (or other positive value) on success
359 * @param emsg NULL on success, otherwise an error message
362 del_continuation (void *cls,
368 if (GNUNET_NO == success)
371 _("Deleting record failed, record does not exist%s%s\n"),
372 (NULL != emsg) ? ": " : "",
373 (NULL != emsg) ? emsg : "");
375 if (GNUNET_SYSERR == success)
378 _("Deleting record failed%s%s\n"),
379 (NULL != emsg) ? ": " : "",
380 (NULL != emsg) ? emsg : "");
387 * Function called when we are done with a zone iteration.
390 zone_iteration_finished (void *cls)
399 * Function called when we encountered an error in a zone iteration.
402 zone_iteration_error_cb (void *cls)
407 "Error iterating over zone\n");
414 * Process a record that was stored in the namestore.
416 * @param rname name that is being mapped (at most 255 characters long)
417 * @param rd_len number of entries in @a rd array
418 * @param rd array of records with data to store
421 display_record (const char *rname,
423 const struct GNUNET_GNSRECORD_Data *rd)
425 const char *typestring;
428 struct GNUNET_TIME_Absolute at;
429 struct GNUNET_TIME_Relative rt;
431 if ( (NULL != name) &&
432 (0 != strcmp (name, rname)) )
434 GNUNET_NAMESTORE_zone_iterator_next (list_it,
441 for (unsigned int i=0;i<rd_len;i++)
443 if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
445 GNUNET_GNS_EMPTY_LABEL_AT)) )
447 typestring = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
448 s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
454 _("\tCorrupt or unsupported record of type %u\n"),
455 (unsigned int) rd[i].record_type);
458 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
460 rt.rel_value_us = rd[i].expiration_time;
461 ets = GNUNET_STRINGS_relative_time_to_string (rt, GNUNET_YES);
465 at.abs_value_us = rd[i].expiration_time;
466 ets = GNUNET_STRINGS_absolute_time_to_string (at);
469 "\t%s: %s (%s)\t%s\t%s\n",
473 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) ? "PRIVATE" : "PUBLIC",
474 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)) ? "SHADOW" : "");
477 FPRINTF (stdout, "%s", "\n");
482 * Process a record that was stored in the namestore.
485 * @param zone_key private key of the zone
486 * @param rname name that is being mapped (at most 255 characters long)
487 * @param rd_len number of entries in @a rd array
488 * @param rd array of records with data to store
491 display_record_iterator (void *cls,
492 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
495 const struct GNUNET_GNSRECORD_Data *rd)
499 display_record (rname,
502 GNUNET_NAMESTORE_zone_iterator_next (list_it,
508 * Process a record that was stored in the namestore.
511 * @param zone_key private key of the zone
512 * @param rname name that is being mapped (at most 255 characters long)
513 * @param rd_len number of entries in @a rd array
514 * @param rd array of records with data to store
517 display_record_monitor (void *cls,
518 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
521 const struct GNUNET_GNSRECORD_Data *rd)
525 display_record (rname,
528 GNUNET_NAMESTORE_zone_monitor_next (zm,
534 * Process a record that was stored in the namestore.
537 * @param zone_key private key of the zone
538 * @param rname name that is being mapped (at most 255 characters long)
539 * @param rd_len number of entries in @a rd array
540 * @param rd array of records with data to store
543 display_record_lookup (void *cls,
544 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
547 const struct GNUNET_GNSRECORD_Data *rd)
552 display_record (rname,
560 * Function called once we are in sync in monitor mode.
570 "Monitor is now in sync.\n");
575 * Function called on errors while monitoring.
580 monitor_error_cb (void *cls)
585 "Monitor disconnected and out of sync.\n");
590 * Function called on errors while monitoring.
595 lookup_error_cb (void *cls)
601 "Failed to lookup record.\n");
607 * Function called if lookup fails.
610 add_error_cb (void *cls)
621 * We're storing a record; this function is given the existing record
622 * so that we can merge the information.
624 * @param cls closure, unused
625 * @param zone_key private key of the zone
626 * @param rec_name name that is being mapped (at most 255 characters long)
627 * @param rd_count number of entries in @a rd array
628 * @param rd array of records with data to store
631 get_existing_record (void *cls,
632 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
633 const char *rec_name,
634 unsigned int rd_count,
635 const struct GNUNET_GNSRECORD_Data *rd)
637 struct GNUNET_GNSRECORD_Data rdn[rd_count + 1];
638 struct GNUNET_GNSRECORD_Data *rde;
643 if (0 != strcmp (rec_name, name))
651 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
652 "Received %u records for name `%s'\n",
654 for (unsigned int i=0;i<rd_count;i++)
656 switch (rd[i].record_type)
658 case GNUNET_DNSPARSER_TYPE_CNAME:
660 _("A %s record exists already under `%s', no other records can be added.\n"),
666 case GNUNET_GNSRECORD_TYPE_PKEY:
668 _("A %s record exists already under `%s', no other records can be added.\n"),
678 case GNUNET_DNSPARSER_TYPE_CNAME:
682 _("Records already exist under `%s', cannot add `%s' record.\n"),
690 case GNUNET_GNSRECORD_TYPE_PKEY:
694 _("Records already exist under `%s', cannot add `%s' record.\n"),
702 case GNUNET_GNSRECORD_TYPE_GNS2DNS:
703 for (unsigned int i=0;i<rd_count;i++)
704 if (GNUNET_GNSRECORD_TYPE_GNS2DNS != rd[i].record_type)
707 _("Non-GNS2DNS records already exist under `%s', cannot add GNS2DNS record.\n"),
717 sizeof (struct GNUNET_GNSRECORD_Data));
718 GNUNET_memcpy (&rdn[1],
720 rd_count * sizeof (struct GNUNET_GNSRECORD_Data));
723 rde->data_size = data_size;
724 rde->record_type = type;
726 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
728 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
729 rde->expiration_time = etime;
730 if (GNUNET_YES == etime_is_rel)
731 rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
732 else if (GNUNET_NO != etime_is_rel)
733 rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
734 GNUNET_assert (NULL != name);
735 add_qe = GNUNET_NAMESTORE_records_store (ns,
746 * Function called if we encountered an error in zone-to-name.
749 reverse_error_cb (void *cls)
760 * Function called with the result of our attempt to obtain a name for a given
764 * @param zone private key of the zone; NULL on disconnect
765 * @param label label of the records; NULL on disconnect
766 * @param rd_count number of entries in @a rd array, 0 if label was deleted
767 * @param rd array of records with data to store
770 handle_reverse_lookup (void *cls,
771 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
773 unsigned int rd_count,
774 const struct GNUNET_GNSRECORD_Data *rd)
795 * Function called if lookup for deletion fails.
798 del_lookup_error_cb (void *cls)
809 * We were asked to delete something; this function is called with
810 * the existing records. Now we should determine what should be
811 * deleted and then issue the deletion operation.
814 * @param zone private key of the zone we are deleting from
815 * @param label name of the records we are editing
816 * @param rd_count size of the @a rd array
817 * @param rd existing records
820 del_monitor (void *cls,
821 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
823 unsigned int rd_count,
824 const struct GNUNET_GNSRECORD_Data *rd)
826 struct GNUNET_GNSRECORD_Data rdx[rd_count];
827 unsigned int rd_left;
837 _("There are no records under label `%s' that could be deleted.\n"),
843 if ( (NULL == value) &&
844 (NULL == typestring) )
846 /* delete everything */
847 del_qe = GNUNET_NAMESTORE_records_store (ns,
857 if (NULL != typestring)
858 type = GNUNET_GNSRECORD_typename_to_number (typestring);
860 type = GNUNET_GNSRECORD_TYPE_ANY;
861 for (unsigned int i=0;i<rd_count;i++)
864 if (! ( ( (GNUNET_GNSRECORD_TYPE_ANY == type) ||
865 (rd[i].record_type == type) ) &&
867 (NULL == (vs = (GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
869 rd[i].data_size)))) ||
870 (0 == strcmp (vs, value)) ) ) )
871 rdx[rd_left++] = rd[i];
872 GNUNET_free_non_null (vs);
874 if (rd_count == rd_left)
876 /* nothing got deleted */
878 _("There are no records under label `%s' that match the request for deletion.\n"),
883 /* delete everything but what we copied to 'rdx' */
884 del_qe = GNUNET_NAMESTORE_records_store (ns,
895 * Parse expiration time.
897 * @param expirationstring text to parse
898 * @param etime_is_rel[out] set to #GNUNET_YES if time is relative
899 * @param etime[out] set to expiration time (abs or rel)
900 * @return #GNUNET_OK on success
903 parse_expiration (const char *expirationstring,
907 struct GNUNET_TIME_Relative etime_rel;
908 struct GNUNET_TIME_Absolute etime_abs;
910 if (0 == strcmp (expirationstring,
913 *etime = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
914 *etime_is_rel = GNUNET_NO;
918 GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
921 *etime_is_rel = GNUNET_YES;
922 *etime = etime_rel.rel_value_us;
923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
924 "Storing record with relative expiration time of %s\n",
925 GNUNET_STRINGS_relative_time_to_string (etime_rel,
930 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
933 *etime_is_rel = GNUNET_NO;
934 *etime = etime_abs.abs_value_us;
935 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
936 "Storing record with absolute expiration time of %s\n",
937 GNUNET_STRINGS_absolute_time_to_string (etime_abs));
940 return GNUNET_SYSERR;
945 * Function called when namestore is done with the replace
949 * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
950 * #GNUNET_NO if content was already there or not found
951 * #GNUNET_YES (or other positive value) on success
952 * @param emsg NULL on success, otherwise an error message
955 replace_cont (void *cls,
962 if (GNUNET_OK != success)
964 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
965 _("Failed to replace records: %s\n"),
967 ret = 1; /* fail from 'main' */
969 GNUNET_SCHEDULER_shutdown ();
974 * Callback invoked from identity service with ego information.
975 * An @a ego of NULL means the ego was not found.
977 * @param cls closure with the configuration
978 * @param ego an ego known to identity service, or NULL
981 identity_cb (void *cls,
982 const struct GNUNET_IDENTITY_Ego *ego)
984 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
985 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
986 struct GNUNET_GNSRECORD_Data rd;
991 if (NULL != ego_name)
994 _("Ego `%s' not known to identity service\n"),
997 GNUNET_SCHEDULER_shutdown ();
1001 zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1002 GNUNET_free_non_null (ego_name);
1005 if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey)|(NULL != recordset)) )
1007 /* nothing more to be done */
1009 _("No options given\n"));
1010 GNUNET_SCHEDULER_shutdown ();
1013 GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey,
1015 ns = GNUNET_NAMESTORE_connect (cfg);
1018 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1019 _("Failed to connect to namestore\n"));
1023 if (NULL != recordset)
1025 /* replace entire record set */
1026 unsigned int rd_count;
1027 struct GNUNET_GNSRECORD_Data *rd;
1032 _("Missing option `%s' for operation `%s'\n"),
1033 "-R", _("replace"));
1034 GNUNET_SCHEDULER_shutdown ();
1039 for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
1041 rd = GNUNET_new_array (rd_count,
1042 struct GNUNET_GNSRECORD_Data);
1044 for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
1046 rd[rd_count] = e->record;
1049 set_qe = GNUNET_NAMESTORE_records_store (ns,
1065 _("Missing option `%s' for operation `%s'\n"),
1067 GNUNET_SCHEDULER_shutdown ();
1071 if (NULL == typestring)
1074 _("Missing option `%s' for operation `%s'\n"),
1076 GNUNET_SCHEDULER_shutdown ();
1080 type = GNUNET_GNSRECORD_typename_to_number (typestring);
1081 if (UINT32_MAX == type)
1084 _("Unsupported type `%s'\n"),
1086 GNUNET_SCHEDULER_shutdown ();
1093 _("Missing option `%s' for operation `%s'\n"),
1096 GNUNET_SCHEDULER_shutdown ();
1100 GNUNET_GNSRECORD_string_to_value (type,
1106 _("Value `%s' invalid for record type `%s'\n"),
1109 GNUNET_SCHEDULER_shutdown ();
1113 if (NULL == expirationstring)
1116 _("Missing option `%s' for operation `%s'\n"),
1119 GNUNET_SCHEDULER_shutdown ();
1124 parse_expiration (expirationstring,
1129 _("Invalid time format `%s'\n"),
1131 GNUNET_SCHEDULER_shutdown ();
1135 add_qe = GNUNET_NAMESTORE_records_lookup (ns,
1140 &get_existing_record,
1148 _("Missing option `%s' for operation `%s'\n"),
1150 GNUNET_SCHEDULER_shutdown ();
1154 del_qe = GNUNET_NAMESTORE_records_lookup (ns,
1157 &del_lookup_error_cb,
1165 get_qe = GNUNET_NAMESTORE_records_lookup (ns,
1170 &display_record_lookup,
1173 list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
1175 &zone_iteration_error_cb,
1177 &display_record_iterator,
1179 &zone_iteration_finished,
1182 if (NULL != reverse_pkey)
1184 struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
1187 GNUNET_CRYPTO_ecdsa_public_key_from_string (reverse_pkey,
1188 strlen (reverse_pkey),
1192 _("Invalid public key for reverse lookup `%s'\n"),
1194 GNUNET_SCHEDULER_shutdown ();
1196 reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
1201 &handle_reverse_lookup,
1208 struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1210 GNUNET_STRINGS_utf8_tolower (uri, uri);
1211 if ( (2 != (sscanf (uri,
1212 "gnunet://gns/%52s/%63s",
1216 GNUNET_CRYPTO_ecdsa_public_key_from_string (sh,
1221 _("Invalid URI `%s'\n"),
1223 GNUNET_SCHEDULER_shutdown ();
1227 memset (&rd, 0, sizeof (rd));
1229 rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1230 rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
1231 rd.expiration_time = etime;
1232 if (GNUNET_YES == etime_is_rel)
1233 rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1235 rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
1236 add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
1244 if (NULL != nickstring)
1246 if (0 == strlen(nickstring))
1249 _("Invalid nick `%s'\n"),
1251 GNUNET_SCHEDULER_shutdown ();
1255 add_qe_uri = GNUNET_NAMESTORE_set_nick (ns,
1263 zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
1268 &display_record_monitor,
1277 default_ego_cb (void *cls,
1278 struct GNUNET_IDENTITY_Ego *ego,
1289 _("No default ego configured in identity service\n"));
1290 GNUNET_SCHEDULER_shutdown ();
1296 identity_cb (cls, ego);
1302 id_connect_cb (void *cls,
1303 struct GNUNET_IDENTITY_Ego *ego,
1307 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1314 get_default = GNUNET_IDENTITY_get (idh,
1323 * Main function that will be run.
1325 * @param cls closure
1326 * @param args remaining command-line arguments
1327 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1328 * @param cfg configuration
1333 const char *cfgfile,
1334 const struct GNUNET_CONFIGURATION_Handle *cfg)
1339 if (NULL != args[0])
1340 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1341 _("Superfluous command line arguments (starting with `%s') ignored\n"),
1343 if ( (NULL != args[0]) &&
1345 uri = GNUNET_strdup (args[0]);
1347 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1350 if (NULL == ego_name)
1352 idh = GNUNET_IDENTITY_connect (cfg,
1357 _("Cannot connect to identity service\n"));
1361 el = GNUNET_IDENTITY_ego_lookup (cfg,
1369 * Command-line option parser function that allows the user to specify
1370 * a complete record as one argument for adding/removing. A pointer
1371 * to the head of the list of record sets must be passed as the "scls"
1374 * @param ctx command line processor context
1375 * @param scls must be of type "struct GNUNET_FS_Uri **"
1376 * @param option name of the option (typically 'R')
1377 * @param value command line argument given; format is
1378 * "TTL TYPE FLAGS VALUE" where TTL is an expiration time (rel or abs),
1379 * always given in seconds (without the unit),
1380 * TYPE is a DNS/GNS record type, FLAGS is either "n" for no flags or
1381 * a combination of 's' (shadow) and 'p' (public) and VALUE is the
1382 * value (in human-readable format)
1383 * @return #GNUNET_OK on success
1386 multirecord_process (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
1391 struct RecordSetEntry **head = scls;
1392 struct RecordSetEntry *r;
1393 struct GNUNET_GNSRECORD_Data record;
1402 cp = GNUNET_strdup (value);
1403 tok = strtok_r (cp, " ", &saveptr);
1406 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1407 _("Empty record line argument is not allowed.\n"));
1409 return GNUNET_SYSERR;
1414 GNUNET_asprintf (&etime_in_s,
1418 parse_expiration (etime_in_s,
1420 &record.expiration_time))
1422 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1423 _("Invalid expiration time `%s' (must be without unit)\n"),
1426 GNUNET_free (etime_in_s);
1427 return GNUNET_SYSERR;
1429 GNUNET_free (etime_in_s);
1431 tok = strtok_r (NULL, " ", &saveptr);
1434 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1435 _("Missing entries in record line `%s'.\n"),
1438 return GNUNET_SYSERR;
1440 record.record_type = GNUNET_GNSRECORD_typename_to_number (tok);
1441 if (UINT32_MAX == record.record_type)
1443 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1444 _("Unknown record type `%s'\n"),
1447 return GNUNET_SYSERR;
1449 tok = strtok_r (NULL, " ", &saveptr);
1452 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1453 _("Missing entries in record line `%s'.\n"),
1456 return GNUNET_SYSERR;
1458 record.flags = GNUNET_GNSRECORD_RF_NONE;
1460 record.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1461 if (NULL == strchr (tok, (unsigned char) 'p')) /* p = public */
1462 record.flags |= GNUNET_GNSRECORD_RF_PRIVATE;
1463 if (NULL != strchr (tok, (unsigned char) 's'))
1464 record.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
1465 /* find beginning of record value */
1466 tok = strchr (&value[tok - cp], (unsigned char) ' ');
1469 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1470 _("Missing entries in record line `%s'.\n"),
1473 return GNUNET_SYSERR;
1476 tok++; /* skip space */
1478 GNUNET_GNSRECORD_string_to_value (record.record_type,
1483 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1484 _("Invalid record data for type %s: `%s'.\n"),
1485 GNUNET_GNSRECORD_number_to_typename (record.record_type),
1487 return GNUNET_SYSERR;
1490 r = GNUNET_malloc (sizeof (struct RecordSetEntry) + record.data_size);
1492 record.data = &r[1];
1496 GNUNET_free (raw_data);
1504 * Allow user to specify keywords.
1506 * @param shortName short name of the option
1507 * @param name long name of the option
1508 * @param argumentHelp help text for the option argument
1509 * @param description long help text for the option
1510 * @param[out] topKeywords set to the desired value
1512 struct GNUNET_GETOPT_CommandLineOption
1513 multirecord_option (char shortName,
1515 const char *argumentHelp,
1516 const char *description,
1517 struct RecordSetEntry **rs)
1519 struct GNUNET_GETOPT_CommandLineOption clo = {
1520 .shortName = shortName,
1522 .argumentHelp = argumentHelp,
1523 .description = description,
1524 .require_argument = 1,
1525 .processor = &multirecord_process,
1535 * The main function for gnunet-namestore.
1537 * @param argc number of arguments from the command line
1538 * @param argv command line arguments
1539 * @return 0 ok, 1 on error
1545 struct GNUNET_GETOPT_CommandLineOption options[] = {
1546 GNUNET_GETOPT_option_flag ('a',
1548 gettext_noop ("add record"),
1550 GNUNET_GETOPT_option_flag ('d',
1552 gettext_noop ("delete record"),
1554 GNUNET_GETOPT_option_flag ('D',
1556 gettext_noop ("display records"),
1558 GNUNET_GETOPT_option_string ('e',
1561 gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"),
1563 GNUNET_GETOPT_option_string ('i',
1566 gettext_noop ("set the desired nick name for the zone"),
1568 GNUNET_GETOPT_option_flag ('m',
1570 gettext_noop ("monitor changes in the namestore"),
1572 GNUNET_GETOPT_option_string ('n',
1575 gettext_noop ("name of the record to add/delete/display"),
1577 GNUNET_GETOPT_option_string ('r',
1580 gettext_noop ("determine our name for the given PKEY"),
1582 multirecord_option ('R',
1585 gettext_noop ("set record set to values given by (possibly multiple) RECORDLINES; can be specified multiple times"),
1587 GNUNET_GETOPT_option_string ('t',
1590 gettext_noop ("type of the record to add/delete/display"),
1592 GNUNET_GETOPT_option_string ('u',
1595 gettext_noop ("URI to import into our zone"),
1597 GNUNET_GETOPT_option_string ('V',
1600 gettext_noop ("value of the record to add/delete"),
1602 GNUNET_GETOPT_option_flag ('p',
1604 gettext_noop ("create or list public record"),
1606 GNUNET_GETOPT_option_flag ('s',
1608 gettext_noop ("create shadow record (only valid if all other records of the same type have expired"),
1610 GNUNET_GETOPT_option_string ('z',
1613 gettext_noop ("name of the ego controlling the zone"),
1615 GNUNET_GETOPT_OPTION_END
1619 GNUNET_STRINGS_get_utf8_args (argc, argv,
1625 GNUNET_log_setup ("gnunet-namestore",
1629 GNUNET_PROGRAM_run (argc,
1632 _("GNUnet zone manipulation tool"),
1636 GNUNET_free ((void*) argv);
1637 GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
1640 GNUNET_free ((void*) argv);
1641 GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
1645 /* end of gnunet-namestore.c */