diceware.c (2212B)
1 #include "config.h" 2 #if HAVE_ERR 3 #include <err.h> 4 #endif 5 #include <stdint.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 10 #include "rng.h" 11 #include "diceware.h" 12 13 /* Enough for ten six-character words and their seperators */ 14 static char buf[70] = {0}; 15 static size_t buflen = 0; 16 17 int 18 main(int argc, char **argv) 19 { 20 int num; 21 const char *errstr; 22 23 #if HAVE_PLEDGE 24 if (pledge("stdio", NULL) == -1) 25 err(1, "pledge"); 26 #endif 27 28 if (argc > 2) { 29 warnx("too many arguments: %s", argv[2]); 30 } else if (argc == 2) { 31 if (argv[1][0] == '-' && argv[1][1] == 'h') 32 goto usage; 33 num = strtonum(argv[1], 1, 10, &errstr); 34 if (errstr != NULL) 35 errx(1, "number of words is %s: %s", errstr, argv[1]); 36 37 generate(num); 38 } else { 39 interactive(); 40 } 41 42 return 0; 43 usage: 44 fprintf(stderr, "usage: %s [num-words]\n", getprogname()); 45 46 return 1; 47 } 48 49 void 50 generate(int num_words) 51 { 52 static char roll[6] = {0}; 53 const char *word; 54 uint32_t num, rem; 55 56 for (int i = 0; i < num_words; i++) { 57 num = rng_uniform(NUM_WORDS); 58 word = words[num]; 59 60 for (size_t i = 0; i < 5; i++) { 61 rem = num % 6; 62 roll[4 - i] = rem + '1'; 63 num /= 6; 64 } 65 66 fprintf(stderr, "%s %s\n", roll, word); 67 buflen = strlcat(buf, word, sizeof(buf)); 68 buf[buflen] = ' '; 69 } 70 buf[buflen] = '\n'; 71 72 (void)fwrite(buf, 1, buflen + 1, stdout); 73 } 74 75 void 76 interactive(void) 77 { 78 static const uint32_t exps[5] = {1296, 216, 36, 6, 1}; 79 uint32_t num; 80 char *line = NULL; 81 size_t size = 0; 82 ssize_t len; 83 size_t i = 0; 84 85 do { 86 fprintf(stderr, "Roll %2zu: ", i + 1); 87 len = getline(&line, &size, stdin); 88 if (len == -1) { 89 if (feof(stdin)) 90 break; 91 else if (ferror(stdin)) 92 err(1, "getline"); 93 } else if (len != 6) { 94 warnx("roll is not 5 numbers long, skipping"); 95 continue; 96 } 97 line[len] = '\0'; 98 99 num = 0; 100 for (size_t j = 0; j < 5; j++) { 101 if (line[j] < '1' || line[j] > '6') { 102 warnx("invalid roll, skipping: %s", line); 103 continue; 104 } 105 num += (line[j] - '1') * exps[j]; 106 } 107 108 buflen = strlcat(buf, words[num], sizeof(buf)); 109 buf[buflen] = ' '; 110 i++; 111 } while (i < 10); 112 fputc('\n', stderr); 113 free(line); 114 115 buf[buflen] = '\n'; 116 fputs("Your password is: ", stderr); 117 (void)fwrite(buf, 1, buflen + 1, stdout); 118 }