]> mj.ucw.cz Git - pciutils.git/blob - lib/names-cache.c
MacOS: An attempt to appease compiler picky about attribute placement
[pciutils.git] / lib / names-cache.c
1 /*
2  *      The PCI Library -- ID to Name Cache
3  *
4  *      Copyright (c) 2008--2009 Martin Mares <mj@ucw.cz>
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL v2+.
7  *
8  *      SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include "internal.h"
12 #include "names.h"
13
14 #ifdef PCI_USE_DNS
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <sys/types.h>
21 #include <pwd.h>
22 #include <unistd.h>
23
24 static const char cache_version[] = "#PCI-CACHE-1.0";
25
26 static char *get_cache_name(struct pci_access *a)
27 {
28   char *name, *buf;
29
30   name = pci_get_param(a, "net.cache_name");
31   if (!name || !name[0])
32     return NULL;
33   if (strncmp(name, "~/", 2))
34     return name;
35
36   uid_t uid = getuid();
37   struct passwd *pw = getpwuid(uid);
38   if (!pw)
39     return name;
40
41   buf = pci_malloc(a, strlen(pw->pw_dir) + strlen(name+1) + 1);
42   sprintf(buf, "%s%s", pw->pw_dir, name+1);
43   pci_set_param_internal(a, "net.cache_name", buf, 1);
44   pci_mfree(buf);
45   return pci_get_param(a, "net.cache_name");
46 }
47
48 int
49 pci_id_cache_load(struct pci_access *a, int flags)
50 {
51   char *name;
52   char line[MAX_LINE];
53   FILE *f;
54   int lino;
55
56   a->id_cache_status = 1;
57   name = get_cache_name(a);
58   if (!name)
59     return 0;
60   a->debug("Using cache %s\n", name);
61   if (flags & PCI_LOOKUP_REFRESH_CACHE)
62     {
63       a->debug("Not loading cache, will refresh everything\n");
64       a->id_cache_status = 2;
65       return 0;
66     }
67
68   f = fopen(name, "rb");
69   if (!f)
70     {
71       a->debug("Cache file does not exist\n");
72       return 0;
73     }
74   /* FIXME: Compare timestamp with the pci.ids file? */
75
76   lino = 0;
77   while (fgets(line, sizeof(line), f))
78     {
79       char *p = strchr(line, '\n');
80       lino++;
81       if (p)
82         {
83           *p = 0;
84           if (lino == 1)
85             {
86               if (strcmp(line, cache_version))
87                 {
88                   a->debug("Unrecognized cache version %s, ignoring\n", line);
89                   break;
90                 }
91               continue;
92             }
93           else
94             {
95               int cat, id1, id2, id3, id4, cnt;
96               if (sscanf(line, "%d%x%x%x%x%n", &cat, &id1, &id2, &id3, &id4, &cnt) >= 5)
97                 {
98                   p = line + cnt;
99                   while (*p && *p == ' ')
100                     p++;
101                   pci_id_insert(a, cat, id1, id2, id3, id4, p, SRC_CACHE);
102                   continue;
103                 }
104             }
105         }
106       a->warning("Malformed cache file %s (line %d), ignoring", name, lino);
107       break;
108     }
109
110   if (ferror(f))
111     a->warning("Error while reading %s", name);
112   fclose(f);
113   return 1;
114 }
115
116 void
117 pci_id_cache_flush(struct pci_access *a)
118 {
119   int orig_status = a->id_cache_status;
120   FILE *f;
121   unsigned int h;
122   struct id_entry *e, *e2;
123   char hostname[256], *tmpname, *name;
124   int this_pid;
125
126   a->id_cache_status = 0;
127   if (orig_status < 2)
128     return;
129   name = get_cache_name(a);
130   if (!name)
131     return;
132
133   this_pid = getpid();
134   if (gethostname(hostname, sizeof(hostname)) < 0)
135     hostname[0] = 0;
136   else
137     hostname[sizeof(hostname)-1] = 0;
138   tmpname = pci_malloc(a, strlen(name) + strlen(hostname) + 64);
139   sprintf(tmpname, "%s.tmp-%s-%d", name, hostname, this_pid);
140
141   f = fopen(tmpname, "wb");
142   if (!f)
143     {
144       a->warning("Cannot write to %s: %s", name, strerror(errno));
145       pci_mfree(tmpname);
146       return;
147     }
148   a->debug("Writing cache to %s\n", name);
149   fprintf(f, "%s\n", cache_version);
150
151   for (h=0; h<HASH_SIZE; h++)
152     for (e=a->id_hash[h]; e; e=e->next)
153       if (e->src == SRC_CACHE || e->src == SRC_NET)
154         {
155           /* Negative entries are not written */
156           if (!e->name[0])
157             continue;
158
159           /* Verify that every entry is written at most once */
160           for (e2=a->id_hash[h]; e2 != e; e2=e2->next)
161             if ((e2->src == SRC_CACHE || e2->src == SRC_NET) &&
162                 e2->cat == e->cat &&
163                 e2->id12 == e->id12 && e2->id34 == e->id34)
164             break;
165           if (e2 == e)
166             fprintf(f, "%d %x %x %x %x %s\n",
167                     e->cat,
168                     pair_first(e->id12), pair_second(e->id12),
169                     pair_first(e->id34), pair_second(e->id34),
170                     e->name);
171         }
172
173   fflush(f);
174   if (ferror(f))
175     a->warning("Error writing %s", name);
176   fclose(f);
177
178   if (rename(tmpname, name) < 0)
179     {
180       a->warning("Cannot rename %s to %s: %s", tmpname, name, strerror(errno));
181       unlink(tmpname);
182     }
183   pci_mfree(tmpname);
184 }
185
186 #else
187
188 int pci_id_cache_load(struct pci_access *a UNUSED, int flags UNUSED)
189 {
190   a->id_cache_status = 1;
191   return 0;
192 }
193
194 void pci_id_cache_flush(struct pci_access *a)
195 {
196   a->id_cache_status = 0;
197 }
198
199 #endif
200
201 void
202 pci_id_cache_dirty(struct pci_access *a)
203 {
204   if (a->id_cache_status >= 1)
205     a->id_cache_status = 2;
206 }