/*
* The PCI Library -- Initialization and related things
*
- * Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
+ * Copyright (c) 1997--2024 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL v2+.
*
#endif
+#ifdef PCI_USE_DNS
+
+static void
+pci_init_dns(struct pci_access *a)
+{
+ pci_define_param(a, "net.domain", PCI_ID_DOMAIN, "DNS domain used for resolving of ID's");
+ a->id_lookup_mode = PCI_LOOKUP_CACHE;
+
+ char *cache_dir = getenv("XDG_CACHE_HOME");
+ if (!cache_dir)
+ cache_dir = "~/.cache";
+
+ int name_len = strlen(cache_dir) + 32;
+ char *cache_name = pci_malloc(NULL, name_len);
+ snprintf(cache_name, name_len, "%s/pci-ids", cache_dir);
+ struct pci_param *param = pci_define_param(a, "net.cache_name", cache_name, "Name of the ID cache file");
+ param->value_malloced = 1;
+}
+
+#endif
+
struct pci_access *
pci_alloc(void)
{
memset(a, 0, sizeof(*a));
pci_init_name_list_path(a);
#ifdef PCI_USE_DNS
- pci_define_param(a, "net.domain", PCI_ID_DOMAIN, "DNS domain used for resolving of ID's");
- pci_define_param(a, "net.cache_name", "~/.pciids-cache", "Name of the ID cache file");
- a->id_lookup_mode = PCI_LOOKUP_CACHE;
+ pci_init_dns(a);
#endif
#ifdef PCI_HAVE_HWDB
pci_define_param(a, "hwdb.disable", "0", "Do not look up names in UDEV's HWDB if non-zero");
#include <string.h>
#include <errno.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <pwd.h>
#include <unistd.h>
static char *get_cache_name(struct pci_access *a)
{
- char *name, *buf;
-
- name = pci_get_param(a, "net.cache_name");
- if (!name || !name[0])
- return NULL;
- if (strncmp(name, "~/", 2))
- return name;
-
- uid_t uid = getuid();
- struct passwd *pw = getpwuid(uid);
- if (!pw)
- return name;
-
- buf = pci_malloc(a, strlen(pw->pw_dir) + strlen(name+1) + 1);
- sprintf(buf, "%s%s", pw->pw_dir, name+1);
- pci_set_param_internal(a, "net.cache_name", buf, 1);
- pci_mfree(buf);
- return pci_get_param(a, "net.cache_name");
+ if (!a->id_cache_name)
+ {
+ char *name = pci_get_param(a, "net.cache_name");
+ if (!name || !name[0])
+ return NULL;
+
+ if (strncmp(name, "~/", 2))
+ a->id_cache_name = pci_strdup(a, name);
+ else
+ {
+ uid_t uid = getuid();
+ struct passwd *pw = getpwuid(uid);
+ if (!pw)
+ return name;
+
+ a->id_cache_name = pci_malloc(a, strlen(pw->pw_dir) + strlen(name+1) + 1);
+ sprintf(a->id_cache_name, "%s%s", pw->pw_dir, name+1);
+ }
+ }
+
+ return a->id_cache_name;
+}
+
+static void create_parent_dirs(struct pci_access *a, char *name)
+{
+ // Assumes that we have a private copy of the name we can modify
+
+ char *p = name + strlen(name);
+ while (p > name && *p != '/')
+ p--;
+ if (p == name)
+ return;
+
+ while (p > name)
+ {
+ // We stand at a slash. Check if the current prefix exists.
+ *p = 0;
+ struct stat st;
+ int res = stat(name, &st);
+ *p = '/';
+ if (res >= 0)
+ break;
+
+ // Does not exist yet, move up one directory
+ p--;
+ while (p > name && *p != '/')
+ p--;
+ }
+
+ // We now stand at the end of the longest existing prefix.
+ // Create all directories to the right of it.
+ for (;;)
+ {
+ p++;
+ while (*p && *p != '/')
+ p++;
+ if (!*p)
+ break;
+
+ *p = 0;
+ int res = mkdir(name, 0777);
+ if (res < 0)
+ {
+ a->warning("Cannot create directory %s: %s", name, strerror(errno));
+ *p = '/';
+ break;
+ }
+ *p = '/';
+ }
}
int
FILE *f;
int lino;
+ if (a->id_cache_status > 0)
+ return 0;
a->id_cache_status = 1;
+
name = get_cache_name(a);
if (!name)
return 0;
a->debug("Using cache %s\n", name);
+
if (flags & PCI_LOOKUP_REFRESH_CACHE)
{
a->debug("Not loading cache, will refresh everything\n");
if (!name)
return;
+ create_parent_dirs(a, name);
+
this_pid = getpid();
if (gethostname(hostname, sizeof(hostname)) < 0)
hostname[0] = 0;
void pci_id_cache_flush(struct pci_access *a)
{
a->id_cache_status = 0;
+ pci_mfree(a->id_cache_name);
+ a->id_cache_name = NULL;
}
#endif