"Fossies" - the Fresh Open Source Software Archive

Member "usbutils-014/usbmisc.c" (22 Feb 2021, 5464 Bytes) of package /linux/misc/usbutils-014.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "usbmisc.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 013_vs_014.

    1 // SPDX-License-Identifier: GPL-2.0-or-later
    2 /*
    3  * Misc USB routines
    4  *
    5  * Copyright (C) 2003 Aurelien Jarno (aurelien@aurel32.net)
    6  */
    7 
    8 #ifdef HAVE_CONFIG_H
    9 #include "config.h"
   10 #endif
   11 
   12 #include <stdio.h>
   13 #include <stdlib.h>
   14 #include <string.h>
   15 #include <unistd.h>
   16 #include <limits.h>
   17 
   18 #ifdef HAVE_ICONV
   19 #include <iconv.h>
   20 #endif
   21 
   22 #ifdef HAVE_NL_LANGINFO
   23 #include <langinfo.h>
   24 #endif
   25 
   26 #include "usbmisc.h"
   27 
   28 /* ---------------------------------------------------------------------- */
   29 
   30 static const char *devbususb = "/dev/bus/usb";
   31 
   32 /* ---------------------------------------------------------------------- */
   33 
   34 static int readlink_recursive(const char *path, char *buf, size_t bufsize)
   35 {
   36     char temp[PATH_MAX + 1];
   37     char *ptemp;
   38     int ret;
   39 
   40     ret = readlink(path, buf, bufsize-1);
   41 
   42     if (ret > 0) {
   43         buf[ret] = 0;
   44         if (*buf != '/') {
   45             strncpy(temp, path, sizeof(temp) - 1);
   46             ptemp = temp + strlen(temp);
   47             while (*ptemp != '/' && ptemp != temp)
   48                 ptemp--;
   49             ptemp++;
   50             strncpy(ptemp, buf, bufsize + temp - ptemp - 1);
   51         } else
   52             strncpy(temp, buf, sizeof(temp) - 1);
   53         return readlink_recursive(temp, buf, bufsize);
   54     } else {
   55         strncpy(buf, path, bufsize);
   56         return strlen(buf);
   57     }
   58 }
   59 
   60 static char *get_absolute_path(const char *path, char *result,
   61                    size_t result_size)
   62 {
   63     const char *ppath;  /* pointer on the input string */
   64     char *presult;      /* pointer on the output string */
   65 
   66     ppath = path;
   67     presult = result;
   68     result[0] = 0;
   69 
   70     if (path == NULL)
   71         return result;
   72 
   73     if (*ppath != '/') {
   74         result = getcwd(result, result_size);
   75         presult += strlen(result);
   76         result_size -= strlen(result);
   77 
   78         *presult++ = '/';
   79         result_size--;
   80     }
   81 
   82     while (*ppath != 0 && result_size > 1) {
   83         if (*ppath == '/') {
   84             do
   85                 ppath++;
   86             while (*ppath == '/');
   87             *presult++ = '/';
   88             result_size--;
   89         } else if (*ppath == '.' && *(ppath + 1) == '.' &&
   90                *(ppath + 2) == '/' && *(presult - 1) == '/') {
   91             if ((presult - 1) != result) {
   92                 /* go one directory upper */
   93                 do {
   94                     presult--;
   95                     result_size++;
   96                 } while (*(presult - 1) != '/');
   97             }
   98             ppath += 3;
   99         } else if (*ppath == '.'  &&
  100                *(ppath + 1) == '/' &&
  101                *(presult - 1) == '/') {
  102             ppath += 2;
  103         } else {
  104             *presult++ = *ppath++;
  105             result_size--;
  106         }
  107     }
  108     /* Don't forget to mark the end of the string! */
  109     *presult = 0;
  110 
  111     return result;
  112 }
  113 
  114 libusb_device *get_usb_device(libusb_context *ctx, const char *path)
  115 {
  116     libusb_device **list;
  117     libusb_device *dev;
  118     ssize_t num_devs, i;
  119     char device_path[PATH_MAX + 1];
  120     char absolute_path[PATH_MAX + 1];
  121 
  122     readlink_recursive(path, device_path, sizeof(device_path));
  123     get_absolute_path(device_path, absolute_path, sizeof(absolute_path));
  124 
  125     dev = NULL;
  126     num_devs = libusb_get_device_list(ctx, &list);
  127 
  128     for (i = 0; i < num_devs; ++i) {
  129         uint8_t bnum = libusb_get_bus_number(list[i]);
  130         uint8_t dnum = libusb_get_device_address(list[i]);
  131 
  132         snprintf(device_path, sizeof(device_path), "%s/%03u/%03u",
  133              devbususb, bnum, dnum);
  134         if (!strcmp(device_path, absolute_path)) {
  135             dev = list[i];
  136             break;
  137         }
  138     }
  139 
  140     libusb_free_device_list(list, 0);
  141     return dev;
  142 }
  143 
  144 static char *get_dev_string_ascii(libusb_device_handle *dev, size_t size,
  145                                   uint8_t id)
  146 {
  147     char *buf = malloc(size);
  148     int ret = libusb_get_string_descriptor_ascii(dev, id,
  149                                                  (unsigned char *) buf,
  150                                                  size);
  151 
  152     if (ret < 0) {
  153         free(buf);
  154         return strdup("(error)");
  155     }
  156 
  157     return buf;
  158 }
  159 
  160 #if defined(HAVE_NL_LANGINFO) && defined(HAVE_ICONV)
  161 static uint16_t get_any_langid(libusb_device_handle *dev)
  162 {
  163     unsigned char buf[4];
  164     int ret = libusb_get_string_descriptor(dev, 0, 0, buf, sizeof buf);
  165     if (ret != sizeof buf) return 0;
  166     return buf[2] | (buf[3] << 8);
  167 }
  168 
  169 static char *usb_string_to_native(char * str, size_t len)
  170 {
  171     size_t num_converted;
  172     iconv_t conv;
  173     char *result, *result_end;
  174     size_t in_bytes_left, out_bytes_left;
  175 
  176     conv = iconv_open(nl_langinfo(CODESET), "UTF-16LE");
  177 
  178     if (conv == (iconv_t) -1)
  179         return NULL;
  180 
  181     in_bytes_left = len * 2;
  182     out_bytes_left = len * MB_CUR_MAX;
  183     result = result_end = malloc(out_bytes_left + 1);
  184 
  185     num_converted = iconv(conv, &str, &in_bytes_left,
  186                           &result_end, &out_bytes_left);
  187 
  188     iconv_close(conv);
  189     if (num_converted == (size_t) -1) {
  190         free(result);
  191         return NULL;
  192     }
  193 
  194     *result_end = 0;
  195     return result;
  196 }
  197 #endif
  198 
  199 char *get_dev_string(libusb_device_handle *dev, uint8_t id)
  200 {
  201 #if defined(HAVE_NL_LANGINFO) && defined(HAVE_ICONV)
  202     int ret;
  203     char *buf, unicode_buf[254];
  204     uint16_t langid;
  205 #endif
  206 
  207     if (!dev || !id) return strdup("");
  208 
  209 #if defined(HAVE_NL_LANGINFO) && defined(HAVE_ICONV)
  210     langid = get_any_langid(dev);
  211     if (!langid) return strdup("(error)");
  212 
  213     /*
  214      * Some devices lie about their string size, so initialize
  215      * the buffer with all 0 to account for that.
  216      */
  217     memset(unicode_buf, 0x00, sizeof(unicode_buf));
  218 
  219     ret = libusb_get_string_descriptor(dev, id, langid,
  220                                        (unsigned char *) unicode_buf,
  221                                        sizeof unicode_buf);
  222     if (ret < 2) return strdup("(error)");
  223 
  224     if ((unsigned char)unicode_buf[0] < 2 || unicode_buf[1] != LIBUSB_DT_STRING)
  225         return strdup("(error)");
  226 
  227     buf = usb_string_to_native(unicode_buf + 2,
  228                                ((unsigned char) unicode_buf[0] - 2) / 2);
  229 
  230     if (!buf) return get_dev_string_ascii(dev, 127, id);
  231 
  232     return buf;
  233 #else
  234     return get_dev_string_ascii(dev, 127, id);
  235 #endif
  236 }