Merge branch 'vendor/PAM_PASSWDQC'
[dragonfly.git] / usr.sbin / asf / asf.c
CommitLineData
44faebf9
HP
1/*
2 * Copyright (c) 2002, 2003 Greg Lehey
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * This software is provided by the author ``as is'' and any express
15 * or implied warranties, including, but not limited to, the implied
16 * warranties of merchantability and fitness for a particular purpose
17 * are disclaimed. In no event shall the author be liable for any
18 * direct, indirect, incidental, special, exemplary, or consequential
19 * damages (including, but not limited to, procurement of substitute
20 * goods or services; loss of use, data, or profits; or business
21 * interruption) however caused and on any theory of liability,
22 * whether in contract, strict liability, or tort (including
23 * negligence or otherwise) arising in any way out of the use of this
24 * software, even if advised of the possibility of such damage.
25 */
26/* $Id: asf.c,v 1.6 2003/11/04 06:38:37 green Exp $ */
27/* $FreeBSD: src/usr.sbin/asf/asf.c,v 1.6 2003/11/04 06:38:37 green Exp $ */
2d7f24f1 28/* $DragonFly: src/usr.sbin/asf/asf.c,v 1.8 2008/09/19 17:49:31 swildner Exp $ */
44faebf9
HP
29
30#define MAXLINE 1024
31#include <ctype.h>
32#include <errno.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <sys/file.h>
37#include <sys/param.h>
38#include <sys/stat.h>
39#include <sys/wait.h>
40#include <sys/types.h>
41#include <fts.h>
42#include <unistd.h>
43
44#define MAXTOKEN 10
45const char *modules_path; /* path relative to kernel
46 * build directory */
47const char *outfile; /* and where to write the output */
48
49/*
50 * Take a blank separated list of tokens and turn it into a list of
51 * individual nul-delimited strings. Build a list of pointers at
52 * token, which must have enough space for the tokens. Return the
53 * number of tokens, or -1 on error (typically a missing string
54 * delimiter).
55 */
56static int
57tokenize(char *cptr, char *token[], int maxtoken)
58{
59 char delim; /* delimiter to search for */
60 int tokennr; /* index of this token */
61
62 for (tokennr = 0; tokennr < maxtoken;) {
63 while (isspace(*cptr))
64 cptr++; /* skip initial white space */
65 if ((*cptr == '\0') || (*cptr == '\n')
66 || (*cptr == '#')) /* end of line */
67 return tokennr; /* return number of tokens found */
68 delim = *cptr;
69 token[tokennr] = cptr; /* point to it */
70 tokennr++; /* one more */
71 if (tokennr == maxtoken) /* run off the end? */
72 return tokennr;
73 if ((delim == '\'') || (delim == '"')) { /* delimitered */
74 for (;;) {
75 cptr++;
76 if ((*cptr == delim)
77 && (cptr[-1] != '\\')) { /* found the partner */
78 cptr++; /* move on past */
79 if (!isspace(*cptr)) /* no space after closing quote */
80 return -1;
81 *cptr++ = '\0'; /* delimit */
82 } else if ((*cptr == '\0')
83 || (*cptr == '\n')) /* end of line */
84 return -1;
85 }
86 } else { /* not quoted */
87 while ((*cptr != '\0') && (!isspace(*cptr)) && (*cptr != '\n'))
88 cptr++;
89 if (*cptr != '\0') /* not end of the line, */
90 *cptr++ = '\0'; /* delimit and move to the next */
91 }
92 }
93 return maxtoken; /* can't get here */
94}
95
96static char *
97findmodule(char *modules_path, const char *module_name)
98{
99 char *const path_argv[2] = { modules_path, NULL };
100 char *module_path = NULL;
101 int module_name_len = strlen(module_name);
102 FTS *fts;
103 FTSENT *ftsent;
104
105 if (modules_path == NULL) {
106 fprintf(stderr,
107 "Can't allocate memory to traverse a path: %s (%d)\n",
108 strerror(errno),
109 errno);
110 exit(1);
111 }
112 fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
113 if (fts == NULL) {
114 fprintf(stderr,
115 "Can't begin traversing path %s: %s (%d)\n",
116 modules_path,
117 strerror(errno),
118 errno);
119 exit(1);
120 }
121 while ((ftsent = fts_read(fts)) != NULL) {
122 if (ftsent->fts_info == FTS_DNR ||
123 ftsent->fts_info == FTS_ERR ||
124 ftsent->fts_info == FTS_NS) {
125 fprintf(stderr,
126 "Error while traversing path %s: %s (%d)\n",
127 modules_path,
128 strerror(errno),
129 errno);
130 exit(1);
131 }
132 if (ftsent->fts_info != FTS_F ||
133 ftsent->fts_namelen != module_name_len ||
134 memcmp(module_name, ftsent->fts_name, module_name_len) != 0)
135 continue;
136 if (asprintf(&module_path,
137 "%.*s",
138 ftsent->fts_pathlen,
139 ftsent->fts_path) == -1) {
140 fprintf(stderr,
141 "Can't allocate memory traversing path %s: %s (%d)\n",
142 modules_path,
143 strerror(errno),
144 errno);
145 exit(1);
146 }
147 break;
148 }
149 if (ftsent == NULL && errno != 0) {
150 fprintf(stderr,
151 "Couldn't complete traversing path %s: %s (%d)\n",
152 modules_path,
153 strerror(errno),
154 errno);
155 exit(1);
156 }
157 fts_close(fts);
158 free(modules_path);
159 return (module_path);
160}
161
162static void
163usage(const char *myname)
164{
165 fprintf(stderr,
166 "Usage:\n"
440dfd90 167 "%s [-a] [-f] [-k] [modules-path [outfile]]\n\n"
44faebf9
HP
168 "\t-a\tappend to outfile)\n"
169 "\t-f\tfind the module in any subdirectory of module-path\n"
440dfd90 170 "\t-k\ttake input from kldstat(8)\n",
44faebf9
HP
171 myname);
172}
173
174int
175main(int argc, char *argv[])
176{
177 char buf[MAXLINE];
178 FILE *kldstat;
179 FILE *objcopy;
180 FILE *out; /* output file */
181 char ocbuf[MAXLINE];
182 int tokens; /* number of tokens on line */
2d7f24f1 183 int ch;
44faebf9
HP
184 const char *filemode = "w"; /* mode for outfile */
185 char cwd[MAXPATHLEN]; /* current directory */
44faebf9 186 char *token[MAXTOKEN];
44faebf9
HP
187 int dofind = 0;
188
189 getcwd(cwd, MAXPATHLEN); /* find where we are */
190 kldstat = stdin;
9f7ce2c1
SS
191 while ((ch = getopt(argc, argv, "afks")) != -1) {
192 switch (ch) {
193 case 'k': /* get input from kldstat(8) */
194 if (!(kldstat = popen("kldstat", "r"))) {
195 perror("Can't start kldstat");
44faebf9
HP
196 return 1;
197 }
9f7ce2c1
SS
198 break;
199 case 'a': /* append to outfile */
200 filemode = "a";
201 break;
9f7ce2c1
SS
202 case 'f': /* find .ko (recursively) */
203 dofind = 1;
204 break;
205 default:
44faebf9
HP
206 usage(argv[0]);
207 return 1;
208 }
209 }
9f7ce2c1
SS
210
211 argv += optind;
212 argc -= optind;
213
214 if (argc >= 1) {
215 modules_path = argv[0];
216 argc--;
217 argv++;
218 }
219
220 if (argc >= 1) {
221 outfile = argv[0];
222 argc--;
223 argv++;
224 }
225
226 if (argc > 0) {
227 fprintf(stderr,
228 "Extraneous startup information: \"%s\", aborting\n",
229 argv[0]);
230 usage(getprogname());
231 return 1;
232 }
44faebf9 233 if (modules_path == NULL)
8e1c6f81 234 modules_path = "/boot/modules";
44faebf9
HP
235 if (outfile == NULL)
236 outfile = ".asf";
237 if ((out = fopen(outfile, filemode)) == NULL) {
238 fprintf(stderr,
239 "Can't open output file %s: %s (%d)\n",
240 outfile,
241 strerror(errno),
242 errno);
243 return 1;
244 }
245 while (fgets(buf, MAXLINE, kldstat)) {
246 if ((!(strstr(buf, "kernel")))
247 && buf[0] != 'I') {
248 quad_t base;
249 quad_t textaddr;
250 quad_t dataaddr;
251 quad_t bssaddr;
252
253 tokens = tokenize(buf, token, MAXTOKEN);
34ba3f53
MD
254 if (tokens <= 1)
255 continue;
44faebf9
HP
256 base = strtoll(token[2], NULL, 16);
257 if (!dofind) {
44faebf9
HP
258 snprintf(ocbuf,
259 MAXLINE,
440dfd90 260 "/usr/bin/objdump --section-headers %s/%s",
44faebf9 261 modules_path,
9f7ce2c1 262 token[4]);
44faebf9
HP
263 } else {
264 char *modpath;
265
266 modpath = findmodule(strdup(modules_path), token[4]);
267 if (modpath == NULL)
268 continue;
269 snprintf(ocbuf,
270 MAXLINE,
9f7ce2c1
SS
271 "/usr/bin/objdump --section-headers %s",
272 modpath);
44faebf9
HP
273 free(modpath);
274 }
275 if (!(objcopy = popen(ocbuf, "r"))) {
276 fprintf(stderr,
277 "Can't start %s: %s (%d)\n",
278 ocbuf,
279 strerror(errno),
280 errno);
281 return 1;
282 }
283 while (fgets(ocbuf, MAXLINE, objcopy)) {
284 int octokens;
285 char *octoken[MAXTOKEN];
286
287 octokens = tokenize(ocbuf, octoken, MAXTOKEN);
288 if (octokens > 1) {
289 if (!strcmp(octoken[1], ".text"))
290 textaddr = strtoll(octoken[3], NULL, 16) + base;
291 else if (!strcmp(octoken[1], ".data"))
292 dataaddr = strtoll(octoken[3], NULL, 16) + base;
293 else if (!strcmp(octoken[1], ".bss"))
294 bssaddr = strtoll(octoken[3], NULL, 16) + base;
295 }
296 }
297 if (textaddr) { /* we must have a text address */
298 if (!dofind) {
299 fprintf(out,
440dfd90 300 "add-symbol-file %s%s%s/%s 0x%llx",
9f7ce2c1
SS
301 modules_path[0] != '/' ? cwd : "",
302 modules_path[0] != '/' ? "/" : "",
44faebf9 303 modules_path,
44faebf9 304 token[4],
44faebf9
HP
305 textaddr);
306 } else {
307 char *modpath;
9f7ce2c1 308
44faebf9
HP
309 modpath = findmodule(strdup(modules_path), token[4]);
310 if (modpath == NULL)
311 continue;
312 fprintf(out,
9f7ce2c1 313 "add-symbol-file %s 0x%llx",
44faebf9 314 modpath,
44faebf9
HP
315 textaddr);
316 free(modpath);
317 }
318 if (dataaddr)
319 fprintf(out, " -s .data 0x%llx", dataaddr);
320 if (bssaddr)
321 fprintf(out, " -s .bss 0x%llx", bssaddr);
322 fprintf(out, "\n");
323 }
324 }
325 }
326 return 0;
327}