|
|
1.1 root 1: /**
2: * strings -- prints out all the character strings in an executable file.
3: *
4: * Usage: strings [-xaop] [-nnn] [file ...]
5: *
6: * Options:
7: * -x print offset of each string in the file in hex
8: * -a print offset of each string in the file in ASCII
9: * -o print offset of each string in the file in octal
10: * -p mask out the parity bit
11: */
12:
13: #include <sys/stat.h>
14: #include <l.out.h>
15: #include <stdio.h>
16: #include <canon.h>
17: #include <ctype.h>
18:
19: /* The lamentable <rico.h>... */
20: #define bool char
21: #define TRUE (0 == 0)
22: #define FALSE (!TRUE)
23:
24: int nchars = 4; /* minimum character string length */
25:
26: bool flag; /* input condition: FALSE for redirection, else TRUE */
27: bool aflag; /* option flags: ascii line numbering */
28: bool xflag; /* hex line numbering */
29: bool oflag; /* octal line numbering */
30:
31: int pbit; /* parity bit mask */
32: long addr; /* current seek position in data space segment */
33: long count; /* size of data space segment */
34: char * buff; /* string to store beginning NCHARS
35: characters in character string */
36: bool printstr();
37: bool lookfor();
38:
39: extern FILE * freopen();
40: extern char * malloc();
41:
42:
43: main( argc, argv )
44:
45: int argc;
46: char * argv[];
47:
48: {
49: char * malloc();
50: char * s;
51:
52: while( (--argc > 0) && ((*++argv)[0] == '-') ) {
53:
54: /*
55: * Read options declared.
56: */
57: for( s = argv[0] + 1 ; *s != '\0'; s++ ) {
58:
59: /*
60: * Set minimum string length for recognizing
61: * character strings.
62: */
63: if( isdigit( *s ) ) {
64: if( (nchars = atoi( s )) <= 0 )
65: fatal( "string length must be greater than 0" );
66:
67: break;
68: }
69:
70: /*
71: * Set appropriate flags or bit mask according to
72: * option declared.
73: */
74: switch( *s ) {
75:
76: case 'x':
77: if( aflag | oflag | xflag )
78: usage();
79:
80: xflag = TRUE;
81: break;
82:
83: case 'a':
84: if( aflag | oflag | xflag )
85: usage();
86:
87: aflag = TRUE;
88: break;
89:
90: case 'o':
91: if( aflag | oflag | xflag )
92: usage();
93:
94: oflag = TRUE;
95: break;
96:
97: case 'p':
98: pbit = 0200;
99: break;
100:
101: default:
102: usage();
103: }
104: }
105: }
106:
107: /*
108: * Get memory for string buffer.
109: */
110: if( (buff = malloc( nchars )) == NULL )
111: fatal( "not enough memory" );
112:
113: /*
114: * Set input condition:
115: * FALSE if input is through indirection, else TRUE.
116: */
117: if( argc > 0 )
118: flag = TRUE;
119: else {
120: argc++;
121: flag = FALSE;
122: }
123:
124: /*
125: * Examine each file for strings of the required length.
126: */
127: while( argc-- ) {
128:
129: /*
130: * Test for read permission in file.
131: */
132: if( flag && freopen( *argv, "r", stdin ) == NULL )
133: fatal( "can't open %s", argv[0] );
134:
135: /*
136: * Test if file is an executable file.
137: */
138: if( checklout( stdin ) < 0 ) {
139: if( flag ) {
140: fprintf( stderr, "strings: '%s' not executable\n", *argv);
141: ++argv;
142: continue;
143: }
144: else {
145: fprintf( stderr, "strings: not executable\n" );
146: exit( 1 );
147: }
148: }
149:
150: /*
151: * Display file name if available.
152: */
153: if( flag )
154: fprintf( stderr, "%s:\n", *argv );
155:
156: /*
157: * Display all character strings in file.
158: */
159: while( printstr() )
160: ;
161:
162: ++argv;
163: }
164:
165: free( buff );
166: exit( 0 );
167: }
168:
169: /**
170: * bool
171: * printstr()
172: *
173: * Input: None.
174: *
175: * Action: Display character strings in file.
176: *
177: * Return: FALSE on error or no character strings available,
178: * otherwise TRUE.
179: *
180: * Note: None.
181: *
182: */
183:
184: bool
185: printstr()
186:
187: {
188: char c;
189: char * p;
190: char * q;
191:
192: p = buff;
193: q = p + nchars;
194:
195: /*
196: * Check if character strings are available in file.
197: */
198: if( ! lookfor() )
199: return( FALSE );
200:
201: /*
202: * Display line number according to the format option specified.
203: * Ignore if no format option is set.
204: */
205: if( aflag )
206: printf( "%-6D: ", addr-nchars );
207:
208: else if( oflag )
209: printf( "0%-6O: ", addr-nchars );
210:
211: else if( xflag )
212: printf( "0x%-6X: ", addr-nchars );
213:
214: /*
215: * Display printable characters found.
216: */
217: do {
218: putchar( *p++ );
219: } while( p < q );
220:
221: /*
222: * Display remaining printable characters in file.
223: */
224: for ( ;; ) {
225: if( --count <= 0L )
226: return( FALSE );
227:
228: ++addr;
229: c = getchar();
230:
231: if( c == EOF )
232: return( FALSE );
233:
234: if( ! (isascii( (c) & ~pbit ) && isprint( (c) & ~pbit )) )
235: break;
236:
237: putchar( c );
238: }
239:
240: putchar( '\n' );
241: return( TRUE );
242: }
243:
244: /**
245: * bool
246: * lookfor()
247: *
248: * Input: None.
249: *
250: * Action: Look for the first character string in file.
251: *
252: * Return: TRUE if a character string is found, else FALSE.
253: *
254: * Note: None.
255: *
256: */
257:
258: bool
259: lookfor()
260:
261: {
262: char c;
263: char * p;
264: char * q;
265:
266: q = buff + nchars;
267:
268: for( ;; ) {
269:
270: /*
271: * Seek in data space segment of file until a printable
272: * character is encountered.
273: */
274: do {
275: if( --count <= 0L )
276: return( FALSE );
277:
278: ++addr;
279: c = getchar();
280:
281: if( c == EOF )
282: return( FALSE );
283:
284: } while( ! (isascii( (c) & ~pbit ) && isprint( (c) & ~pbit )) );
285:
286: p = buff;
287:
288: /*
289: * Check for valid character string.
290: */
291: do {
292: *p++ = c;
293:
294: if( p >= q )
295: return( TRUE );
296:
297: if( --count <= 0L )
298: return( FALSE );
299:
300: ++addr;
301: c = getchar();
302:
303: if( c == EOF )
304: return( FALSE );
305:
306: } while( isascii( (c) & ~pbit ) && isprint( (c) & ~pbit ) );
307: }
308: }
309:
310:
311: /**
312: * int
313: * checklout( f )
314: *
315: * register FILE * f;
316: *
317: * Input: f - file pointer to stdin.
318: *
319: * Action: Check if executable (l.out) file.
320: *
321: * Return: Returns -1 on error or file is not executable, otherwise 0.
322: *
323: * Note: None.
324: *
325: */
326:
327: int
328: checklout( f )
329:
330: register FILE * f;
331:
332: {
333: register int i; /* counter variable */
334: int ret = -1; /* returning error value */
335: struct stat s; /* file attributes */
336: struct ldheader l; /* file header information */
337:
338: if( fstat( fileno( f ), &s ) == -1 )
339: return( ret );
340:
341: /*
342: * File type check. Return unless regular file.
343: */
344: if( (s.st_mode & S_IFMT) != S_IFREG )
345: return( ret );
346:
347: /*
348: * Get file header information.
349: */
350: if( fread( &l, sizeof( l ), 1, f ) != 1 ) {
351: rewind( f );
352: return( ret );
353: }
354:
355: rewind( f );
356:
357: if( l.l_magic != L_MAGIC )
358: return( ret );
359:
360: /*
361: * Correct canonical effect on file format information.
362: */
363: for( i = 0 ; i < NLSEG ; ++i )
364: canlong(l.l_ssize[i]);
365:
366: /*
367: * Get seek position to the beginning memory location of the
368: * data space segment in the executable file.
369: */
370: fseek( f, (long)sizeof(l) + l.l_ssize[L_SHRI] + l.l_ssize[L_PRVI], 0 );
371: addr = ftell( f );
372:
373: /*
374: * Get size of data space segment of file.
375: */
376: count = l.l_ssize[L_SHRD] + l.l_ssize[L_PRVD];
377:
378: if( count == 0L ) {
379: fatal( "zero-length data segments" );
380: /* NOTREACHED */
381: }
382:
383: ++count;
384: return( 0 );
385: }
386:
387: /**
388: * void
389: * fatal( arg0 )
390: *
391: * char * arg0;
392: *
393: * Input: arg0 - pointer to string containing the error message.
394: *
395: * Action: Display fatal error message and exit.
396: *
397: * Return: Never return, always exit.
398: *
399: * Note: None.
400: *
401: */
402:
403: fatal( arg0 )
404:
405: char * arg0;
406:
407: {
408: fflush( stdout );
409: fprintf( stderr, "strings: %r\n", &arg0 );
410: exit( 1 );
411: }
412:
413: /**
414: * void
415: * usage()
416: *
417: * Input: None.
418: *
419: * Action: Display command usage format.
420: *
421: * Return: Never return, always exit.
422: *
423: * Note: None.
424: *
425: */
426:
427: usage()
428:
429: {
430: fprintf( stderr, "Usage: strings [-xaop] [-nnn] [file ...]\n" );
431: exit( 1 );
432: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.