mmc.c revision f4eb241519f8d500ce6068a70d2389be39ac5189
1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public 4 * License v2 as published by the Free Software Foundation. 5 * 6 * This program is distributed in the hope that it will be useful, 7 * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 9 * General Public License for more details. 10 * 11 * You should have received a copy of the GNU General Public 12 * License along with this program; if not, write to the 13 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 14 * Boston, MA 021110-1307, USA. 15 * 16 * (This code is based on btrfs-progs/btrfs.c.) 17 */ 18 19#define _GNU_SOURCE 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23 24#include "mmc_cmds.h" 25 26#define MMC_VERSION "0.1" 27 28#define BASIC_HELP 0 29#define ADVANCED_HELP 1 30 31typedef int (*CommandFunction)(int argc, char **argv); 32 33struct Command { 34 CommandFunction func; /* function which implements the command */ 35 int nargs; /* if == 999, any number of arguments 36 if >= 0, number of arguments, 37 if < 0, _minimum_ number of arguments */ 38 char *verb; /* verb */ 39 char *help; /* help lines; from the 2nd line onward they 40 are automatically indented */ 41 char *adv_help; /* advanced help message; from the 2nd line 42 onward they are automatically indented */ 43 44 /* the following fields are run-time filled by the program */ 45 char **cmds; /* array of subcommands */ 46 int ncmds; /* number of subcommand */ 47}; 48 49static struct Command commands[] = { 50 /* 51 * avoid short commands different for the case only 52 */ 53 { do_read_extcsd, -1, 54 "extcsd read", "<device>\n" 55 "Print extcsd data from <device>.", 56 NULL 57 }, 58 { do_writeprotect_get, -1, 59 "writeprotect get", "<device>\n" 60 "Determine the eMMC writeprotect status of <device>.", 61 NULL 62 }, 63 { do_writeprotect_set, -1, 64 "writeprotect set", "<device>\n" 65 "Set the eMMC writeprotect status of <device>.\nThis sets the eMMC to be write-protected until next boot.", 66 NULL 67 }, 68 { do_disable_512B_emulation, -1, 69 "disable 512B emulation", "<device>\n" 70 "Set the eMMC data sector size to 4KB by disabling emulation on\n<device>.", 71 NULL 72 }, 73 { do_enh_area_set, -4, 74 "enh_area set", "<-y|-n> " "<start KiB> " "<length KiB> " "<device>\n" 75 "Enable the enhanced user area for the <device>.\nDry-run only unless -y is passed.\nNOTE! This is a one-time programmable (unreversible) change.", 76 NULL 77 }, 78 { do_write_reliability_set, -2, 79 "write_reliability set", "<-y|-n> " "<partition> " "<device>\n" 80 "Enable write reliability per partition for the <device>.\nDry-run only unless -y is passed.\nNOTE! This is a one-time programmable (unreversible) change.", 81 NULL 82 }, 83 { do_status_get, -1, 84 "status get", "<device>\n" 85 "Print the response to STATUS_SEND (CMD13).", 86 NULL 87 }, 88 { do_write_boot_en, -3, 89 "bootpart enable", "<boot_partition> " "<send_ack> " "<device>\n" 90 "Enable the boot partition for the <device>.\nTo receive acknowledgment of boot from the card set <send_ack>\nto 1, else set it to 0.", 91 NULL 92 }, 93 { do_write_bkops_en, -1, 94 "bkops enable", "<device>\n" 95 "Enable the eMMC BKOPS feature on <device>.\nNOTE! This is a one-time programmable (unreversible) change.", 96 NULL 97 }, 98 { do_hwreset_en, -1, 99 "hwreset enable", "<device>\n" 100 "Permanently enable the eMMC H/W Reset feature on <device>.\nNOTE! This is a one-time programmable (unreversible) change.", 101 NULL 102 }, 103 { do_hwreset_dis, -1, 104 "hwreset disable", "<device>\n" 105 "Permanently disable the eMMC H/W Reset feature on <device>.\nNOTE! This is a one-time programmable (unreversible) change.", 106 NULL 107 }, 108 { do_sanitize, -1, 109 "sanitize", "<device>\n" 110 "Send Sanitize command to the <device>.\nThis will delete the unmapped memory region of the device.", 111 NULL 112 }, 113 { do_rpmb_write_key, -1, 114 "rpmb write-key", "<rpmb device> <key file>\n" 115 "Program authentication key which is 32 bytes length and stored\n" 116 "in the specified file. Also you can specify '-' instead of\n" 117 "key file path to read the key from stdin.\n" 118 "NOTE! This is a one-time programmable (unreversible) change.\n" 119 "Example:\n" 120 " $ echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | \\\n" 121 " mmc rpmb write-key /dev/mmcblk0rpmb -", 122 NULL 123 }, 124 { do_rpmb_read_counter, -1, 125 "rpmb read-counter", "<rpmb device>\n" 126 "Counter value for the <rpmb device> will be read to stdout.", 127 NULL 128 }, 129 { do_rpmb_read_block, -1, 130 "rpmb read-block", "<rpmb device> <address> <blocks count> <output file> [key file]\n" 131 "Blocks of 256 bytes will be read from <rpmb device> to output\n" 132 "file or stdout if '-' is specified. If key is specified - read\n" 133 "data will be verified. Instead of regular path you can specify\n" 134 "'-' to read key from stdin.\n" 135 "Example:\n" 136 " $ echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH | \\\n" 137 " mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block -\n" 138 "or read two blocks without verification\n" 139 " $ mmc rpmb read-block /dev/mmcblk0rpmb 0x02 2 /tmp/block", 140 NULL 141 }, 142 { do_rpmb_write_block, -1, 143 "rpmb write-block", "<rpmb device> <address> <256 byte data file> <key file>\n" 144 "Block of 256 bytes will be written from data file to\n" 145 "<rpmb device>. Also you can specify '-' instead of key\n" 146 "file path or data file to read the data from stdin.\n" 147 "Example:\n" 148 " $ (awk 'BEGIN {while (c++<256) printf \"a\"}' | \\\n" 149 " echo -n AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH) | \\\n" 150 " mmc rpmb write-block /dev/mmcblk0rpmb 0x02 - -", 151 NULL 152 }, 153 { 0, 0, 0, 0 } 154}; 155 156static char *get_prgname(char *programname) 157{ 158 char *np; 159 np = strrchr(programname,'/'); 160 if(!np) 161 np = programname; 162 else 163 np++; 164 165 return np; 166} 167 168static void print_help(char *programname, struct Command *cmd, int helptype) 169{ 170 char *pc; 171 172 printf("\t%s %s ", programname, cmd->verb ); 173 174 if (helptype == ADVANCED_HELP && cmd->adv_help) 175 for(pc = cmd->adv_help; *pc; pc++){ 176 putchar(*pc); 177 if(*pc == '\n') 178 printf("\t\t"); 179 } 180 else 181 for(pc = cmd->help; *pc; pc++){ 182 putchar(*pc); 183 if(*pc == '\n') 184 printf("\t\t"); 185 } 186 187 putchar('\n'); 188} 189 190static void help(char *np) 191{ 192 struct Command *cp; 193 194 printf("Usage:\n"); 195 for( cp = commands; cp->verb; cp++ ) 196 print_help(np, cp, BASIC_HELP); 197 198 printf("\n\t%s help|--help|-h\n\t\tShow the help.\n",np); 199 printf("\n\t%s <cmd> --help\n\t\tShow detailed help for a command or subset of commands.\n",np); 200 printf("\n%s\n", MMC_VERSION); 201} 202 203static int split_command(char *cmd, char ***commands) 204{ 205 int c, l; 206 char *p, *s; 207 208 for( *commands = 0, l = c = 0, p = s = cmd ; ; p++, l++ ){ 209 if ( *p && *p != ' ' ) 210 continue; 211 212 /* c + 2 so that we have room for the null */ 213 (*commands) = realloc( (*commands), sizeof(char *)*(c + 2)); 214 (*commands)[c] = strndup(s, l); 215 c++; 216 l = 0; 217 s = p+1; 218 if( !*p ) break; 219 } 220 221 (*commands)[c] = 0; 222 return c; 223} 224 225/* 226 This function checks if the passed command is ambiguous 227*/ 228static int check_ambiguity(struct Command *cmd, char **argv){ 229 int i; 230 struct Command *cp; 231 /* check for ambiguity */ 232 for( i = 0 ; i < cmd->ncmds ; i++ ){ 233 int match; 234 for( match = 0, cp = commands; cp->verb; cp++ ){ 235 int j, skip; 236 char *s1, *s2; 237 238 if( cp->ncmds < i ) 239 continue; 240 241 for( skip = 0, j = 0 ; j < i ; j++ ) 242 if( strcmp(cmd->cmds[j], cp->cmds[j])){ 243 skip=1; 244 break; 245 } 246 if(skip) 247 continue; 248 249 if( !strcmp(cmd->cmds[i], cp->cmds[i])) 250 continue; 251 for(s2 = cp->cmds[i], s1 = argv[i+1]; 252 *s1 == *s2 && *s1; s1++, s2++ ) ; 253 if( !*s1 ) 254 match++; 255 } 256 if(match){ 257 int j; 258 fprintf(stderr, "ERROR: in command '"); 259 for( j = 0 ; j <= i ; j++ ) 260 fprintf(stderr, "%s%s",j?" ":"", argv[j+1]); 261 fprintf(stderr, "', '%s' is ambiguous\n",argv[j]); 262 return -2; 263 } 264 } 265 return 0; 266} 267 268/* 269 * This function, compacts the program name and the command in the first 270 * element of the '*av' array 271 */ 272static int prepare_args(int *ac, char ***av, char *prgname, struct Command *cmd ){ 273 274 char **ret; 275 int i; 276 char *newname; 277 278 ret = (char **)malloc(sizeof(char*)*(*ac+1)); 279 newname = (char*)malloc(strlen(prgname)+strlen(cmd->verb)+2); 280 if( !ret || !newname ){ 281 free(ret); 282 free(newname); 283 return -1; 284 } 285 286 ret[0] = newname; 287 for(i=0; i < *ac ; i++ ) 288 ret[i+1] = (*av)[i]; 289 290 strcpy(newname, prgname); 291 strcat(newname, " "); 292 strcat(newname, cmd->verb); 293 294 (*ac)++; 295 *av = ret; 296 297 return 0; 298 299} 300 301/* 302 This function performs the following jobs: 303 - show the help if '--help' or 'help' or '-h' are passed 304 - verify that a command is not ambiguous, otherwise show which 305 part of the command is ambiguous 306 - if after a (even partial) command there is '--help' show detailed help 307 for all the matching commands 308 - if the command doesn't match show an error 309 - finally, if a command matches, they return which command matched and 310 the arguments 311 312 The function return 0 in case of help is requested; <0 in case 313 of uncorrect command; >0 in case of matching commands 314 argc, argv are the arg-counter and arg-vector (input) 315 *nargs_ is the number of the arguments after the command (output) 316 **cmd_ is the invoked command (output) 317 ***args_ are the arguments after the command 318 319*/ 320static int parse_args(int argc, char **argv, 321 CommandFunction *func_, 322 int *nargs_, char **cmd_, char ***args_ ) 323{ 324 struct Command *cp; 325 struct Command *matchcmd=0; 326 char *prgname = get_prgname(argv[0]); 327 int i=0, helprequested=0; 328 329 if( argc < 2 || !strcmp(argv[1], "help") || 330 !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){ 331 help(prgname); 332 return 0; 333 } 334 335 for( cp = commands; cp->verb; cp++ ) 336 if( !cp->ncmds) 337 cp->ncmds = split_command(cp->verb, &(cp->cmds)); 338 339 for( cp = commands; cp->verb; cp++ ){ 340 int match; 341 342 if( argc-1 < cp->ncmds ) 343 continue; 344 for( match = 1, i = 0 ; i < cp->ncmds ; i++ ){ 345 char *s1, *s2; 346 s1 = cp->cmds[i]; 347 s2 = argv[i+1]; 348 349 for(s2 = cp->cmds[i], s1 = argv[i+1]; 350 *s1 == *s2 && *s1; 351 s1++, s2++ ) ; 352 if( *s1 ){ 353 match=0; 354 break; 355 } 356 } 357 358 /* If you understand why this code works ... 359 you are a genious !! */ 360 if(argc>i+1 && !strcmp(argv[i+1],"--help")){ 361 if(!helprequested) 362 printf("Usage:\n"); 363 print_help(prgname, cp, ADVANCED_HELP); 364 helprequested=1; 365 continue; 366 } 367 368 if(!match) 369 continue; 370 371 matchcmd = cp; 372 *nargs_ = argc-matchcmd->ncmds-1; 373 *cmd_ = matchcmd->verb; 374 *args_ = argv+matchcmd->ncmds+1; 375 *func_ = cp->func; 376 377 break; 378 } 379 380 if(helprequested){ 381 printf("\n%s\n", MMC_VERSION); 382 return 0; 383 } 384 385 if(!matchcmd){ 386 fprintf( stderr, "ERROR: unknown command '%s'\n",argv[1]); 387 help(prgname); 388 return -1; 389 } 390 391 if(check_ambiguity(matchcmd, argv)) 392 return -2; 393 394 /* check the number of argument */ 395 if (matchcmd->nargs < 0 && matchcmd->nargs < -*nargs_ ){ 396 fprintf(stderr, "ERROR: '%s' requires minimum %d arg(s)\n", 397 matchcmd->verb, -matchcmd->nargs); 398 return -2; 399 } 400 if(matchcmd->nargs >= 0 && matchcmd->nargs != *nargs_ && matchcmd->nargs != 999){ 401 fprintf(stderr, "ERROR: '%s' requires %d arg(s)\n", 402 matchcmd->verb, matchcmd->nargs); 403 return -2; 404 } 405 406 if (prepare_args( nargs_, args_, prgname, matchcmd )){ 407 fprintf(stderr, "ERROR: not enough memory\\n"); 408 return -20; 409 } 410 411 412 return 1; 413} 414int main(int ac, char **av ) 415{ 416 char *cmd=0, **args=0; 417 int nargs=0, r; 418 CommandFunction func=0; 419 420 r = parse_args(ac, av, &func, &nargs, &cmd, &args); 421 if( r <= 0 ){ 422 /* error or no command to parse*/ 423 exit(-r); 424 } 425 426 exit(func(nargs, args)); 427} 428 429