#include "nvme_pci.h"
#include "nvme_common.h"
#include "nvme_mem.h"
#ifndef __HAIKU__
#include "nvme_cpu.h"
#endif
#include <fcntl.h>
#include <sys/file.h>
#include <sys/stat.h>
#if defined(NVME_ARCH_X86)
#include <sys/io.h>
#endif
#include <sys/ioctl.h>
#include <sys/types.h>
#ifndef __HAIKU__
#include <linux/fs.h>
#include <execinfo.h>
#endif
void nvme_str_trim(char *s)
{
char *p, *q;
p = s;
while (*p != '\0' && isspace(*p))
p++;
q = p + strlen(p);
while (q - 1 >= p && isspace(*(q - 1))) {
q--;
*q = '\0';
}
if (p != s) {
q = s;
while (*p != '\0')
*q++ = *p++;
*q = '\0';
}
}
int nvme_str_split(char *string, int stringlen,
char **tokens, int maxtokens, char delim)
{
int i, tok = 0;
int tokstart = 1;
if (string == NULL || tokens == NULL) {
errno = EINVAL;
return -1;
}
for (i = 0; i < stringlen; i++) {
if (string[i] == '\0' || tok >= maxtokens)
break;
if (tokstart) {
tokstart = 0;
tokens[tok++] = &string[i];
}
if (string[i] == delim) {
string[i] = '\0';
tokstart = 1;
}
}
return tok;
}
#ifndef __HAIKU__
int nvme_parse_sysfs_value(const char *filename,
unsigned long *val)
{
FILE *f;
char buf[BUFSIZ];
char *end = NULL;
if ((f = fopen(filename, "r")) == NULL) {
nvme_err("%s(): cannot open sysfs value %s\n",
__func__, filename);
return -1;
}
if (fgets(buf, sizeof(buf), f) == NULL) {
nvme_err("%s(): cannot read sysfs value %s\n",
__func__, filename);
fclose(f);
return -1;
}
*val = strtoul(buf, &end, 0);
if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) {
nvme_err("%s(): cannot parse sysfs value %s\n",
__func__, filename);
fclose(f);
return -1;
}
fclose(f);
return 0;
}
ssize_t nvme_dev_get_blocklen(int fd)
{
uint32_t blocklen = 0;
if (ioctl(fd, BLKSSZGET, &blocklen) < 0) {
nvme_err("iioctl BLKSSZGET failed %d (%s)\n",
errno,
strerror(errno));
return -1;
}
return blocklen;
}
#endif
uint64_t nvme_file_get_size(int fd)
{
struct stat st;
if (fstat(fd, &st) != 0)
return 0;
if (S_ISLNK(st.st_mode))
return 0;
if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) {
#ifndef __HAIKU__
uint64_t size;
if (ioctl(fd, BLKGETSIZE64, &size) == 0)
return size;
else
#endif
return 0;
}
if (S_ISREG(st.st_mode))
return st.st_size;
return 0;
}
#ifndef __HAIKU__
static void nvme_dump_stack(void)
{
#define BACKTRACE_SIZE 256
void *func[BACKTRACE_SIZE];
char **symb = NULL;
int size;
size = backtrace(func, BACKTRACE_SIZE);
symb = backtrace_symbols(func, size);
if (symb == NULL)
return;
while (size > 0) {
nvme_crit("%d: [%s]\n", size, symb[size - 1]);
size --;
}
free(symb);
}
#endif
#ifndef __HAIKU__
void
void __nvme_panic(const char *funcname, const char *format, ...)
{
va_list ap;
nvme_crit("PANIC in %s():\n", funcname);
va_start(ap, format);
nvme_vlog(NVME_LOG_CRIT, format, ap);
va_end(ap);
nvme_dump_stack();
abort();
}
#endif
int nvme_lib_init(enum nvme_log_level level,
enum nvme_log_facility facility, const char *path)
{
int ret;
#ifndef __HAIKU__
nvme_set_log_level(level);
nvme_set_log_facility(facility, path);
ret = nvme_cpu_init();
if (ret != 0) {
nvme_crit("Failed to gather CPU information\n");
goto out;
}
#endif
ret = nvme_pci_init();
if (ret != 0) {
nvme_crit("PCI subsystem initialization failed\n");
goto out;
}
ret = nvme_mem_init();
if (ret != 0)
nvme_crit("Memory management initialization failed\n");
out:
return ret;
}
__attribute__((destructor)) void nvme_lib_exit(void)
{
nvme_ctrlr_cleanup();
nvme_mem_cleanup();
}