]>
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); | |
7220de95 | 41 | pci_set_param_internal(a, "net.cache_name", buf, 1); |
cd10d1d1 MM |
42 | pci_mfree(buf); |
43 | return pci_get_param(a, "net.cache_name"); | |
98ccf6d6 MM |
44 | } |
45 | ||
752d4d9a MM |
46 | int |
47 | pci_id_cache_load(struct pci_access *a, int flags) | |
48 | { | |
49 | char *name; | |
50 | char line[MAX_LINE]; | |
752d4d9a MM |
51 | FILE *f; |
52 | int lino; | |
53 | ||
54 | a->id_cache_status = 1; | |
98ccf6d6 MM |
55 | name = get_cache_name(a); |
56 | if (!name) | |
57 | return 0; | |
58 | a->debug("Using cache %s\n", name); | |
752d4d9a MM |
59 | if (flags & PCI_LOOKUP_REFRESH_CACHE) |
60 | { | |
61 | a->debug("Not loading cache, will refresh everything\n"); | |
62 | a->id_cache_status = 2; | |
63 | return 0; | |
64 | } | |
65 | ||
98ccf6d6 | 66 | f = fopen(name, "rb"); |
752d4d9a MM |
67 | if (!f) |
68 | { | |
69 | a->debug("Cache file does not exist\n"); | |
70 | return 0; | |
71 | } | |
72 | /* FIXME: Compare timestamp with the pci.ids file? */ | |
73 | ||
74 | lino = 0; | |
75 | while (fgets(line, sizeof(line), f)) | |
76 | { | |
77 | char *p = strchr(line, '\n'); | |
78 | lino++; | |
79 | if (p) | |
80 | { | |
81 | *p = 0; | |
82 | if (lino == 1) | |
83 | { | |
84 | if (strcmp(line, cache_version)) | |
85 | { | |
86 | a->debug("Unrecognized cache version %s, ignoring\n", line); | |
87 | break; | |
88 | } | |
89 | continue; | |
90 | } | |
91 | else | |
92 | { | |
93 | int cat, id1, id2, id3, id4, cnt; | |
94 | if (sscanf(line, "%d%x%x%x%x%n", &cat, &id1, &id2, &id3, &id4, &cnt) >= 5) | |
95 | { | |
96 | p = line + cnt; | |
97 | while (*p && *p == ' ') | |
98 | p++; | |
99 | pci_id_insert(a, cat, id1, id2, id3, id4, p, SRC_CACHE); | |
100 | continue; | |
101 | } | |
102 | } | |
103 | } | |
98ccf6d6 | 104 | a->warning("Malformed cache file %s (line %d), ignoring", name, lino); |
752d4d9a MM |
105 | break; |
106 | } | |
107 | ||
108 | if (ferror(f)) | |
98ccf6d6 | 109 | a->warning("Error while reading %s", name); |
752d4d9a MM |
110 | fclose(f); |
111 | return 1; | |
112 | } | |
113 | ||
752d4d9a MM |
114 | void |
115 | pci_id_cache_flush(struct pci_access *a) | |
116 | { | |
117 | int orig_status = a->id_cache_status; | |
118 | FILE *f; | |
119 | unsigned int h; | |
120 | struct id_entry *e, *e2; | |
98ccf6d6 | 121 | char hostname[256], *tmpname, *name; |
61bc0b58 | 122 | int this_pid; |
752d4d9a MM |
123 | |
124 | a->id_cache_status = 0; | |
125 | if (orig_status < 2) | |
126 | return; | |
98ccf6d6 MM |
127 | name = get_cache_name(a); |
128 | if (!name) | |
752d4d9a | 129 | return; |
61bc0b58 MM |
130 | |
131 | this_pid = getpid(); | |
132 | if (gethostname(hostname, sizeof(hostname)) < 0) | |
133 | hostname[0] = 0; | |
134 | else | |
135 | hostname[sizeof(hostname)-1] = 0; | |
98ccf6d6 MM |
136 | tmpname = pci_malloc(a, strlen(name) + strlen(hostname) + 64); |
137 | sprintf(tmpname, "%s.tmp-%s-%d", name, hostname, this_pid); | |
61bc0b58 MM |
138 | |
139 | f = fopen(tmpname, "wb"); | |
752d4d9a MM |
140 | if (!f) |
141 | { | |
98ccf6d6 | 142 | a->warning("Cannot write to %s: %s", name, strerror(errno)); |
61bc0b58 | 143 | pci_mfree(tmpname); |
752d4d9a MM |
144 | return; |
145 | } | |
98ccf6d6 | 146 | a->debug("Writing cache to %s\n", name); |
752d4d9a MM |
147 | fprintf(f, "%s\n", cache_version); |
148 | ||
149 | for (h=0; h<HASH_SIZE; h++) | |
150 | for (e=a->id_hash[h]; e; e=e->next) | |
151 | if (e->src == SRC_CACHE || e->src == SRC_NET) | |
152 | { | |
61bc0b58 MM |
153 | /* Negative entries are not written */ |
154 | if (!e->name[0]) | |
155 | continue; | |
156 | ||
752d4d9a MM |
157 | /* Verify that every entry is written at most once */ |
158 | for (e2=a->id_hash[h]; e2 != e; e2=e2->next) | |
159 | if ((e2->src == SRC_CACHE || e2->src == SRC_NET) && | |
160 | e2->cat == e->cat && | |
161 | e2->id12 == e->id12 && e2->id34 == e->id34) | |
162 | break; | |
163 | if (e2 == e) | |
164 | fprintf(f, "%d %x %x %x %x %s\n", | |
165 | e->cat, | |
166 | pair_first(e->id12), pair_second(e->id12), | |
167 | pair_first(e->id34), pair_second(e->id34), | |
168 | e->name); | |
169 | } | |
170 | ||
171 | fflush(f); | |
172 | if (ferror(f)) | |
98ccf6d6 | 173 | a->warning("Error writing %s", name); |
752d4d9a | 174 | fclose(f); |
61bc0b58 | 175 | |
98ccf6d6 | 176 | if (rename(tmpname, name) < 0) |
61bc0b58 | 177 | { |
98ccf6d6 | 178 | a->warning("Cannot rename %s to %s: %s", tmpname, name, strerror(errno)); |
61bc0b58 MM |
179 | unlink(tmpname); |
180 | } | |
181 | pci_mfree(tmpname); | |
752d4d9a MM |
182 | } |
183 | ||
94d1b5e0 MM |
184 | #else |
185 | ||
186 | int pci_id_cache_load(struct pci_access *a UNUSED, int flags UNUSED) | |
187 | { | |
188 | a->id_cache_status = 1; | |
189 | return 0; | |
190 | } | |
191 | ||
192 | void pci_id_cache_flush(struct pci_access *a) | |
193 | { | |
194 | a->id_cache_status = 0; | |
195 | } | |
196 | ||
197 | #endif | |
198 | ||
199 | void | |
200 | pci_id_cache_dirty(struct pci_access *a) | |
201 | { | |
202 | if (a->id_cache_status >= 1) | |
203 | a->id_cache_status = 2; | |
204 | } |