diff options
| author | 2009-01-08 18:17:21 +0100 | |
|---|---|---|
| committer | 2009-01-09 20:18:38 -0800 | |
| commit | 89ad220b093b73e229207ca2da0ad568d81f69e3 (patch) | |
| tree | babb6c465ad3fd021068f7a86d55845590d06bad /src | |
| parent | cae85d48c44a9cf9b947a91aef6fbf7309398c4a (diff) | |
| download | libimobiledevice-89ad220b093b73e229207ca2da0ad568d81f69e3.tar.gz libimobiledevice-89ad220b093b73e229207ca2da0ad568d81f69e3.tar.bz2 | |
Perform proper goodby on lockdown shutdown.
Diffstat (limited to 'src')
| -rw-r--r-- | src/iphone.c | 59 | ||||
| -rw-r--r-- | src/lockdown.c | 178 | ||||
| -rw-r--r-- | src/lockdown.h | 1 | ||||
| -rw-r--r-- | src/usbmux.c | 3 | ||||
| -rw-r--r-- | src/utils.c | 34 |
5 files changed, 260 insertions, 15 deletions
diff --git a/src/iphone.c b/src/iphone.c index 32d27f6..1f68180 100644 --- a/src/iphone.c +++ b/src/iphone.c | |||
| @@ -28,6 +28,49 @@ | |||
| 28 | #include <stdlib.h> | 28 | #include <stdlib.h> |
| 29 | #include <string.h> | 29 | #include <string.h> |
| 30 | 30 | ||
| 31 | /** | ||
| 32 | * This function sets the configuration of the given device to 3 | ||
| 33 | * and claims the interface 1. If usb_set_configuration fails, it detaches | ||
| 34 | * the kernel driver that blocks the device, and retries configuration. | ||
| 35 | * | ||
| 36 | * @param phone which device to configure | ||
| 37 | */ | ||
| 38 | static void iphone_config_usb_device(iphone_device_t phone) | ||
| 39 | { | ||
| 40 | int ret; | ||
| 41 | |||
| 42 | log_debug_msg("setting configuration... "); | ||
| 43 | ret = usb_set_configuration(phone->device, 3); | ||
| 44 | if (ret != 0) { | ||
| 45 | log_debug_msg("Hm, usb_set_configuration returned %d: %s, trying to fix:\n", ret, strerror(-ret)); | ||
| 46 | log_debug_msg("-> detaching kernel driver... "); | ||
| 47 | ret = | ||
| 48 | usb_detach_kernel_driver_np(phone->device, | ||
| 49 | phone->__device->config->interface->altsetting->bInterfaceNumber); | ||
| 50 | if (ret != 0) { | ||
| 51 | log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", ret, strerror(-ret)); | ||
| 52 | } else { | ||
| 53 | log_debug_msg("done.\n"); | ||
| 54 | log_debug_msg("setting configuration again... "); | ||
| 55 | ret = usb_set_configuration(phone->device, 3); | ||
| 56 | if (ret != 0) { | ||
| 57 | log_debug_msg("Error: usb_set_configuration returned %d: %s\n", ret, strerror(-ret)); | ||
| 58 | } else { | ||
| 59 | log_debug_msg("done.\n"); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | } else { | ||
| 63 | log_debug_msg("done.\n"); | ||
| 64 | } | ||
| 65 | |||
| 66 | log_debug_msg("claiming interface... "); | ||
| 67 | ret = usb_claim_interface(phone->device, 1); | ||
| 68 | if (ret != 0) { | ||
| 69 | log_debug_msg("Error: usb_claim_interface returned %d: %s\n", ret, strerror(-ret)); | ||
| 70 | } else { | ||
| 71 | log_debug_msg("done.\n"); | ||
| 72 | } | ||
| 73 | } | ||
| 31 | 74 | ||
| 32 | /** | 75 | /** |
| 33 | * Given a USB bus and device number, returns a device handle to the iPhone on | 76 | * Given a USB bus and device number, returns a device handle to the iPhone on |
| @@ -73,8 +116,7 @@ static iphone_error_t iphone_get_specific_device(unsigned int bus_n, int dev_n, | |||
| 73 | if (dev->devnum == dev_n) { | 116 | if (dev->devnum == dev_n) { |
| 74 | phone->__device = dev; | 117 | phone->__device = dev; |
| 75 | phone->device = usb_open(phone->__device); | 118 | phone->device = usb_open(phone->__device); |
| 76 | usb_set_configuration(phone->device, 3); | 119 | iphone_config_usb_device(phone); |
| 77 | usb_claim_interface(phone->device, 1); | ||
| 78 | goto found; | 120 | goto found; |
| 79 | } | 121 | } |
| 80 | 122 | ||
| @@ -115,9 +157,10 @@ static iphone_error_t iphone_get_specific_device(unsigned int bus_n, int dev_n, | |||
| 115 | return IPHONE_E_SUCCESS; | 157 | return IPHONE_E_SUCCESS; |
| 116 | } else { | 158 | } else { |
| 117 | // Bad header | 159 | // Bad header |
| 160 | log_debug_msg("get_iPhone(): Received a bad header/invalid version number.\n"); | ||
| 161 | log_debug_buffer((char *) version, sizeof(*version)); | ||
| 118 | iphone_free_device(phone); | 162 | iphone_free_device(phone); |
| 119 | free(version); | 163 | free(version); |
| 120 | log_debug_msg("get_iPhone(): Received a bad header/invalid version number."); | ||
| 121 | return IPHONE_E_BAD_HEADER; | 164 | return IPHONE_E_BAD_HEADER; |
| 122 | } | 165 | } |
| 123 | 166 | ||
| @@ -173,13 +216,21 @@ iphone_error_t iphone_free_device(iphone_device_t device) | |||
| 173 | if (!device) | 216 | if (!device) |
| 174 | return IPHONE_E_INVALID_ARG; | 217 | return IPHONE_E_INVALID_ARG; |
| 175 | iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; | 218 | iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; |
| 219 | int bytes; | ||
| 220 | unsigned char buf[512]; | ||
| 221 | |||
| 222 | // read final package | ||
| 223 | bytes = usb_bulk_read(device->device, BULKIN, (void *) &buf, 512, 1000); | ||
| 224 | if (bytes > 0) { | ||
| 225 | log_debug_msg("iphone_free_device: final read returned\n"); | ||
| 226 | log_debug_buffer(buf, bytes); | ||
| 227 | } | ||
| 176 | 228 | ||
| 177 | if (device->buffer) { | 229 | if (device->buffer) { |
| 178 | free(device->buffer); | 230 | free(device->buffer); |
| 179 | } | 231 | } |
| 180 | if (device->device) { | 232 | if (device->device) { |
| 181 | usb_release_interface(device->device, 1); | 233 | usb_release_interface(device->device, 1); |
| 182 | usb_reset(device->device); | ||
| 183 | usb_close(device->device); | 234 | usb_close(device->device); |
| 184 | ret = IPHONE_E_SUCCESS; | 235 | ret = IPHONE_E_SUCCESS; |
| 185 | } | 236 | } |
diff --git a/src/lockdown.c b/src/lockdown.c index cf0d99e..ab168a3 100644 --- a/src/lockdown.c +++ b/src/lockdown.c | |||
| @@ -92,6 +92,97 @@ iphone_lckd_client_t new_lockdownd_client(iphone_device_t phone) | |||
| 92 | return control; | 92 | return control; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | /** | ||
| 96 | * Closes the lockdownd communication session, by sending | ||
| 97 | * the StopSession Request to the device. | ||
| 98 | * | ||
| 99 | * @param control The lockdown client | ||
| 100 | */ | ||
| 101 | static void iphone_lckd_stop_session(iphone_lckd_client_t control) | ||
| 102 | { | ||
| 103 | if (!control) | ||
| 104 | return; // IPHONE_E_INVALID_ARG; | ||
| 105 | xmlDocPtr plist = new_plist(); | ||
| 106 | xmlNode *dict, *key; | ||
| 107 | char **dictionary; | ||
| 108 | int bytes = 0, i = 0; | ||
| 109 | iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; | ||
| 110 | |||
| 111 | log_debug_msg("lockdownd_stop_session() called\n"); | ||
| 112 | dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); | ||
| 113 | key = add_key_str_dict_element(plist, dict, "Request", "StopSession", 1); | ||
| 114 | key = add_key_str_dict_element(plist, dict, "SessionID", control->session_id, 1); | ||
| 115 | |||
| 116 | char *XML_content; | ||
| 117 | uint32 length; | ||
| 118 | |||
| 119 | xmlDocDumpMemory(plist, (xmlChar **) & XML_content, &length); | ||
| 120 | ret = iphone_lckd_send(control, XML_content, length, &bytes); | ||
| 121 | |||
| 122 | xmlFree(XML_content); | ||
| 123 | xmlFreeDoc(plist); | ||
| 124 | plist = NULL; | ||
| 125 | ret = iphone_lckd_recv(control, &XML_content, &bytes); | ||
| 126 | |||
| 127 | plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0); | ||
| 128 | if (!plist) { | ||
| 129 | fprintf(stderr, "lockdownd_stop_session(): IPHONE_E_PLIST_ERROR\n"); | ||
| 130 | return; //IPHONE_E_PLIST_ERROR; | ||
| 131 | } | ||
| 132 | dict = xmlDocGetRootElement(plist); | ||
| 133 | for (dict = dict->children; dict; dict = dict->next) { | ||
| 134 | if (!xmlStrcmp(dict->name, "dict")) | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | if (!dict) { | ||
| 138 | fprintf(stderr, "lockdownd_stop_session(): IPHONE_E_DICT_ERROR\n"); | ||
| 139 | return; //IPHONE_E_DICT_ERROR; | ||
| 140 | } | ||
| 141 | dictionary = read_dict_element_strings(dict); | ||
| 142 | xmlFreeDoc(plist); | ||
| 143 | free(XML_content); | ||
| 144 | |||
| 145 | for (i = 0; dictionary[i]; i += 2) { | ||
| 146 | if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { | ||
| 147 | log_debug_msg("lockdownd_stop_session(): success\n"); | ||
| 148 | ret = IPHONE_E_SUCCESS; | ||
| 149 | break; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | free_dictionary(dictionary); | ||
| 154 | return; //ret; | ||
| 155 | } | ||
| 156 | |||
| 157 | /** | ||
| 158 | * Shuts down the SSL session by first calling iphone_lckd_stop_session | ||
| 159 | * to cleanly close the lockdownd communication session, and then | ||
| 160 | * performing a close notify, which is done by "gnutls_bye". | ||
| 161 | * | ||
| 162 | * @param client The lockdown client | ||
| 163 | */ | ||
| 164 | static void iphone_lckd_stop_SSL_session(iphone_lckd_client_t client) | ||
| 165 | { | ||
| 166 | if (!client) { | ||
| 167 | log_debug_msg("lockdownd_stop_SSL_session(): invalid argument!\n"); | ||
| 168 | return; | ||
| 169 | } | ||
| 170 | |||
| 171 | if (client->in_SSL) { | ||
| 172 | log_debug_msg("Stopping SSL Session\n"); | ||
| 173 | iphone_lckd_stop_session(client); | ||
| 174 | log_debug_msg("Sending SSL close notify\n"); | ||
| 175 | gnutls_bye(*client->ssl_session, GNUTLS_SHUT_RDWR); | ||
| 176 | } | ||
| 177 | if (client->ssl_session) { | ||
| 178 | gnutls_deinit(*client->ssl_session); | ||
| 179 | free(client->ssl_session); | ||
| 180 | } | ||
| 181 | client->in_SSL = 0; | ||
| 182 | client->gtls_buffer_hack_len = 0; // dunno if required?! | ||
| 183 | |||
| 184 | return; | ||
| 185 | } | ||
| 95 | 186 | ||
| 96 | /** Closes the lockdownd client and does the necessary housekeeping. | 187 | /** Closes the lockdownd client and does the necessary housekeeping. |
| 97 | * | 188 | * |
| @@ -103,13 +194,17 @@ iphone_error_t iphone_lckd_free_client(iphone_lckd_client_t client) | |||
| 103 | return IPHONE_E_INVALID_ARG; | 194 | return IPHONE_E_INVALID_ARG; |
| 104 | iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; | 195 | iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; |
| 105 | 196 | ||
| 197 | iphone_lckd_stop_SSL_session(client); | ||
| 198 | |||
| 106 | if (client->connection) { | 199 | if (client->connection) { |
| 200 | lockdownd_close(client); | ||
| 201 | |||
| 202 | // IMO, read of final "sessionUpcall connection closed" packet | ||
| 203 | // should come here instead of in iphone_free_device | ||
| 204 | |||
| 107 | ret = iphone_mux_free_client(client->connection); | 205 | ret = iphone_mux_free_client(client->connection); |
| 108 | } | 206 | } |
| 109 | 207 | ||
| 110 | if (client->ssl_session) | ||
| 111 | gnutls_deinit(*client->ssl_session); | ||
| 112 | free(client->ssl_session); | ||
| 113 | free(client); | 208 | free(client); |
| 114 | return ret; | 209 | return ret; |
| 115 | } | 210 | } |
| @@ -520,6 +615,66 @@ iphone_error_t lockdownd_pair_device(iphone_lckd_client_t control, char *uid, ch | |||
| 520 | return ret; | 615 | return ret; |
| 521 | } | 616 | } |
| 522 | 617 | ||
| 618 | /** | ||
| 619 | * Performs the Goodbye Request to tell the device the communication | ||
| 620 | * session is now closed. | ||
| 621 | * | ||
| 622 | * @param control The lockdown client | ||
| 623 | */ | ||
| 624 | void lockdownd_close(iphone_lckd_client_t control) | ||
| 625 | { | ||
| 626 | if (!control) | ||
| 627 | return; // IPHONE_E_INVALID_ARG; | ||
| 628 | xmlDocPtr plist = new_plist(); | ||
| 629 | xmlNode *dict, *key; | ||
| 630 | char **dictionary; | ||
| 631 | int bytes = 0, i = 0; | ||
| 632 | iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; | ||
| 633 | |||
| 634 | log_debug_msg("lockdownd_close() called\n"); | ||
| 635 | dict = add_child_to_plist(plist, "dict", "\n", NULL, 0); | ||
| 636 | key = add_key_str_dict_element(plist, dict, "Request", "Goodbye", 1); | ||
| 637 | char *XML_content; | ||
| 638 | uint32 length; | ||
| 639 | |||
| 640 | xmlDocDumpMemory(plist, (xmlChar **) & XML_content, &length); | ||
| 641 | ret = iphone_lckd_send(control, XML_content, length, &bytes); | ||
| 642 | |||
| 643 | xmlFree(XML_content); | ||
| 644 | xmlFreeDoc(plist); | ||
| 645 | plist = NULL; | ||
| 646 | ret = iphone_lckd_recv(control, &XML_content, &bytes); | ||
| 647 | |||
| 648 | plist = xmlReadMemory(XML_content, bytes, NULL, NULL, 0); | ||
| 649 | if (!plist) { | ||
| 650 | fprintf(stderr, "lockdownd_close(): IPHONE_E_PLIST_ERROR\n"); | ||
| 651 | return; //IPHONE_E_PLIST_ERROR; | ||
| 652 | } | ||
| 653 | dict = xmlDocGetRootElement(plist); | ||
| 654 | for (dict = dict->children; dict; dict = dict->next) { | ||
| 655 | if (!xmlStrcmp(dict->name, "dict")) | ||
| 656 | break; | ||
| 657 | } | ||
| 658 | if (!dict) { | ||
| 659 | fprintf(stderr, "lockdownd_close(): IPHONE_E_DICT_ERROR\n"); | ||
| 660 | return; //IPHONE_E_DICT_ERROR; | ||
| 661 | } | ||
| 662 | dictionary = read_dict_element_strings(dict); | ||
| 663 | xmlFreeDoc(plist); | ||
| 664 | free(XML_content); | ||
| 665 | |||
| 666 | for (i = 0; dictionary[i]; i += 2) { | ||
| 667 | if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { | ||
| 668 | log_debug_msg("lockdownd_close(): success\n"); | ||
| 669 | ret = IPHONE_E_SUCCESS; | ||
| 670 | break; | ||
| 671 | } | ||
| 672 | } | ||
| 673 | |||
| 674 | free_dictionary(dictionary); | ||
| 675 | return; //ret; | ||
| 676 | } | ||
| 677 | |||
| 523 | /** Generates the device certificate from the public key as well as the host | 678 | /** Generates the device certificate from the public key as well as the host |
| 524 | * and root certificates. | 679 | * and root certificates. |
| 525 | * | 680 | * |
| @@ -664,6 +819,8 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c | |||
| 664 | iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; | 819 | iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; |
| 665 | // end variables | 820 | // end variables |
| 666 | 821 | ||
| 822 | control->session_id[0] = '\0'; | ||
| 823 | |||
| 667 | key = add_key_str_dict_element(plist, dict, "HostID", HostID, 1); | 824 | key = add_key_str_dict_element(plist, dict, "HostID", HostID, 1); |
| 668 | if (!key) { | 825 | if (!key) { |
| 669 | log_debug_msg("Couldn't add a key.\n"); | 826 | log_debug_msg("Couldn't add a key.\n"); |
| @@ -699,6 +856,7 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c | |||
| 699 | dictionary = read_dict_element_strings(dict); | 856 | dictionary = read_dict_element_strings(dict); |
| 700 | xmlFreeDoc(plist); | 857 | xmlFreeDoc(plist); |
| 701 | free(what2send); | 858 | free(what2send); |
| 859 | ret = IPHONE_E_SSL_ERROR; | ||
| 702 | for (i = 0; dictionary[i]; i += 2) { | 860 | for (i = 0; dictionary[i]; i += 2) { |
| 703 | if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { | 861 | if (!strcmp(dictionary[i], "Result") && !strcmp(dictionary[i + 1], "Success")) { |
| 704 | // Set up GnuTLS... | 862 | // Set up GnuTLS... |
| @@ -741,8 +899,6 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c | |||
| 741 | return_me = gnutls_handshake(*control->ssl_session); | 899 | return_me = gnutls_handshake(*control->ssl_session); |
| 742 | log_debug_msg("GnuTLS handshake done...\n"); | 900 | log_debug_msg("GnuTLS handshake done...\n"); |
| 743 | 901 | ||
| 744 | free_dictionary(dictionary); | ||
| 745 | |||
| 746 | if (return_me != GNUTLS_E_SUCCESS) { | 902 | if (return_me != GNUTLS_E_SUCCESS) { |
| 747 | log_debug_msg("GnuTLS reported something wrong.\n"); | 903 | log_debug_msg("GnuTLS reported something wrong.\n"); |
| 748 | gnutls_perror(return_me); | 904 | gnutls_perror(return_me); |
| @@ -750,10 +906,20 @@ iphone_error_t lockdownd_start_SSL_session(iphone_lckd_client_t control, const c | |||
| 750 | return IPHONE_E_SSL_ERROR; | 906 | return IPHONE_E_SSL_ERROR; |
| 751 | } else { | 907 | } else { |
| 752 | control->in_SSL = 1; | 908 | control->in_SSL = 1; |
| 753 | return IPHONE_E_SUCCESS; | 909 | ret = IPHONE_E_SUCCESS; |
| 754 | } | 910 | } |
| 911 | } else if (!strcmp(dictionary[i], "SessionID")) { | ||
| 912 | // we need to store the session ID for StopSession | ||
| 913 | strcpy(control->session_id, dictionary[i + 1]); | ||
| 914 | log_debug_msg("SessionID: %s\n", control->session_id); | ||
| 915 | free_dictionary(dictionary); | ||
| 916 | return ret; | ||
| 755 | } | 917 | } |
| 756 | } | 918 | } |
| 919 | if (ret == IPHONE_E_SUCCESS) { | ||
| 920 | log_debug_msg("Failed to get SessionID!\n"); | ||
| 921 | return ret; | ||
| 922 | } | ||
| 757 | 923 | ||
| 758 | log_debug_msg("Apparently failed negotiating with lockdownd.\n"); | 924 | log_debug_msg("Apparently failed negotiating with lockdownd.\n"); |
| 759 | log_debug_msg("Responding dictionary: \n"); | 925 | log_debug_msg("Responding dictionary: \n"); |
diff --git a/src/lockdown.h b/src/lockdown.h index 79ca37e..8b4f27c 100644 --- a/src/lockdown.h +++ b/src/lockdown.h | |||
| @@ -38,6 +38,7 @@ struct iphone_lckd_client_int { | |||
| 38 | int in_SSL; | 38 | int in_SSL; |
| 39 | char *gtls_buffer_hack; | 39 | char *gtls_buffer_hack; |
| 40 | int gtls_buffer_hack_len; | 40 | int gtls_buffer_hack_len; |
| 41 | char session_id[40]; | ||
| 41 | }; | 42 | }; |
| 42 | 43 | ||
| 43 | char *lockdownd_generate_hostid(void); | 44 | char *lockdownd_generate_hostid(void); |
diff --git a/src/usbmux.c b/src/usbmux.c index 770d0db..c7ac7ef 100644 --- a/src/usbmux.c +++ b/src/usbmux.c | |||
| @@ -182,8 +182,11 @@ iphone_error_t iphone_mux_free_client(iphone_umux_client_t client) | |||
| 182 | return IPHONE_E_INVALID_ARG; | 182 | return IPHONE_E_INVALID_ARG; |
| 183 | 183 | ||
| 184 | client->header->tcp_flags = 0x04; | 184 | client->header->tcp_flags = 0x04; |
| 185 | client->header->length = htonl(0x1C); | ||
| 185 | client->header->scnt = htonl(client->header->scnt); | 186 | client->header->scnt = htonl(client->header->scnt); |
| 186 | client->header->ocnt = htonl(client->header->ocnt); | 187 | client->header->ocnt = htonl(client->header->ocnt); |
| 188 | client->header->window = 0; | ||
| 189 | client->header->length16 = htons(0x1C); | ||
| 187 | int bytes = 0; | 190 | int bytes = 0; |
| 188 | 191 | ||
| 189 | bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800); | 192 | bytes = usb_bulk_write(client->phone->device, BULKOUT, (char *) client->header, sizeof(usbmux_tcp_header), 800); |
diff --git a/src/utils.c b/src/utils.c index 049777a..fb98471 100644 --- a/src/utils.c +++ b/src/utils.c | |||
| @@ -46,7 +46,7 @@ void log_debug_msg(const char *format, ...) | |||
| 46 | va_start(args, format); | 46 | va_start(args, format); |
| 47 | 47 | ||
| 48 | if (toto_debug) | 48 | if (toto_debug) |
| 49 | fprintf(stderr, format, args); | 49 | vfprintf(stderr, format, args); |
| 50 | 50 | ||
| 51 | va_end(args); | 51 | va_end(args); |
| 52 | 52 | ||
| @@ -56,11 +56,35 @@ void log_debug_msg(const char *format, ...) | |||
| 56 | inline void log_debug_buffer(const char *data, const int length) | 56 | inline void log_debug_buffer(const char *data, const int length) |
| 57 | { | 57 | { |
| 58 | #ifndef STRIP_DEBUG_CODE | 58 | #ifndef STRIP_DEBUG_CODE |
| 59 | int i; | ||
| 60 | int j; | ||
| 61 | unsigned char c; | ||
| 59 | 62 | ||
| 60 | /* run the real fprintf */ | 63 | if (toto_debug) { |
| 61 | if (toto_debug) | 64 | for (i = 0; i < length; i += 16) { |
| 62 | fwrite(data, 1, length, stderr); | 65 | fprintf(stderr, "%04x: ", i); |
| 63 | 66 | for (j = 0; j < 16; j++) { | |
| 67 | if (i + j >= length) { | ||
| 68 | fprintf(stderr, " "); | ||
| 69 | continue; | ||
| 70 | } | ||
| 71 | fprintf(stderr, "%02hhx ", *(data + i + j)); | ||
| 72 | } | ||
| 73 | fprintf(stderr, " | "); | ||
| 74 | for (j = 0; j < 16; j++) { | ||
| 75 | if (i + j >= length) | ||
| 76 | break; | ||
| 77 | c = *(data + i + j); | ||
| 78 | if ((c < 32) || (c > 127)) { | ||
| 79 | fprintf(stderr, "."); | ||
| 80 | continue; | ||
| 81 | } | ||
| 82 | fprintf(stderr, "%c", c); | ||
| 83 | } | ||
| 84 | fprintf(stderr, "\n"); | ||
| 85 | } | ||
| 86 | fprintf(stderr, "\n"); | ||
| 87 | } | ||
| 64 | #endif | 88 | #endif |
| 65 | } | 89 | } |
| 66 | 90 | ||
