diff options
Diffstat (limited to 'src/namestore/gnunet-namestore.c')
-rw-r--r-- | src/namestore/gnunet-namestore.c | 375 |
1 files changed, 324 insertions, 51 deletions
diff --git a/src/namestore/gnunet-namestore.c b/src/namestore/gnunet-namestore.c index c5f48848e..8386a696d 100644 --- a/src/namestore/gnunet-namestore.c +++ b/src/namestore/gnunet-namestore.c | |||
@@ -33,6 +33,24 @@ | |||
33 | 33 | ||
34 | 34 | ||
35 | /** | 35 | /** |
36 | * Entry in record set for bulk processing. | ||
37 | */ | ||
38 | struct RecordSetEntry | ||
39 | { | ||
40 | /** | ||
41 | * Kept in a linked list. | ||
42 | */ | ||
43 | struct RecordSetEntry *next; | ||
44 | |||
45 | /** | ||
46 | * The record to add/remove. | ||
47 | */ | ||
48 | struct GNUNET_GNSRECORD_Data record; | ||
49 | |||
50 | }; | ||
51 | |||
52 | |||
53 | /** | ||
36 | * Handle to the namestore. | 54 | * Handle to the namestore. |
37 | */ | 55 | */ |
38 | static struct GNUNET_NAMESTORE_Handle *ns; | 56 | static struct GNUNET_NAMESTORE_Handle *ns; |
@@ -118,6 +136,11 @@ static int is_shadow; | |||
118 | static struct GNUNET_NAMESTORE_QueueEntry *del_qe; | 136 | static struct GNUNET_NAMESTORE_QueueEntry *del_qe; |
119 | 137 | ||
120 | /** | 138 | /** |
139 | * Queue entry for the 'set/replace' operation. | ||
140 | */ | ||
141 | static struct GNUNET_NAMESTORE_QueueEntry *set_qe; | ||
142 | |||
143 | /** | ||
121 | * Name of the records to add/list/remove. | 144 | * Name of the records to add/list/remove. |
122 | */ | 145 | */ |
123 | static char *name; | 146 | static char *name; |
@@ -173,14 +196,9 @@ static void *data; | |||
173 | static size_t data_size; | 196 | static size_t data_size; |
174 | 197 | ||
175 | /** | 198 | /** |
176 | * Expirationstring converted to relative time. | 199 | * Expiration string converted to numeric value. |
177 | */ | ||
178 | static struct GNUNET_TIME_Relative etime_rel; | ||
179 | |||
180 | /** | ||
181 | * Expirationstring converted to absolute time. | ||
182 | */ | 200 | */ |
183 | static struct GNUNET_TIME_Absolute etime_abs; | 201 | static uint64_t etime; |
184 | 202 | ||
185 | /** | 203 | /** |
186 | * Is expiration time relative or absolute time? | 204 | * Is expiration time relative or absolute time? |
@@ -197,6 +215,11 @@ static struct GNUNET_NAMESTORE_ZoneMonitor *zm; | |||
197 | */ | 215 | */ |
198 | static int monitor; | 216 | static int monitor; |
199 | 217 | ||
218 | /** | ||
219 | * Entry in record set for processing records in bulk. | ||
220 | */ | ||
221 | static struct RecordSetEntry *recordset; | ||
222 | |||
200 | 223 | ||
201 | /** | 224 | /** |
202 | * Task run on shutdown. Cleans up everything. | 225 | * Task run on shutdown. Cleans up everything. |
@@ -232,6 +255,11 @@ do_shutdown (void *cls) | |||
232 | GNUNET_NAMESTORE_cancel (add_qe); | 255 | GNUNET_NAMESTORE_cancel (add_qe); |
233 | add_qe = NULL; | 256 | add_qe = NULL; |
234 | } | 257 | } |
258 | if (NULL != set_qe) | ||
259 | { | ||
260 | GNUNET_NAMESTORE_cancel (set_qe); | ||
261 | set_qe = NULL; | ||
262 | } | ||
235 | if (NULL != add_qe_uri) | 263 | if (NULL != add_qe_uri) |
236 | { | 264 | { |
237 | GNUNET_NAMESTORE_cancel (add_qe_uri); | 265 | GNUNET_NAMESTORE_cancel (add_qe_uri); |
@@ -516,6 +544,8 @@ display_record_lookup (void *cls, | |||
516 | unsigned int rd_len, | 544 | unsigned int rd_len, |
517 | const struct GNUNET_GNSRECORD_Data *rd) | 545 | const struct GNUNET_GNSRECORD_Data *rd) |
518 | { | 546 | { |
547 | (void) cls; | ||
548 | (void) zone_key; | ||
519 | get_qe = NULL; | 549 | get_qe = NULL; |
520 | display_record (rname, | 550 | display_record (rname, |
521 | rd_len, | 551 | rd_len, |
@@ -694,14 +724,10 @@ get_existing_record (void *cls, | |||
694 | rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD; | 724 | rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD; |
695 | if (1 != is_public) | 725 | if (1 != is_public) |
696 | rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE; | 726 | rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE; |
727 | rde->expiration_time = etime; | ||
697 | if (GNUNET_YES == etime_is_rel) | 728 | if (GNUNET_YES == etime_is_rel) |
698 | { | ||
699 | rde->expiration_time = etime_rel.rel_value_us; | ||
700 | rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; | 729 | rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; |
701 | } | 730 | else if (GNUNET_NO != etime_is_rel) |
702 | else if (GNUNET_NO == etime_is_rel) | ||
703 | rde->expiration_time = etime_abs.abs_value_us; | ||
704 | else | ||
705 | rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us; | 731 | rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us; |
706 | GNUNET_assert (NULL != name); | 732 | GNUNET_assert (NULL != name); |
707 | add_qe = GNUNET_NAMESTORE_records_store (ns, | 733 | add_qe = GNUNET_NAMESTORE_records_store (ns, |
@@ -864,6 +890,85 @@ del_monitor (void *cls, | |||
864 | 890 | ||
865 | 891 | ||
866 | /** | 892 | /** |
893 | * Parse expiration time. | ||
894 | * | ||
895 | * @param expirationstring text to parse | ||
896 | * @param etime_is_rel[out] set to #GNUNET_YES if time is relative | ||
897 | * @param etime[out] set to expiration time (abs or rel) | ||
898 | * @return #GNUNET_OK on success | ||
899 | */ | ||
900 | static int | ||
901 | parse_expiration (const char *expirationstring, | ||
902 | int *etime_is_rel, | ||
903 | uint64_t *etime) | ||
904 | { | ||
905 | struct GNUNET_TIME_Relative etime_rel; | ||
906 | struct GNUNET_TIME_Absolute etime_abs; | ||
907 | |||
908 | if (0 == strcmp (expirationstring, | ||
909 | "never")) | ||
910 | { | ||
911 | *etime = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us; | ||
912 | *etime_is_rel = GNUNET_NO; | ||
913 | return GNUNET_OK; | ||
914 | } | ||
915 | if (GNUNET_OK == | ||
916 | GNUNET_STRINGS_fancy_time_to_relative (expirationstring, | ||
917 | &etime_rel)) | ||
918 | { | ||
919 | *etime_is_rel = GNUNET_YES; | ||
920 | *etime = etime_rel.rel_value_us; | ||
921 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
922 | "Storing record with relative expiration time of %s\n", | ||
923 | GNUNET_STRINGS_relative_time_to_string (etime_rel, | ||
924 | GNUNET_NO)); | ||
925 | return GNUNET_OK; | ||
926 | } | ||
927 | if (GNUNET_OK == | ||
928 | GNUNET_STRINGS_fancy_time_to_absolute (expirationstring, | ||
929 | &etime_abs)) | ||
930 | { | ||
931 | *etime_is_rel = GNUNET_NO; | ||
932 | *etime = etime_abs.abs_value_us; | ||
933 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
934 | "Storing record with absolute expiration time of %s\n", | ||
935 | GNUNET_STRINGS_absolute_time_to_string (etime_abs)); | ||
936 | return GNUNET_OK; | ||
937 | } | ||
938 | return GNUNET_SYSERR; | ||
939 | } | ||
940 | |||
941 | |||
942 | /** | ||
943 | * Function called when namestore is done with the replace | ||
944 | * operation. | ||
945 | * | ||
946 | * @param cls NULL | ||
947 | * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) | ||
948 | * #GNUNET_NO if content was already there or not found | ||
949 | * #GNUNET_YES (or other positive value) on success | ||
950 | * @param emsg NULL on success, otherwise an error message | ||
951 | */ | ||
952 | static void | ||
953 | replace_cont (void *cls, | ||
954 | int success, | ||
955 | const char *emsg) | ||
956 | { | ||
957 | (void) cls; | ||
958 | |||
959 | set_qe = NULL; | ||
960 | if (GNUNET_OK != success) | ||
961 | { | ||
962 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
963 | _("Failed to replace records: %s\n"), | ||
964 | emsg); | ||
965 | ret = 1; /* fail from 'main' */ | ||
966 | } | ||
967 | GNUNET_SCHEDULER_shutdown (); | ||
968 | } | ||
969 | |||
970 | |||
971 | /** | ||
867 | * Callback invoked from identity service with ego information. | 972 | * Callback invoked from identity service with ego information. |
868 | * An @a ego of NULL means the ego was not found. | 973 | * An @a ego of NULL means the ego was not found. |
869 | * | 974 | * |
@@ -895,7 +1000,7 @@ identity_cb (void *cls, | |||
895 | GNUNET_free_non_null (ego_name); | 1000 | GNUNET_free_non_null (ego_name); |
896 | ego_name = NULL; | 1001 | ego_name = NULL; |
897 | 1002 | ||
898 | if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey)) ) | 1003 | if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey))|(NULL != recordset) ) |
899 | { | 1004 | { |
900 | /* nothing more to be done */ | 1005 | /* nothing more to be done */ |
901 | fprintf (stderr, | 1006 | fprintf (stderr, |
@@ -904,8 +1009,7 @@ identity_cb (void *cls, | |||
904 | return; | 1009 | return; |
905 | } | 1010 | } |
906 | GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey, | 1011 | GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey, |
907 | &pub); | 1012 | &pub); |
908 | |||
909 | ns = GNUNET_NAMESTORE_connect (cfg); | 1013 | ns = GNUNET_NAMESTORE_connect (cfg); |
910 | if (NULL == ns) | 1014 | if (NULL == ns) |
911 | { | 1015 | { |
@@ -913,6 +1017,44 @@ identity_cb (void *cls, | |||
913 | _("Failed to connect to namestore\n")); | 1017 | _("Failed to connect to namestore\n")); |
914 | return; | 1018 | return; |
915 | } | 1019 | } |
1020 | |||
1021 | if (NULL != recordset) | ||
1022 | { | ||
1023 | /* replace entire record set */ | ||
1024 | unsigned int rd_count; | ||
1025 | struct GNUNET_GNSRECORD_Data *rd; | ||
1026 | |||
1027 | if (NULL == name) | ||
1028 | { | ||
1029 | fprintf (stderr, | ||
1030 | _("Missing option `%s' for operation `%s'\n"), | ||
1031 | "-n", _("replace")); | ||
1032 | GNUNET_SCHEDULER_shutdown (); | ||
1033 | ret = 1; | ||
1034 | return; | ||
1035 | } | ||
1036 | rd_count = 0; | ||
1037 | for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next) | ||
1038 | rd_count++; | ||
1039 | rd = GNUNET_new_array (rd_count, | ||
1040 | struct GNUNET_GNSRECORD_Data); | ||
1041 | rd_count = 0; | ||
1042 | for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next) | ||
1043 | { | ||
1044 | rd[rd_count] = e->record; | ||
1045 | rd_count++; | ||
1046 | } | ||
1047 | set_qe = GNUNET_NAMESTORE_records_store (ns, | ||
1048 | &zone_pkey, | ||
1049 | name, | ||
1050 | rd_count, | ||
1051 | rd, | ||
1052 | &replace_cont, | ||
1053 | NULL); | ||
1054 | GNUNET_free (rd); | ||
1055 | return; | ||
1056 | } | ||
1057 | |||
916 | if (add) | 1058 | if (add) |
917 | { | 1059 | { |
918 | if (NULL == name) | 1060 | if (NULL == name) |
@@ -976,32 +1118,10 @@ identity_cb (void *cls, | |||
976 | ret = 1; | 1118 | ret = 1; |
977 | return; | 1119 | return; |
978 | } | 1120 | } |
979 | if (0 == strcmp (expirationstring, | 1121 | if (GNUNET_OK != |
980 | "never")) | 1122 | parse_expiration (expirationstring, |
981 | { | 1123 | &etime_is_rel, |
982 | etime_abs = GNUNET_TIME_UNIT_FOREVER_ABS; | 1124 | &etime)) |
983 | etime_is_rel = GNUNET_NO; | ||
984 | } | ||
985 | else if (GNUNET_OK == | ||
986 | GNUNET_STRINGS_fancy_time_to_relative (expirationstring, | ||
987 | &etime_rel)) | ||
988 | { | ||
989 | etime_is_rel = GNUNET_YES; | ||
990 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
991 | "Storing record with relative expiration time of %s\n", | ||
992 | GNUNET_STRINGS_relative_time_to_string (etime_rel, | ||
993 | GNUNET_NO)); | ||
994 | } | ||
995 | else if (GNUNET_OK == | ||
996 | GNUNET_STRINGS_fancy_time_to_absolute (expirationstring, | ||
997 | &etime_abs)) | ||
998 | { | ||
999 | etime_is_rel = GNUNET_NO; | ||
1000 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1001 | "Storing record with absolute expiration time of %s\n", | ||
1002 | GNUNET_STRINGS_absolute_time_to_string (etime_abs)); | ||
1003 | } | ||
1004 | else | ||
1005 | { | 1125 | { |
1006 | fprintf (stderr, | 1126 | fprintf (stderr, |
1007 | _("Invalid time format `%s'\n"), | 1127 | _("Invalid time format `%s'\n"), |
@@ -1106,16 +1226,9 @@ identity_cb (void *cls, | |||
1106 | rd.data = &pkey; | 1226 | rd.data = &pkey; |
1107 | rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey); | 1227 | rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey); |
1108 | rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY; | 1228 | rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY; |
1109 | if (GNUNET_YES == etime_is_rel) | 1229 | rd.expiration_time = etime; |
1110 | { | 1230 | if (GNUNET_YES == etime_is_rel) |
1111 | rd.expiration_time = etime_rel.rel_value_us; | ||
1112 | rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; | 1231 | rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; |
1113 | } | ||
1114 | else if (GNUNET_NO == etime_is_rel) | ||
1115 | rd.expiration_time = etime_abs.abs_value_us; | ||
1116 | else | ||
1117 | rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us; | ||
1118 | |||
1119 | if (1 == is_shadow) | 1232 | if (1 == is_shadow) |
1120 | rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD; | 1233 | rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD; |
1121 | add_qe_uri = GNUNET_NAMESTORE_records_store (ns, | 1234 | add_qe_uri = GNUNET_NAMESTORE_records_store (ns, |
@@ -1247,6 +1360,161 @@ run (void *cls, | |||
1247 | 1360 | ||
1248 | 1361 | ||
1249 | /** | 1362 | /** |
1363 | * Command-line option parser function that allows the user to specify | ||
1364 | * a complete record as one argument for adding/removing. A pointer | ||
1365 | * to the head of the list of record sets must be passed as the "scls" | ||
1366 | * argument. | ||
1367 | * | ||
1368 | * @param ctx command line processor context | ||
1369 | * @param scls must be of type "struct GNUNET_FS_Uri **" | ||
1370 | * @param option name of the option (typically 'R') | ||
1371 | * @param value command line argument given; format is | ||
1372 | * "TTL TYPE FLAGS VALUE" where TTL is an expiration time (rel or abs), | ||
1373 | * TYPE is a DNS/GNS record type, FLAGS is either "n" for no flags or | ||
1374 | * a combination of 's' (shadow) and 'p' (public) and VALUE is the | ||
1375 | * value (in human-readable format) | ||
1376 | * @return #GNUNET_OK on success | ||
1377 | */ | ||
1378 | static int | ||
1379 | multirecord_process (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | ||
1380 | void *scls, | ||
1381 | const char *option, | ||
1382 | const char *value) | ||
1383 | { | ||
1384 | struct RecordSetEntry **head = scls; | ||
1385 | struct RecordSetEntry *r; | ||
1386 | struct GNUNET_GNSRECORD_Data record; | ||
1387 | char *cp; | ||
1388 | char *tok; | ||
1389 | int etime_is_rel; | ||
1390 | void *raw_data; | ||
1391 | |||
1392 | (void) ctx; | ||
1393 | (void) option; | ||
1394 | cp = GNUNET_strdup (value); | ||
1395 | tok = strtok (cp, " "); | ||
1396 | if (NULL == tok) | ||
1397 | { | ||
1398 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1399 | _("Empty record line argument is not allowed.\n")); | ||
1400 | GNUNET_free (cp); | ||
1401 | return GNUNET_SYSERR; | ||
1402 | } | ||
1403 | if (GNUNET_OK != | ||
1404 | parse_expiration (tok, | ||
1405 | &etime_is_rel, | ||
1406 | &record.expiration_time)) | ||
1407 | { | ||
1408 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1409 | _("Invalid expiration time `%s'\n"), | ||
1410 | tok); | ||
1411 | GNUNET_free (cp); | ||
1412 | return GNUNET_SYSERR; | ||
1413 | } | ||
1414 | tok = strtok (NULL, " "); | ||
1415 | if (NULL == tok) | ||
1416 | { | ||
1417 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1418 | _("Missing entries in record line `%s'.\n"), | ||
1419 | value); | ||
1420 | GNUNET_free (cp); | ||
1421 | return GNUNET_SYSERR; | ||
1422 | } | ||
1423 | record.record_type = GNUNET_GNSRECORD_typename_to_number (tok); | ||
1424 | if (UINT32_MAX == record.record_type) | ||
1425 | { | ||
1426 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1427 | _("Unknown record type `%s'\n"), | ||
1428 | tok); | ||
1429 | GNUNET_free (cp); | ||
1430 | return GNUNET_SYSERR; | ||
1431 | } | ||
1432 | tok = strtok (NULL, " "); | ||
1433 | if (NULL == tok) | ||
1434 | { | ||
1435 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1436 | _("Missing entries in record line `%s'.\n"), | ||
1437 | value); | ||
1438 | GNUNET_free (cp); | ||
1439 | return GNUNET_SYSERR; | ||
1440 | } | ||
1441 | record.flags = GNUNET_GNSRECORD_RF_NONE; | ||
1442 | if (etime_is_rel) | ||
1443 | record.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; | ||
1444 | if (NULL == strchr (tok, (unsigned char) 'p')) /* p = public */ | ||
1445 | record.flags |= GNUNET_GNSRECORD_RF_PRIVATE; | ||
1446 | if (NULL != strchr (tok, (unsigned char) 's')) | ||
1447 | record.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD; | ||
1448 | /* find beginning of record value */ | ||
1449 | tok = strchr (&value[tok - cp], (unsigned char) ' '); | ||
1450 | if (NULL == tok) | ||
1451 | { | ||
1452 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1453 | _("Missing entries in record line `%s'.\n"), | ||
1454 | value); | ||
1455 | GNUNET_free (cp); | ||
1456 | return GNUNET_SYSERR; | ||
1457 | } | ||
1458 | GNUNET_free (cp); | ||
1459 | tok++; /* skip space */ | ||
1460 | if (GNUNET_OK != | ||
1461 | GNUNET_GNSRECORD_string_to_value (record.record_type, | ||
1462 | tok, | ||
1463 | &raw_data, | ||
1464 | &record.data_size)) | ||
1465 | { | ||
1466 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1467 | _("Invalid record data for type %s: `%s'.\n"), | ||
1468 | GNUNET_GNSRECORD_number_to_typename (record.record_type), | ||
1469 | tok); | ||
1470 | return GNUNET_SYSERR; | ||
1471 | } | ||
1472 | |||
1473 | r = GNUNET_malloc (sizeof (struct RecordSetEntry) + record.data_size); | ||
1474 | r->next = *head; | ||
1475 | record.data = &r[1]; | ||
1476 | memcpy (&r[1], | ||
1477 | raw_data, | ||
1478 | record.data_size); | ||
1479 | GNUNET_free (raw_data); | ||
1480 | r->record = record; | ||
1481 | *head = r; | ||
1482 | return GNUNET_OK; | ||
1483 | } | ||
1484 | |||
1485 | |||
1486 | /** | ||
1487 | * Allow user to specify keywords. | ||
1488 | * | ||
1489 | * @param shortName short name of the option | ||
1490 | * @param name long name of the option | ||
1491 | * @param argumentHelp help text for the option argument | ||
1492 | * @param description long help text for the option | ||
1493 | * @param[out] topKeywords set to the desired value | ||
1494 | */ | ||
1495 | struct GNUNET_GETOPT_CommandLineOption | ||
1496 | multirecord_option (char shortName, | ||
1497 | const char *name, | ||
1498 | const char *argumentHelp, | ||
1499 | const char *description, | ||
1500 | struct RecordSetEntry **rs) | ||
1501 | { | ||
1502 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
1503 | .shortName = shortName, | ||
1504 | .name = name, | ||
1505 | .argumentHelp = argumentHelp, | ||
1506 | .description = description, | ||
1507 | .require_argument = 1, | ||
1508 | .processor = &multirecord_process, | ||
1509 | .scls = (void *) rs | ||
1510 | }; | ||
1511 | |||
1512 | return clo; | ||
1513 | } | ||
1514 | |||
1515 | |||
1516 | |||
1517 | /** | ||
1250 | * The main function for gnunet-namestore. | 1518 | * The main function for gnunet-namestore. |
1251 | * | 1519 | * |
1252 | * @param argc number of arguments from the command line | 1520 | * @param argc number of arguments from the command line |
@@ -1294,6 +1562,11 @@ main (int argc, | |||
1294 | "PKEY", | 1562 | "PKEY", |
1295 | gettext_noop ("determine our name for the given PKEY"), | 1563 | gettext_noop ("determine our name for the given PKEY"), |
1296 | &reverse_pkey), | 1564 | &reverse_pkey), |
1565 | multirecord_option ('R', | ||
1566 | "replace", | ||
1567 | "RECORDLINE", | ||
1568 | gettext_noop ("set record set to values given by (possibly multiple) RECORDLINES; can be specified multiple times"), | ||
1569 | &recordset), | ||
1297 | GNUNET_GETOPT_option_string ('t', | 1570 | GNUNET_GETOPT_option_string ('t', |
1298 | "type", | 1571 | "type", |
1299 | "TYPE", | 1572 | "TYPE", |