string: Improve fortify with clang
[glibc.git] / nscd / cachedumper.c
blob0d6c1c99ce584382670d4c6cf3fa34010548f2e2
1 /* Copyright (c) 2020-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published
6 by the Free Software Foundation; version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <https://www.gnu.org/licenses/>. */
17 /* cachedumper - dump a human-readable representation of a cache file. */
19 #include <ctype.h>
20 #include <stdio.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <libintl.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/mman.h>
27 #include <arpa/inet.h>
28 #include <getopt.h>
29 #include <sys/param.h>
31 #include "nscd.h"
32 #include "dbg_log.h"
34 static void *the_cache;
36 #define NO_REF ((ref_t) -1)
38 /* Given a chunk of raw data CP of length LEN, print it in a hopefully
39 user-readable format, including colorizing non-readable characters.
40 STR prefixes it, if non-NULL. If LEN is -1, CP is
41 NUL-terminated. */
42 unsigned char *
43 data_string (unsigned char *cp, const char *str, int len)
45 int oops = 0;
46 unsigned char *cpe = cp + len;
47 printf ("%s", str);
48 while (len == -1 || cp < cpe)
50 if (isgraph (*cp))
51 putchar (*cp);
52 else
53 printf ("\033[%dm<%02x>\033[0m", *cp % 6 + 31, *cp);
54 if (len == -1 && *cp == 0)
55 return cp + 1;
57 ++cp;
58 if (++oops > 1000)
59 break;
61 return cp;
64 void
65 nscd_print_cache (const char *name)
67 struct stat st;
68 int fd;
69 int i;
71 if (stat (name, &st) < 0)
73 perror (name);
74 exit (1);
77 fd = open (name, O_RDONLY);
79 the_cache = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
81 struct database_pers_head *dps = (struct database_pers_head *) the_cache;
83 /* Shortcut for "print the cache offset (address) of X in the
84 cache". */
85 #define A(x) (int) ((char *) &(x) - (char *) the_cache)
87 /* Common code for "print field DPS->F, it's offset, and contents". */
88 #define DPS(f) printf("%08x: %24s : %10d %08x\n", A (dps->f), #f, (int) dps->f, (int) dps->f);
90 if (debug_level > 0)
92 DPS (version);
93 DPS (header_size);
94 DPS (gc_cycle);
95 DPS (nscd_certainly_running);
96 DPS (timestamp);
97 DPS (module);
98 DPS (data_size);
99 DPS (first_free);
100 DPS (nentries);
101 DPS (maxnentries);
102 DPS (maxnsearched);
103 DPS (poshit);
104 DPS (neghit);
105 DPS (posmiss);
106 DPS (negmiss);
107 DPS (rdlockdelayed);
108 DPS (wrlockdelayed);
109 DPS (addfailed);
110 printf ("\n");
114 char *data = (char *) &dps->array[roundup (dps->module,
115 ALIGN / sizeof (ref_t))];
117 /* Loop through each entry in the hash table, which is of size
118 dps->module. Raw data is stored after the hash table in the
119 cache file. */
120 for (i = 0; i < dps->module; i++)
122 ref_t r = dps->array[i];
123 if (r == NO_REF)
124 continue;
126 if (debug_level > 2)
127 printf ("hash[%4d] = 0x%x\n", i, r);
129 while (r != NO_REF)
131 struct hashentry *here = (struct hashentry *) (data + r);
133 unsigned char *key = (unsigned char *) data + here->key;
135 printf ("\n%08x: type %s key %p \"", A (*here),
136 serv2str[here->type], key);
138 data_string (key, "", here->len);
140 struct datahead *dh = (struct datahead *) (data + here->packet);
141 printf ("\" (len:%ld) Data %08lx\n", (long) here->len,
142 (long unsigned int) ((char *) dh - (char *) the_cache));
144 if (debug_level > 0)
146 /* Common code for printing fields in struct DATAHEAD DH. */
147 #define DH(f) printf ("%08x; %24s : %10d %08x\n", A (dh->f), #f, (int) dh->f, (int) dh->f);
148 DH (allocsize);
149 DH (recsize);
150 DH (timeout);
151 DH (notfound);
152 DH (nreloads);
153 DH (usable);
154 DH (unused);
155 DH (ttl);
158 unsigned char *cp = (unsigned char *) (&dh->data[0]);
159 unsigned char *cpe =
160 (unsigned char *) (&dh->data[0]) + dh->allocsize;
163 int i;
164 uint32_t *grplens;
166 if (debug_level > 1)
168 data_string (cp, _(" - all data: "), cpe - cp);
169 printf ("\n");
172 /* These two are common to all responses. */
173 printf ("V%d F%d",
174 dh->data[0].pwdata.version, dh->data[0].pwdata.found);
176 /* Shortcut for the common case where we iterate through
177 fixed-length strings stored in the data portion of the
178 cache. CP is updated to point to the next string. */
179 #define DSTR(str, l) cp = data_string (cp, str, l)
181 switch (here->type)
183 case GETPWBYNAME:
184 case GETPWBYUID:
186 pw_response_header *pw = &(dh->data[0].pwdata);
187 cp += sizeof (*pw);
188 DSTR (" name ", pw->pw_name_len);
189 DSTR (" passwd ", pw->pw_passwd_len);
190 printf (" uid %d gid %d", pw->pw_uid, pw->pw_gid);
191 DSTR (" gecos ", pw->pw_gecos_len);
192 DSTR (" dir ", pw->pw_dir_len);
193 DSTR (" shell ", pw->pw_shell_len);
194 DSTR (" byuid ", -1);
195 DSTR (" key ", -1);
196 printf ("\n");
198 break;
200 case GETGRBYNAME:
201 case GETGRBYGID:
203 gr_response_header *gr = &(dh->data[0].grdata);
204 cp += sizeof (*gr);
205 grplens = (uint32_t *) cp;
206 cp += gr->gr_mem_cnt * sizeof (uint32_t);
207 DSTR (" name ", gr->gr_name_len);
208 DSTR (" passwd ", gr->gr_passwd_len);
209 printf (" gid %d members %d [ ", (int) gr->gr_gid,
210 (int) gr->gr_mem_cnt);
211 for (i = 0; i < gr->gr_mem_cnt; i++)
212 DSTR (" ", grplens[i]);
213 DSTR (" ] bygid ", -1);
214 DSTR (" key ", -1);
215 printf ("\n");
217 break;
219 case GETHOSTBYADDR:
220 case GETHOSTBYADDRv6:
221 case GETHOSTBYNAME:
222 case GETHOSTBYNAMEv6:
224 hst_response_header *hst = &(dh->data[0].hstdata);
225 printf (" addrtype %d error %d", hst->h_addrtype, hst->error);
226 cp += sizeof (*hst);
227 DSTR (" name ", hst->h_name_len);
228 uint32_t *aliases_len = (uint32_t *) cp;
229 cp += hst->h_aliases_cnt * sizeof (uint32_t);
230 uint32_t *addrs = (uint32_t *) cp;
231 cp += hst->h_length * hst->h_addr_list_cnt;
233 if (hst->h_aliases_cnt)
235 printf (" aliases [");
236 for (i = 0; i < hst->h_aliases_cnt; i++)
237 DSTR (" ", aliases_len[i]);
238 printf (" ]");
240 if (hst->h_addr_list_cnt)
242 char buf[INET6_ADDRSTRLEN];
243 printf (" addresses [");
244 for (i = 0; i < hst->h_addr_list_cnt; i++)
246 inet_ntop (hst->h_addrtype, addrs, buf, sizeof (buf));
247 printf (" %s", buf);
248 addrs += hst->h_length;
250 printf (" ]");
253 printf ("\n");
255 break;
257 case GETAI:
259 ai_response_header *ai = &(dh->data[0].aidata);
260 printf (" naddrs %ld addrslen %ld canonlen %ld error %d [",
261 (long) ai->naddrs, (long) ai->addrslen,
262 (long) ai->canonlen, ai->error);
263 cp += sizeof (*ai);
264 unsigned char *addrs = cp;
265 unsigned char *families = cp + ai->addrslen;
266 cp = families + ai->naddrs;
267 char buf[INET6_ADDRSTRLEN];
269 for (i = 0; i < ai->naddrs; i++)
271 switch (*families)
273 case AF_INET:
274 inet_ntop (*families, addrs, buf, sizeof (buf));
275 printf (" %s", buf);
276 addrs += 4;
277 break;
278 case AF_INET6:
279 inet_ntop (*families, addrs, buf, sizeof (buf));
280 printf (" %s", buf);
281 addrs += 16;
282 break;
284 families++;
286 DSTR (" ] canon ", ai->canonlen);
287 DSTR (" key ", -1);
288 printf ("\n");
290 break;
292 case INITGROUPS:
294 initgr_response_header *ig = &(dh->data[0].initgrdata);
295 printf (" nresults %d groups [", (int) ig->ngrps);
296 cp += sizeof (*ig);
297 grplens = (uint32_t *) cp;
298 cp += ig->ngrps * sizeof (uint32_t);
299 for (i = 0; i < ig->ngrps; i++)
300 printf (" %d", grplens[i]);
301 DSTR (" ] key ", -1);
302 printf ("\n");
304 break;
306 case GETSERVBYNAME:
307 case GETSERVBYPORT:
309 serv_response_header *serv = &(dh->data[0].servdata);
310 printf (" alias_cnt %ld port %d (stored as %d)",
311 (long) serv->s_aliases_cnt,
312 ((serv->s_port & 0xff00) >> 8) | ((serv->
313 s_port & 0xff) <<
314 8), serv->s_port);
315 cp += sizeof (*serv);
316 DSTR (" name ", serv->s_name_len);
317 DSTR (" proto ", serv->s_proto_len);
318 if (serv->s_aliases_cnt)
320 uint32_t *alias_len = (uint32_t *) cp;
321 printf (" aliases [");
322 cp += sizeof (uint32_t) * serv->s_aliases_cnt;
323 for (i = 0; i < serv->s_aliases_cnt; i++)
324 DSTR (" ", alias_len[i]);
325 printf (" ]");
327 printf ("\n");
329 break;
331 case GETNETGRENT:
333 netgroup_response_header *ng = &(dh->data[0].netgroupdata);
334 printf (" nresults %d len %d\n",
335 (int) ng->nresults, (int) ng->result_len);
336 cp += sizeof (*ng);
337 for (i = 0; i < ng->nresults; i++)
339 DSTR (" (", -1);
340 DSTR (",", -1);
341 DSTR (",", -1);
342 printf (")");
344 printf ("\n");
346 break;
348 case INNETGR:
350 innetgroup_response_header *ing =
351 &(dh->data[0].innetgroupdata);
352 printf (" result %d\n", ing->result);
354 break;
356 default:
357 break;
360 if (debug_level > 2 && cp && cp < cpe)
362 printf (_(" - remaining data %p: "), cp);
363 data_string (cp, "", cpe - cp);
364 printf ("\n");
368 r = here->next;
372 munmap (the_cache, st.st_size);
374 exit (0);