From 9c9317d11b88477007ad5ef4359db39daec6e4c0 Mon Sep 17 00:00:00 2001 From: Peter Marschall Date: Thu, 2 Jun 2011 13:21:25 +0200 Subject: [PATCH] opensc-explorer: centralize usage * extend cmds struct by a new element args for a description of the arguments * use args in help texts * new function usage() for centralited dispaly of usage info * harmonize argument strings for usage / help texts * re-sort cmd list shown in help texts * add function "help" to cwallow asking for for help * space-police Signed-off-by: Peter Marschall --- src/tools/opensc-explorer.c | 355 ++++++++++++++++++++---------------- 1 file changed, 199 insertions(+), 156 deletions(-) diff --git a/src/tools/opensc-explorer.c b/src/tools/opensc-explorer.c index 3eca6ca2..0aab1d87 100644 --- a/src/tools/opensc-explorer.c +++ b/src/tools/opensc-explorer.c @@ -73,12 +73,129 @@ static const char *option_help[] = { static size_t hex2binary(u8 *out, size_t outlen, const char *in); +/* declare functions called by user commands */ +static int do_ls(int argc, char **argv); +static int do_cd(int argc, char **argv); +static int do_cat(int argc, char **argv); +static int do_info(int argc, char **argv); +static int do_create(int argc, char **argv); +static int do_mkdir(int argc, char **argv); +static int do_delete(int argc, char **argv); +static int do_verify(int argc, char **argv); +static int do_change(int argc, char **argv); +static int do_unblock(int argc, char **argv); +static int do_get(int argc, char **argv); +static int do_update_binary(int argc, char **argv); +static int do_update_record(int argc, char **argv); +static int do_put(int argc, char **argv); +static int do_debug(int argc, char **argv); +static int do_erase(int argc, char **argv); +static int do_random(int argc, char **argv); +static int do_get_data(int argc, char **argv); +static int do_put_data(int argc, char **argv); +static int do_apdu(int argc, char **argv); +static int do_asn1(int argc, char **argv); +static int do_help(int argc, char **argv); +static int do_quit(int argc, char **argv); + + struct command { - const char * name; int (*func)(int, char **); + const char * name; + const char * args; const char * help; }; +static struct command cmds[] = { + { do_ls, + "ls", "", + "list all files in the current DF" }, + { do_cd, + "cd", "{.. | | aid:}", + "change to another DF" }, + { do_cat, + "cat", "[ | sfi:]" + , "print the contents of an EF" }, + { do_info, + "info", "[]", + "display attributes of card file" }, + { do_create, + "create", " ", + "create a new EF" }, + { do_mkdir, + "mkdir", " ", + "create a new DF" }, + { do_delete, + "delete", "", + "remove an EF/DF" }, + { do_delete, + "rm", "", + "remove an EF/DF" }, + { do_verify, + "verify", " []", + "present a PIN or key to the card" }, + { do_change, + "change", "CHV [[] ]", + "change a PIN" }, + { do_unblock, + "unblock", "CHV [ []]", + "unblock a PIN" }, + { do_put, + "put", " []", + "copy a local file to the card" }, + { do_get, + "get", " []", + "copy an EF to a local file" }, + { do_get_data, + "do_get", " []", + "get a data object" }, + { do_put_data, + "do_put", " ", + "put a data object" }, + { do_erase, + "erase", "", + "erase card" }, + { do_random, + "random", "", + "obtain random bytes from card" }, + { do_update_record, + "update_record", " ", + "update record" }, + { do_update_binary, + "update_binary", " ", + "update binary" }, + { do_apdu, + "apdu", "", + "send a custom apdu command" }, + { do_asn1, + "asn1", "[]", + "decode an asn1 file" }, + { do_debug, + "debug", "[]", + "get/set the debug level" }, + { do_quit, + "quit", "", + "quit this program" }, + { do_quit, + "exit", "", + "quit this program" }, + { do_help, + "help", "", + "show this help" }, + { NULL, NULL, NULL, NULL } +}; + + +static int usage(int (*func)(int, char **)) +{ + struct command *cmd; + + for (cmd = cmds; cmd->func; cmd++) + if (cmd->func == func) + printf("Usage: %s %s\n", cmd->name, cmd->args); + return -1; +} + static void die(int ret) { if (current_file != NULL) @@ -142,7 +259,7 @@ static int arg_to_path(const char *arg, sc_path_t *path, int is_id) /* file id */ unsigned int buf[2]; u8 cbuf[2]; - + if (strlen(arg) != 4) { printf("Wrong ID length.\n"); return -1; @@ -178,7 +295,7 @@ static int arg_to_path(const char *arg, sc_path_t *path, int is_id) } } - return 0; + return 0; } static void print_file(const sc_file_t *file) @@ -215,7 +332,8 @@ static int do_ls(int argc, char **argv) int r, count; if (argc) - goto usage; + return usage(do_ls); + r = sc_list_files(card, buf, sizeof(buf)); if (r < 0) { check_ret(r, SC_AC_OP_LIST_FILES, "unable to receive file listing", current_file); @@ -236,7 +354,7 @@ static int do_ls(int argc, char **argv) die(1); } } - + r = sc_select_file(card, &path, &file); if (r) { printf(" %02X%02X unable to select file, %s\n", cur[0], cur[1], sc_strerror(r)); @@ -250,9 +368,6 @@ static int do_ls(int argc, char **argv) select_current_path_or_die(); } return 0; -usage: - puts("Usage: ls"); - return -1; } static int do_cd(int argc, char **argv) @@ -262,7 +377,8 @@ static int do_cd(int argc, char **argv) int r; if (argc != 1) - goto usage; + return usage(do_cd); + if (strcmp(argv[0], "..") == 0) { path = current_path; if (path.len < 4) { @@ -289,7 +405,7 @@ static int do_cd(int argc, char **argv) return 0; } if (arg_to_path(argv[0], &path, 0) != 0) - goto usage; + return usage(do_cd); r = sc_select_file(card, &path, &file); if (r) { @@ -308,9 +424,6 @@ static int do_cd(int argc, char **argv) current_file = file; return 0; -usage: - puts("Usage: cd |aid:"); - return -1; } static int read_and_util_print_binary_file(sc_file_t *file) @@ -319,7 +432,7 @@ static int read_and_util_print_binary_file(sc_file_t *file) u8 buf[128]; size_t count; int r; - + count = file->size; while (count) { int c = count > sizeof(buf) ? sizeof(buf) : count; @@ -370,7 +483,8 @@ static int do_cat(int argc, char **argv) int sfi = 0; if (argc > 1) - goto usage; + return usage(do_cat); + if (!argc) { path = current_path; file = current_file; @@ -391,11 +505,12 @@ static int do_cat(int argc, char **argv) sfi = atoi(sfi_n); if ((sfi < 1) || (sfi > 30)) { printf("Invalid SFI: %s\n", sfi_n); - goto usage; + return usage(do_cat); } } else { if (arg_to_path(argv[0], &path, 0) != 0) - goto usage; + return usage(do_cat); + r = sc_select_file(card, &path, &file); if (r) { check_ret(r, SC_AC_OP_SELECT, "unable to select file", @@ -413,22 +528,16 @@ static int do_cat(int argc, char **argv) read_and_util_print_binary_file(file); else read_and_print_record_file(file, sfi); - - err = 0; + err = 0; err: if (not_current) { - if (file != NULL) { + if (file != NULL) sc_file_free(file); - } select_current_path_or_die(); } return -err; -usage: - puts("Usage: cat [file_id] or"); - puts(" cat sfi:"); - return -1; } static int do_info(int argc, char **argv) @@ -446,14 +555,15 @@ static int do_info(int argc, char **argv) not_current = 0; } else if (argc == 1) { if (arg_to_path(argv[0], &path, 0) != 0) - goto usage; + return usage(do_info); + r = sc_select_file(card, &path, &file); if (r) { printf("unable to select file: %s\n", sc_strerror(r)); return -1; } } else - goto usage; + return usage(do_info); switch (file->type) { case SC_FILE_TYPE_WORKING_EF: @@ -558,16 +668,12 @@ static int do_info(int argc, char **argv) select_current_path_or_die(); } return 0; - -usage: - puts("Usage: info [file_id]"); - return -1; } static int create_file(sc_file_t *file) { int r; - + r = sc_create_file(card, file); if (r) { check_ret(r, SC_AC_OP_CREATE, "CREATE FILE failed", current_file); @@ -587,12 +693,12 @@ static int do_create(int argc, char **argv) int r, op; if (argc != 2) - goto usage; + return usage(do_create); if (arg_to_path(argv[0], &path, 1) != 0) - goto usage; + return usage(do_create); /* %z isn't supported everywhere */ if (sscanf(argv[1], "%u", &size) != 1) - goto usage; + return usage(do_create); file = sc_file_new(); file->id = (path.value[0] << 8) | path.value[1]; file->type = SC_FILE_TYPE_WORKING_EF; @@ -601,13 +707,10 @@ static int do_create(int argc, char **argv) file->status = SC_FILE_STATUS_ACTIVATED; for (op = 0; op < SC_MAX_AC_OPS; op++) sc_file_add_acl_entry(file, op, SC_AC_NONE, 0); - + r = create_file(file); sc_file_free(file); return r; - usage: - printf("Usage: create \n"); - return -1; } static int do_mkdir(int argc, char **argv) @@ -618,11 +721,11 @@ static int do_mkdir(int argc, char **argv) int r, op; if (argc != 2) - goto usage; + return usage(do_mkdir); if (arg_to_path(argv[0], &path, 1) != 0) - goto usage; + return usage(do_mkdir); if (sscanf(argv[1], "%u", &size) != 1) - goto usage; + return usage(do_mkdir); file = sc_file_new(); file->id = (path.value[0] << 8) | path.value[1]; file->type = SC_FILE_TYPE_DF; @@ -634,9 +737,6 @@ static int do_mkdir(int argc, char **argv) r = create_file(file); sc_file_free(file); return r; - usage: - printf("Usage: mkdir \n"); - return -1; } static int do_delete(int argc, char **argv) @@ -645,11 +745,11 @@ static int do_delete(int argc, char **argv) int r; if (argc != 1) - goto usage; + return usage(do_delete); if (arg_to_path(argv[0], &path, 1) != 0) - goto usage; + return usage(do_delete); if (path.len != 2) - goto usage; + return usage(do_delete); path.type = SC_PATH_TYPE_FILE_ID; r = sc_delete_file(card, &path); if (r) { @@ -657,9 +757,6 @@ static int do_delete(int argc, char **argv) return -1; } return 0; -usage: - printf("Usage: delete \n"); - return -1; } static int do_verify(int argc, char **argv) @@ -739,7 +836,7 @@ static int do_verify(int argc, char **argv) printf("Code correct.\n"); return 0; usage: - printf("Usage: verify []\n"); + printf("Usage: verify []\n"); printf("Possible values of :\n"); for (i = 0; typeNames[i].name; i++) printf("\t%s\n", typeNames[i].name); @@ -757,7 +854,7 @@ static int do_change(int argc, char **argv) const char *s; size_t oldpinlen = sizeof(oldpin), i; size_t newpinlen = sizeof(newpin); - + if (argc < 1 || argc > 3) goto usage; if (strncasecmp(argv[0], "CHV", 3)) { @@ -838,7 +935,7 @@ static int do_unblock(int argc, char **argv) const char *s; size_t puklen = sizeof(puk_buf), i; size_t newpinlen = sizeof(newpin_buf); - + if (argc < 1 || argc > 3) goto usage; if (strncasecmp(argv[0], "CHV", 3)) { @@ -901,7 +998,7 @@ static int do_unblock(int argc, char **argv) printf("PIN unblocked.\n"); return 0; usage: - printf("Usage: unblock CHV [] []\n"); + printf("Usage: unblock CHV [ []]\n"); printf("PUK and PIN values can be hexadecimal, ASCII, empty (\"\") or absent\n"); printf("Examples:\n"); printf("\tUnblock PIN and set a new value: unblock CHV2 00:00:00:00:00:00 \"foobar\"\n"); @@ -924,11 +1021,11 @@ static int do_get(int argc, char **argv) sc_file_t *file = NULL; char fbuf[256], *filename; FILE *outf = NULL; - + if (argc < 1 || argc > 2) - goto usage; + return usage(do_get); if (arg_to_path(argv[0], &path, 0) != 0) - goto usage; + return usage(do_get); if (argc == 2) filename = argv[1]; else { @@ -983,7 +1080,7 @@ static int do_get(int argc, char **argv) printf("Total of %d bytes read from %s and saved to %s.\n", idx, argv[0], filename); } - + err = 0; err: if (file) @@ -992,9 +1089,6 @@ err: fclose(outf); select_current_path_or_die(); return -err; -usage: - printf("Usage: get [output file]\n"); - return -1; } static size_t hex2binary(u8 *out, size_t outlen, const char *in) @@ -1040,11 +1134,11 @@ static int do_update_binary(int argc, char **argv) sc_path_t path; sc_file_t *file; char *in_str; - + if (argc < 2 || argc > 3) - goto usage; + return usage(do_update_binary); if (arg_to_path(argv[0], &path, 0) != 0) - goto usage; + return usage(do_update_binary); offs = strtol(argv[1],NULL,10); in_str = argv[2]; @@ -1059,7 +1153,7 @@ static int do_update_binary(int argc, char **argv) return -1; } } - + r = sc_select_file(card, &path, &file); if (r) { check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file); @@ -1070,7 +1164,7 @@ static int do_update_binary(int argc, char **argv) printf("EF structure should be SC_FILE_EF_TRANSPARENT\n"); goto err; } - + r = sc_update_binary(card, offs, buf, in_len, 0); if (r < 0) { printf("Cannot update %04X; return %i\n", file->id, r); @@ -1081,14 +1175,10 @@ static int do_update_binary(int argc, char **argv) r, file->id, offs); err = 0; - err: sc_file_free(file); select_current_path_or_die(); return -err; -usage: - printf("Usage: update offs | <'\"' enclosed string>\n"); - return -1; } static int do_update_record(int argc, char **argv) @@ -1099,11 +1189,11 @@ static int do_update_record(int argc, char **argv) sc_path_t path; sc_file_t *file; char *in_str; - + if (argc < 3 || argc > 4) - goto usage; + return usage(do_update_record); if (arg_to_path(argv[0], &path, 0) != 0) - goto usage; + return usage(do_update_record); rec = strtol(argv[1],NULL,10); offs = strtol(argv[2],NULL,10); @@ -1123,7 +1213,7 @@ static int do_update_record(int argc, char **argv) printf("Invalid record number %i\n", rec); goto err; } - + r = sc_read_record(card, rec, buf, sizeof(buf), SC_RECORD_BY_REC_NR); if (r<0) { printf("Cannot read record %i; return %i\n", rec, r); @@ -1144,15 +1234,12 @@ static int do_update_record(int argc, char **argv) printf("Total of %d bytes written to record %i at %i offset.\n", i, rec, offs); - err = 0; + err = 0; err: sc_file_free(file); select_current_path_or_die(); return -err; -usage: - printf("Usage: update_record rec_nr rec_offs \n"); - return -1; } @@ -1168,9 +1255,9 @@ static int do_put(int argc, char **argv) FILE *outf = NULL; if (argc < 1 || argc > 2) - goto usage; + return usage(do_put); if (arg_to_path(argv[0], &path, 0) != 0) - goto usage; + return usage(do_put); if (argc == 2) filename = argv[1]; else { @@ -1213,18 +1300,13 @@ static int do_put(int argc, char **argv) printf("Total of %d bytes written.\n", idx); err = 0; - err: - if (file) sc_file_free(file); if (outf) fclose(outf); select_current_path_or_die(); return -err; -usage: - printf("Usage: put [input file]\n"); - return -1; } static int do_debug(int argc, char **argv) @@ -1246,13 +1328,12 @@ static int do_debug(int argc, char **argv) } -static int -do_erase(int argc, char **argv) +static int do_erase(int argc, char **argv) { int r; if (argc != 0) - goto usage; + return usage(do_erase); r = sc_card_ctl(card, SC_CARDCTL_ERASE_CARD, NULL); if (r) { @@ -1260,20 +1341,15 @@ do_erase(int argc, char **argv) return -1; } return 0; - -usage: - printf("Usage: erase\n"); - return -1; } -static int -do_random(int argc, char **argv) +static int do_random(int argc, char **argv) { unsigned char buffer[128]; int r, count; if (argc != 1) - goto usage; + return usage(do_random); count = atoi(argv[0]); if (count < 0 || count > 128) { @@ -1289,10 +1365,6 @@ do_random(int argc, char **argv) util_hex_dump_asc(stdout, buffer, count, 0); return 0; - -usage: - printf("Usage: random count\n"); - return -1; } static int do_get_data(int argc, char **argv) @@ -1303,7 +1375,7 @@ static int do_get_data(int argc, char **argv) int r; if (argc != 1 && argc != 2) - goto usage; + return usage(do_get_data); tag = strtoul(argv[0], NULL, 16); r = sc_get_data(card, tag, buffer, sizeof(buffer)); @@ -1327,17 +1399,11 @@ static int do_get_data(int argc, char **argv) } return 0; - -usage: printf("Usage: do_get hex_tag [dest_file]\n"); - return -1; } static int do_put_data(int argc, char **argv) { - printf("Usage: do_put hex_tag source_file\n" - "or: do_put hex_tag aa:bb:cc\n" - "or: do_put hex_tag \"foobar...\"\n"); - return -1; + return usage(do_put_data); } static int do_apdu(int argc, char **argv) @@ -1347,10 +1413,8 @@ static int do_apdu(int argc, char **argv) u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; size_t len, len0, r, ii; - if (argc < 1) { - puts("Usage: apdu [apdu:hex:codes:...]"); - return -1; - } + if (argc < 1) + return usage(do_apdu); for (ii = 0, len = 0; ii < (unsigned) argc; ii++) { len0 = strlen(argv[ii]); @@ -1393,10 +1457,8 @@ static int do_asn1(int argc, char **argv) size_t len; unsigned char *buf = NULL; - if (argc > 1) { - puts("Usage: asn1 [file_id]"); - return -1; - } + if (argc > 1) + return usage(do_asn1); /* select file */ if (argc) { @@ -1454,49 +1516,30 @@ err: return -err; } +static int do_help(int argc, char **argv) +{ + struct command *cmd; + + if (argc) + return usage(do_help); + + printf("Supported commands:\n"); + for (cmd = cmds; cmd->name; cmd++) { + int len = strlen(cmd->name) + strlen(cmd->args); + printf(" %s %s%*s %s\n", + cmd->name, cmd->args, + (len > 40) ? 0 : (40 - len), "", + cmd->help); + } + return 0; +} + static int do_quit(int argc, char **argv) { die(0); return 0; } -static struct command cmds[] = { - { "ls", do_ls, "list all files in the current DF" }, - { "cd", do_cd, "change to another DF" }, - { "cat", do_cat, "print the contents of an EF" }, - { "info", do_info, "display attributes of card file" }, - { "create", do_create, "create a new EF" }, - { "delete", do_delete, "remove an EF/DF" }, - { "rm", do_delete, "remove an EF/DF" }, - { "verify", do_verify, "present a PIN or key to the card" }, - { "change", do_change, "change a PIN" }, - { "unblock", do_unblock, "unblock a PIN" }, - { "put", do_put, "copy a local file to the card" }, - { "get", do_get, "copy an EF to a local file" }, - { "do_get", do_get_data, "get a data object" }, - { "do_put", do_put_data, "put a data object" }, - { "mkdir", do_mkdir, "create a DF" }, - { "erase", do_erase, "erase card" }, - { "random", do_random, "obtain N random bytes from card" }, - { "quit", do_quit, "quit this program" }, - { "exit", do_quit, "quit this program" }, - { "update_record", do_update_record, "update record" }, - { "update_binary", do_update_binary, "update binary" }, - { "debug", do_debug, "set the debug level" }, - { "apdu", do_apdu, "send a custom apdu command" }, - { "asn1", do_asn1, "decode an asn1 file" }, - { NULL, NULL, NULL } -}; - -static void usage(void) -{ - struct command *cmd; - - printf("Supported commands:\n"); - for (cmd = cmds; cmd->name; cmd++) - printf(" %-16s %s\n", cmd->name, cmd->help); -} - static int parse_line(char *in, char **argv, int maxargc) { int argc; @@ -1644,7 +1687,7 @@ int main(int argc, char * const argv[]) return 1; } } - + r = sc_card_ctl(card, SC_CARDCTL_LIFECYCLE_SET, &lcycle); if (r && r != SC_ERROR_NOT_SUPPORTED) printf("unable to change lifecycle: %s\n", sc_strerror(r)); @@ -1672,13 +1715,13 @@ int main(int argc, char * const argv[]) cargv[r] = ""; cmd = ambiguous_match(cmds, cargv[0]); if (cmd == NULL) { - usage(); + do_help(0, NULL); } else { cmd->func(cargc-1, cargv+1); } } end: die(err); - + return 0; /* not reached */ }