]> mj.ucw.cz Git - pciutils.git/blob - lib/names-cache.c
2811fe46eb1391ea554f612fa14c92a2f45e0693
[pciutils.git] / lib / names-cache.c
1 /*
2  *      The PCI Library -- ID to Name Cache
3  *
4  *      Copyright (c) 2008 Martin Mares <mj@ucw.cz>
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL.
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <sys/types.h>
14 #include <pwd.h>
15 #include <unistd.h>
16
17 #include "internal.h"
18 #include "names.h"
19
20 static const char cache_version[] = "#PCI-CACHE-1.0";
21
22 int
23 pci_id_cache_load(struct pci_access *a, int flags)
24 {
25   char *name;
26   char line[MAX_LINE];
27   const char default_name[] = "/.pciids-cache";
28   FILE *f;
29   int lino;
30
31   a->id_cache_status = 1;
32   if (!a->id_cache_file)
33     {
34       /* Construct the default ID cache name */
35       uid_t uid = getuid();
36       struct passwd *pw = getpwuid(uid);
37       if (!pw)
38         return 0;
39       name = pci_malloc(a, strlen(pw->pw_dir) + sizeof(default_name));
40       sprintf(name, "%s%s", pw->pw_dir, default_name);
41       pci_set_id_cache(a, name, 1);
42     }
43   a->debug("Using cache %s\n", a->id_cache_file);
44   if (flags & PCI_LOOKUP_REFRESH_CACHE)
45     {
46       a->debug("Not loading cache, will refresh everything\n");
47       a->id_cache_status = 2;
48       return 0;
49     }
50
51   f = fopen(a->id_cache_file, "rb");
52   if (!f)
53     {
54       a->debug("Cache file does not exist\n");
55       return 0;
56     }
57   /* FIXME: Compare timestamp with the pci.ids file? */
58
59   lino = 0;
60   while (fgets(line, sizeof(line), f))
61     {
62       char *p = strchr(line, '\n');
63       lino++;
64       if (p)
65         {
66           *p = 0;
67           if (lino == 1)
68             {
69               if (strcmp(line, cache_version))
70                 {
71                   a->debug("Unrecognized cache version %s, ignoring\n", line);
72                   break;
73                 }
74               continue;
75             }
76           else
77             {
78               int cat, id1, id2, id3, id4, cnt;
79               if (sscanf(line, "%d%x%x%x%x%n", &cat, &id1, &id2, &id3, &id4, &cnt) >= 5)
80                 {
81                   p = line + cnt;
82                   while (*p && *p == ' ')
83                     p++;
84                   pci_id_insert(a, cat, id1, id2, id3, id4, p, SRC_CACHE);
85                   continue;
86                 }
87             }
88         }
89       a->warning("Malformed cache file %s (line %d), ignoring", a->id_cache_file, lino);
90       break;
91     }
92
93   if (ferror(f))
94     a->warning("Error while reading %s", a->id_cache_file);
95   fclose(f);
96   return 1;
97 }
98
99 void
100 pci_id_cache_dirty(struct pci_access *a)
101 {
102   if (a->id_cache_status >= 1)
103     a->id_cache_status = 2;
104 }
105
106 void
107 pci_id_cache_flush(struct pci_access *a)
108 {
109   int orig_status = a->id_cache_status;
110   FILE *f;
111   unsigned int h;
112   struct id_entry *e, *e2;
113
114   a->id_cache_status = 0;
115   if (orig_status < 2)
116     return;
117   if (!a->id_cache_file)
118     return;
119   f = fopen(a->id_cache_file, "wb");
120   if (!f)
121     {
122       a->warning("Cannot write %s: %s", a->id_cache_file, strerror(errno));
123       return;
124     }
125   a->debug("Writing cache to %s\n", a->id_cache_file);
126   fprintf(f, "%s\n", cache_version);
127
128   for (h=0; h<HASH_SIZE; h++)
129     for (e=a->id_hash[h]; e; e=e->next)
130       if (e->src == SRC_CACHE || e->src == SRC_NET)
131         {
132           /* Verify that every entry is written at most once */
133           for (e2=a->id_hash[h]; e2 != e; e2=e2->next)
134             if ((e2->src == SRC_CACHE || e2->src == SRC_NET) &&
135                 e2->cat == e->cat &&
136                 e2->id12 == e->id12 && e2->id34 == e->id34)
137             break;
138           if (e2 == e)
139             fprintf(f, "%d %x %x %x %x %s\n",
140                     e->cat,
141                     pair_first(e->id12), pair_second(e->id12),
142                     pair_first(e->id34), pair_second(e->id34),
143                     e->name);
144         }
145
146   fflush(f);
147   if (ferror(f))
148     a->warning("Error writing %s", a->id_cache_file);
149   fclose(f);
150 }
151
152 void
153 pci_set_id_cache(struct pci_access *a, char *name, int to_be_freed)
154 {
155   if (a->free_id_cache_file)
156     free(a->id_cache_file);
157   a->id_cache_file = name;
158   a->free_id_cache_file = to_be_freed;
159 }