11f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <hardware/bluetooth.h> 21f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <netinet/in.h> 31f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <stdio.h> 41f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <string.h> 51f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <sys/socket.h> 61f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <sys/types.h> 71f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati#include <unistd.h> 81f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 90f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/osi.h" 101f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 111f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatitypedef int (*handler_t)(int argc, char **argv); 121f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 131f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatitypedef enum { 141f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati HCI_PACKET_COMMAND = 1, 151f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati HCI_PACKET_ACL_DATA = 2, 161f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati HCI_PACKET_SCO_DATA = 3, 171f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati HCI_PACKET_EVENT = 4, 181f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} hci_packet_t; 191f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 201f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatitypedef struct { 211f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati const char *name; 221f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati const char *help; 231f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati handler_t handler; 241f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} command_t; 251f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 261f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic int help(int argc, char **argv); 2752743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavatistatic int set_discoverable(int argc, char **argv); 281f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic int set_name(int argc, char **argv); 291f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic int set_pcm_loopback(int argc, char **argv); 30f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavatistatic int set_sco_route(int argc, char **argv); 311f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 321f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic bool write_hci_command(hci_packet_t type, const void *packet, size_t length); 331f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic const command_t *find_command(const char *name); 341f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic void usage(const char *name); 351f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 361f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic const command_t commands[] = { 371f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati { "help", "<command> - shows help text for <command>.", help }, 3852743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati { "setDiscoverable", "(true|false) - whether the controller should be discoverable.", set_discoverable }, 391f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati { "setName", "<name> - sets the device's Bluetooth name to <name>.", set_name }, 401f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati { "setPcmLoopback", "(true|false) - enables or disables PCM loopback on the controller.", set_pcm_loopback }, 41f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati { "setScoRoute", "(pcm|i2s|uart) - sets the SCO packet route to one of the specified buses.", set_sco_route }, 421f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati}; 431f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 441f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic int help(int argc, char **argv) { 451f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (!argc) { 461f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("No help command specified.\n"); 471f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 1; 481f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 491f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 501f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati const command_t *command = find_command(argv[0]); 511f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (!command) { 521f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("No command named '%s'.\n", argv[0]); 531f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 2; 541f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 551f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 561f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("%s %s\n", argv[0], command->help); 571f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 0; 581f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 591f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 6052743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavatistatic int set_discoverable(int argc, char **argv) { 6152743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati if (argc != 1) { 6252743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati printf("Discoverable mode not specified.\n"); 6352743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati return 1; 6452743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati } 6552743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati 6652743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) { 6752743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati printf("Invalid discoverable mode '%s'.\n", argv[0]); 6852743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati return 2; 6952743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati } 7052743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati 7152743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati uint8_t packet[] = { 0x1A, 0x0C, 0x01, 0x00 }; 7252743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati if (argv[0][0] == 't') 7352743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati packet[ARRAY_SIZE(packet) - 1] = 0x03; 7452743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati 7552743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet)); 7652743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati} 7752743028aa31788bb6e7cfffbfe8c11c91a779a3Sharvil Nanavati 781f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic int set_name(int argc, char **argv) { 791f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (argc != 1) { 801f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Device name not specified.\n"); 811f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 1; 821f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 831f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 841f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati size_t len = strlen(argv[0]); 851f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (len > 247) { 861f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Device name cannot exceed 247 bytes.\n"); 871f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 2; 881f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 891f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 901f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati uint8_t packet[251] = { 0x13, 0x0C, 248 }; 911f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati memcpy(&packet[3], argv[0], len + 1); 921f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 931f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (!write_hci_command(HCI_PACKET_COMMAND, packet, sizeof(packet))) 941f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 1; 951f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 96d5cb2e56dcc3d6431fb4b50b1fe3804b42c59161Edward Savage-Jones memset(&packet[0], 0, sizeof(packet)); 971f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[0] = 0x52; 981f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[1] = 0x0C; 991f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[2] = 0xF1; // HCI command packet length. 1001f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[3] = 0x01; // FEC required. 1011f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[4] = len + 1; 1021f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[5] = 0x09; // Device name field tag. 1031f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati memcpy(&packet[6], argv[0], len); 1041f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return !write_hci_command(HCI_PACKET_COMMAND, packet, 0xF4); 1051f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 1061f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1071f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic int set_pcm_loopback(int argc, char **argv) { 1081f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (argc != 1) { 1091f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("PCM loopback mode not specified.\n"); 1101f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 1; 1111f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 1121f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1131f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (strcmp(argv[0], "true") && strcmp(argv[0], "false")) { 1141f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Invalid PCM mode '%s'.\n", argv[0]); 1151f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return 2; 1161f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 1171f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1181f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati uint8_t packet[] = { 0x24, 0xFC, 0x01, 0x00 }; 1191f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (argv[0][0] == 't') 1201f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati packet[ARRAY_SIZE(packet) - 1] = 0x01; 1211f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1221f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet)); 1231f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 1241f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 125f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavatistatic int set_sco_route(int argc, char **argv) { 126f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati if (argc != 1) { 127f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati printf("SCO route parameter must be specified.\n"); 128f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati return 1; 129f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati } 130f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati 131f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati uint8_t route = 0xFF; 132f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati if (!strcmp(argv[0], "pcm")) 133f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati route = 0; 134f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati else if (!strcmp(argv[0], "i2s")) 135f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati route = 3; 136f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati else if (!strcmp(argv[0], "uart")) 137f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati route = 1; 138f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati 139f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati if (route == 0xFF) { 140f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati printf("Invalid SCO route specified: %s\n", argv[0]); 141f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati return 2; 142f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati } 143f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati 144f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati uint8_t packet[] = { 0x1C, 0xFC, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00 }; 145f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati packet[3] = route; 146f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati 147f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati return !write_hci_command(HCI_PACKET_COMMAND, packet, ARRAY_SIZE(packet)); 148f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati} 149f060365bf10c41c67d23337242802ffcb0a72895Sharvil Nanavati 1501f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatiint main(int argc, char **argv) { 1511f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (argc < 2) { 1521f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati usage(argv[0]); 1531f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return -1; 1541f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 1551f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1561f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati const command_t *command = find_command(argv[1]); 1571f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (!command) { 1581f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Unrecognized command '%s'.\n", argv[1]); 1591f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return -2; 1601f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 1611f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1621f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (!command->handler) { 1631f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Unhandled command '%s'.\n", argv[1]); 1641f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return -3; 1651f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati } 1661f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1671f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return command->handler(argc - 2, &argv[2]); 1681f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 1691f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1701f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic bool write_hci_command(hci_packet_t type, const void *packet, size_t length) { 1711f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 1721f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (sock == INVALID_FD) 1731f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati goto error; 1741f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1751f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati struct sockaddr_in addr; 1761f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati addr.sin_family = AF_INET; 1771f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati addr.sin_addr.s_addr = htonl(0x7F000001); 1781f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati addr.sin_port = htons(8873); 179574dcfb73e3741d715f7d4394fe5d3bd587cb0d2Pavlin Radoslavov int ret; 180574dcfb73e3741d715f7d4394fe5d3bd587cb0d2Pavlin Radoslavov OSI_NO_INTR(ret = connect(sock, (const struct sockaddr *)&addr, 181574dcfb73e3741d715f7d4394fe5d3bd587cb0d2Pavlin Radoslavov sizeof(addr))); 182574dcfb73e3741d715f7d4394fe5d3bd587cb0d2Pavlin Radoslavov if (ret == -1) 1831f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati goto error; 1841f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1851f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (send(sock, &type, 1, 0) != 1) 1861f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati goto error; 1871f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1881f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (send(sock, &length, 2, 0) != 2) 1891f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati goto error; 1901f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1911f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (send(sock, packet, length, 0) != (ssize_t)length) 1921f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati goto error; 1931f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1941f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati close(sock); 1951f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return true; 1961f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 1971f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatierror:; 1981f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati close(sock); 1991f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return false; 2001f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 2011f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 2021f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic const command_t *find_command(const char *name) { 2031f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati for (size_t i = 0; i < ARRAY_SIZE(commands); ++i) 2041f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati if (!strcmp(commands[i].name, name)) 2051f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return &commands[i]; 2061f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati return NULL; 2071f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 2081f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati 2091f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavatistatic void usage(const char *name) { 2101f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Usage: %s <command> [options]\n", name); 2111f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("Commands:\n"); 2121f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati for (size_t i = 0; i < ARRAY_SIZE(commands); ++i) 2131f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf(" %s\n", commands[i].name); 2141f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati printf("For detailed help on a command, run '%s help <command>'.\n", name); 2151f8c2356a1d9beeb40a9e107df415f46d50ee8baSharvil Nanavati} 216