cake
/
libp7
Archived
1
0
Fork 1
This repository has been archived on 2024-03-16. You can view files and clone it, but cannot push or open issues or pull requests.
libp7/src/handle/cinit.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