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