241 lines
5.3 KiB
C
241 lines
5.3 KiB
C
/* ************************************************************************** */
|
|
/* _____ _ */
|
|
/* init/cinit.c |_ _|__ _ _| |__ ___ _ _ */
|
|
/* | Project: libp7 | |/ _ \| | | | '_ \ / _ \ | | | */
|
|
/* | | (_) | |_| | | | | __/ |_| | */
|
|
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
|
|
/* Last updated: 2016/11/28 14:23:16 |___/ */
|
|
/* */
|
|
/* ************************************************************************** */
|
|
#include <libp7/internals.h>
|
|
#ifdef __linux__
|
|
# include <dirent.h>
|
|
# include <unistd.h>
|
|
# include <string.h>
|
|
# include <errno.h>
|
|
|
|
/**
|
|
* get_hex_from_file:
|
|
* Quick function to get a hex from a file.
|
|
*
|
|
* @arg path the path of the file to get the hex from.
|
|
* @arg hex pointer to the hex to fill.
|
|
* @return if there was an error.
|
|
*/
|
|
|
|
static int get_hex_from_file(char *path, unsigned int *hex)
|
|
{
|
|
int ret = 1;
|
|
|
|
/* open the file */
|
|
FILE *f = fopen(path, "r");
|
|
if (!f) {
|
|
log_error("Unable to open '%s': %s", path, strerror(errno));
|
|
return (1);
|
|
}
|
|
|
|
/* get the hex */
|
|
if (!fscanf(f, "%x", hex))
|
|
goto fail;
|
|
|
|
/* yay */
|
|
ret = 0;
|
|
fail:
|
|
fclose(f);
|
|
return (ret);
|
|
}
|
|
|
|
/**
|
|
* get_product_and_vendor_ids:
|
|
* Get product and vendor IDs according to sysfs.
|
|
*
|
|
* @arg path the path to the device info.
|
|
* @arg idVendor pointer to the idVendor to get
|
|
* @arg idProduct pointer to the idProduct to get
|
|
* @return if there was an error.
|
|
*/
|
|
|
|
static int get_product_and_vendor_ids(char *path,
|
|
unsigned int *idVendor, unsigned int *idProduct)
|
|
{
|
|
/* read the link */
|
|
char buf[PATH_MAX];
|
|
ssize_t rl = readlink(path, buf, PATH_MAX);
|
|
if (rl < 0) return (1);
|
|
buf[rl] = 0;
|
|
|
|
/* go back four folders */
|
|
char *p;
|
|
for (int i = 0; i < 4; i++) {
|
|
p = strrchr(buf, '/');
|
|
if (!p) return (1);
|
|
*p = 0;
|
|
}
|
|
|
|
/* get info from 'idVendor' and 'idProduct' files */
|
|
strcpy(p, "/idVendor");
|
|
if (get_hex_from_file(buf, idVendor))
|
|
return (1);
|
|
strcpy(p, "/idProduct");
|
|
if (get_hex_from_file(buf, idProduct))
|
|
return (1);
|
|
|
|
/* no error */
|
|
return (0);
|
|
}
|
|
|
|
/**
|
|
* p7_cfind:
|
|
* Find appropriate character devices on Linux.
|
|
*
|
|
* @arg devbuf the device path buffer.
|
|
* should be at least 16 bytes long.
|
|
* @return if there was an error.
|
|
*/
|
|
|
|
int p7_cfind(char *devbuf)
|
|
{
|
|
DIR *d;
|
|
int ret = 1;
|
|
|
|
/* backup current directory */
|
|
char cwd[PATH_MAX];
|
|
getcwd(cwd, PATH_MAX);
|
|
|
|
/* change directory */
|
|
chdir("/sys/class/tty");
|
|
|
|
/* prepare buffer */
|
|
char buf[PATH_MAX];
|
|
strcpy(buf, "/sys/class/tty/");
|
|
char *p = &buf[15];
|
|
|
|
/* open the sysfs tty directory */
|
|
d = opendir(buf);
|
|
if (!d) goto fail;
|
|
|
|
/* check for ttyUSB* devices */
|
|
struct dirent *dr;
|
|
while ((dr = readdir(d))) {
|
|
if (!strncmp(dr->d_name, "ttyUSB", 6)) {
|
|
strcpy(p, dr->d_name);
|
|
|
|
/* get idVendor and idProduct */
|
|
unsigned int idVendor, idProduct;
|
|
if (get_product_and_vendor_ids(buf, &idVendor, &idProduct)) {
|
|
log_error("Unable to get IDs of /sys/class/tty/%s", dr->d_name);
|
|
continue ;
|
|
}
|
|
|
|
/* check them */
|
|
if (_p7_check_usb(idVendor, idProduct)) {
|
|
sprintf(devbuf, "/dev/%s", dr->d_name);
|
|
goto success;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* if we're there, no device has been found */
|
|
goto fail;
|
|
success:
|
|
ret = 0;
|
|
fail:
|
|
if (d) closedir(d);
|
|
/* restore old current working directory and return */
|
|
chdir(cwd);
|
|
return (ret);
|
|
}
|
|
|
|
/**
|
|
* p7_cinit:
|
|
* Initialize libp7 with char device.
|
|
*
|
|
* @arg handle the handle to create
|
|
* @arg active whether to start as active or not
|
|
* @arg check if starting as active, send initial check or not
|
|
* @arg path path to char device.
|
|
* @arg tries number of tries (0 means default).
|
|
* @return the error (0 if ok)
|
|
*/
|
|
|
|
int p7_cinit(p7_handle_t **handle, int active, int check,
|
|
const char *path, int tries)
|
|
{
|
|
FILE *d = NULL;
|
|
|
|
/* if no path, get one */
|
|
char devbuf[20];
|
|
int failed = 0;
|
|
|
|
/* do the loop */
|
|
do {
|
|
if (failed) {
|
|
log_info("Trying again in one second.");
|
|
sleep(1);
|
|
}
|
|
|
|
/* if no path, get one */
|
|
if (!path) {
|
|
if (p7_cfind(devbuf))
|
|
goto not_found_yet;
|
|
path = devbuf;
|
|
}
|
|
|
|
/* open the stream */
|
|
d = fopen(path, "r+");
|
|
if (d) break;
|
|
|
|
not_found_yet:
|
|
/* wait */
|
|
#if LOGLEVEL <= ll_error
|
|
if (path)
|
|
log_error("Unable to open stream: %s", strerror(errno));
|
|
else
|
|
log_error("Could not find any appropriate device.");
|
|
#endif
|
|
failed = 1;
|
|
} while (--tries);
|
|
|
|
if (!path) return (p7_error_nocalc);
|
|
if (!d) switch (errno) {
|
|
case ENOENT: return (p7_error_nocalc);
|
|
case EACCES: return (p7_error_noaccess);
|
|
default: return (p7_error_nocalc);
|
|
}
|
|
|
|
/* init for real */
|
|
return (_p7_init(handle, active, check, (p7_stream_t){
|
|
._type = p7_streamtype_libc,
|
|
._rstream = d,
|
|
._wstream = d,
|
|
._rstream_close = 1
|
|
}));
|
|
}
|
|
|
|
#else
|
|
|
|
/**
|
|
* p7_cinit:
|
|
* Initialize libp7 with char device.
|
|
*
|
|
* @arg handle the handle to create
|
|
* @arg active whether to start as active or not
|
|
* @arg check if starting as active, send initial check or not
|
|
* @arg path path to char device.
|
|
* @arg tries number of tries (0 means default).
|
|
* @return the error (0 if ok)
|
|
*/
|
|
|
|
int p7_cinit(p7_handle_t **handle, int active, int check,
|
|
const char *path, int tries)
|
|
{
|
|
(void)handle;
|
|
(void)active;
|
|
(void)check;
|
|
(void)path;
|
|
(void)tries;
|
|
return (p7_error_nocalc);
|
|
}
|
|
|
|
#endif
|