source: rtems/tools/build/eolstrip.c @ c218d01d

5
Last change on this file since c218d01d was c218d01d, checked in by Joel Sherrill <joel@…>, on 03/13/17 at 15:42:24

tools/build/eolstrip.c: Use snprintf() to avoid potential buffer overflow

This was spotted by Coverity Scan.

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/*
2 *  eolstrip - strip white space from end of lines
3 *
4 *  This program strips the white space from the end of every line in the
5 *  specified program.
6 *
7 *  usage:  eolstrip  [ -v ] [ arg ... ] files...
8 *           -v          -- verbose
9 */
10
11#define GETOPTARGS "vt"
12
13char *USAGE = "\
14usage:  cklength  [ -v ] [ arg ... ] files... \n\
15            -v          -- verbose\n\
16            -t          -- test only .. DO NOT OVERWRITE FILE!!!\n\
17\n\
18Strip the white space from the end of every line on the list of files.\n\
19";
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <fcntl.h>
24#include <ctype.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include <string.h>
28#include <memory.h>
29#include <stdarg.h>
30#include <errno.h>
31
32#include "config.h"
33
34#ifndef VMS
35#ifndef HAVE_STRERROR
36extern int sys_nerr;
37extern char *sys_errlist[];
38
39#define strerror( _err ) \
40  ((_err) < sys_nerr) ? sys_errlist [(_err)] : "unknown error"
41
42#else   /* HAVE_STRERROR */
43char *strerror ();
44#endif
45#else   /* VMS */
46char *strerror (int,...);
47#endif
48
49
50#define BUFFER_SIZE     2048
51#define MAX_PATH        2048
52
53#define SUCCESS         0
54#define FAILURE         -1
55#define Failed(x)       (((int) (x)) == FAILURE)
56#define TRUE    1
57#define FALSE   0
58#define STREQ(a,b)      (strcmp(a,b) == 0)
59#define NUMELEMS(arr)   (sizeof(arr) / sizeof(arr[0]))
60
61/*
62 * Definitions for unsigned "ints"; especially for use in data structures
63 *  that will be shared among (potentially) different cpu's (we punt on
64 *  byte ordering problems tho)
65 */
66
67typedef unsigned char   u8;
68typedef unsigned short  u16;
69typedef unsigned long   u32;
70
71/*
72 * vars controlled by command line options
73 */
74
75int verbose = FALSE;                    /* be verbose */
76int test_only = FALSE;                  /* test only */
77
78extern char *optarg;                    /* getopt(3) control vars */
79extern int optind, opterr;
80
81char *progname;                         /* for error() */
82
83int process(char *arg);
84void error(int errn, ...);
85long getparm(char *s, long min, long max, char *msg);
86
87#define ERR_ERRNO  (1<<((sizeof(int) * 8) - 2)) /* hi bit; use 'errno' */
88#define ERR_FATAL  (ERR_ERRNO / 2)              /* fatal error ; no return */
89#define ERR_ABORT  (ERR_ERRNO / 4)              /* fatal error ; abort */
90#define ERR_MASK   (ERR_ERRNO | ERR_FATAL | ERR_ABORT) /* all */
91
92#define stol(p) strtol(p, (char **) NULL, 0)
93int  Open(), Read(), Write();
94
95int main(
96  int argc,
97  char **argv
98)
99{
100    register int c;
101    int showusage = FALSE;                      /* usage error? */
102    int rc = 0;
103
104    /*
105     * figure out invocation leaf-name
106     */
107
108    if ((progname = strrchr(argv[0], '/')) == (char *) NULL)
109        progname = argv[0];
110    else
111        progname++;
112
113    argv[0] = progname;                         /* for getopt err reporting */
114
115    /*
116     *  Check options and arguments.
117     */
118
119    opterr = 0;                                 /* we'll report all errors */
120    while ((c = getopt(argc, argv, GETOPTARGS)) != EOF)
121        switch (c)
122        {
123            case 't':                           /* toggle test only mode */
124                test_only = ! test_only;
125                break;
126
127            case 'v':                           /* toggle verbose */
128                verbose = ! verbose;
129                break;
130
131            case '?':
132                showusage = TRUE;
133        }
134
135    if (showusage)
136    {
137        (void) fprintf(stderr, "%s", USAGE);
138        exit(1);
139    }
140
141    /*
142     *  traverse and process the arguments
143     */
144
145    for ( ; argv[optind]; optind++)
146        if (Failed(process(argv[optind])))
147            rc = FAILURE;
148
149    return rc;
150}
151
152
153/*
154 * process(arg)
155 */
156
157int
158process(char *arg)
159{
160  FILE   *in;
161  FILE   *out = (FILE *) 0;
162  char    outname[ MAX_PATH ];
163  char   *bptr;
164  char    buffer[ BUFFER_SIZE ];
165  int     length;
166  int     line_number;
167  int     rc = SUCCESS;  /* succeed by default */
168
169  in = fopen( arg, "r" );
170  if (!in)
171    error( ERR_ERRNO | ERR_FATAL, "Unable to open file (%s)\n", arg );
172
173  if ( !test_only ) {
174    length = snprintf( outname, BUFFER_SIZE, "%s.eoltmp", arg );
175    if (length >= BUFFER_SIZE)
176      error( ERR_ERRNO | ERR_FATAL, "Tmp file name too long\n" );
177
178    out = fopen( outname, "w" );
179    if (!out)
180      error( ERR_ERRNO | ERR_FATAL, "Unable to open file (%s)\n", arg );
181  }
182
183  if ( verbose )
184    fprintf( stderr, "Processing %s\n", arg );
185
186  for ( line_number=1 ; ; line_number++ ) {
187    bptr = fgets( buffer, BUFFER_SIZE, in );
188    if (!bptr)
189      break;
190
191    /*
192     *  Don't count the carriage return.
193     */
194    length = 0;
195    if ( *buffer != '\0' )
196      length = strnlen( buffer, BUFFER_SIZE ) - 1;
197
198    if ( buffer[ length ] != '\n' )
199      error(ERR_ERRNO|ERR_FATAL, "Line %d too long in %s\n", line_number, arg);
200
201    while ( length && isspace( (unsigned char) buffer[ length ] ) )
202      buffer[ length-- ] = '\0';
203
204    if ( test_only ) {
205      fprintf( stderr, "%s\n", arg );
206      break;
207    }
208
209    fprintf( out, "%s\n", buffer );
210  }
211
212  fclose( in );
213  if ( !test_only ) {
214    if (out) fclose( out );
215    rc = rename( outname, arg );
216    if ( rc != 0 ) {
217      fprintf( stderr, "Unable to rename %s to %s\n", outname, arg );
218    }
219  }
220  return rc;
221}
222
223/*
224 * error(errn, arglist)
225 *      report an error to stderr using printf(3) conventions.
226 *      Any output is preceded by '<progname>: '
227 *
228 * Uses ERR_FATAL bit to request exit(errn)
229 *      ERR_ABORT to request abort()
230 *      ERR_ERRNO to indicate use of errno instead of argument.
231 *
232 * If resulting 'errn' is non-zero, it is assumed to be an 'errno' and its
233 *      associated error message is appended to the output.
234 */
235
236/*VARARGS*/
237
238void
239error(int error_flag, ...)
240{
241    va_list arglist;
242    register char *format;
243    int local_errno;
244
245    extern int errno;
246
247    (void) fflush(stdout);          /* in case stdout/stderr same */
248
249    local_errno = error_flag & ~ERR_MASK;
250    if (error_flag & ERR_ERRNO)     /* use errno? */
251        local_errno = errno;
252
253    va_start(arglist, error_flag);
254    format = va_arg(arglist, char *);
255    (void) fprintf(stderr, "%s: ", progname);
256    (void) vfprintf(stderr, format, arglist);
257    va_end(arglist);
258
259    if (local_errno)
260      (void) fprintf(stderr, " (%s)\n", strerror(local_errno));
261    else
262      (void) fprintf(stderr, "\n");
263
264    (void) fflush(stderr);
265
266    if (error_flag & (ERR_FATAL | ERR_ABORT))
267    {
268        if (error_flag & ERR_FATAL)
269        {
270            error(0, "fatal error, exiting");
271            exit(local_errno ? local_errno : 1);
272        }
273        else
274        {
275            error(0, "fatal error, aborting");
276            abort();
277        }
278    }
279}
280
281long
282getparm(char *s,
283        long min,
284        long max,
285        char *msg)
286{
287    long val;
288
289    if ( ! strchr("0123456789-", *s))
290    {
291        error(ERR_FATAL, "'%s' is not a number", s);
292        return min;
293    }
294
295    val = strtol(s, (char **) NULL, 0);
296    if ((val < min) || (val > max))
297    {
298        if (min == max)
299            error(ERR_FATAL, "%s can only be %ld", s, min);
300        else
301            error(ERR_FATAL, "%s must be between %ld and %ld", msg, min, max);
302    }
303
304    return val;
305}
306
307
308/*
309 * Open()
310 *      Perform open(2), returning the file descriptor.  Prints
311 *      error message if open fails.
312 */
313
314int
315Open(char *file,
316     int oflag,
317     int mode)
318{
319    int O_fd;
320
321    if (Failed(O_fd = open(file, oflag, mode)))
322        error(
323          ERR_ERRNO | ERR_FATAL,
324          "open('%s', 0x%x, 0%o) failed", file, oflag, mode
325        );
326
327    return O_fd;
328}
329
330/*
331 * Read()
332 *      Perform read(2); prints error message if fails.
333 */
334
335int
336Read(int file,
337     char *buffer,
338     unsigned int count)
339{
340    int nbytes;
341
342    if (Failed(nbytes = read(file, buffer, count)))
343        error(
344          ERR_ERRNO | ERR_FATAL,
345          "read(%d, 0x%x, %d) failed", file, buffer, count
346        );
347
348    return nbytes;
349}
350
351/*
352 * Write()
353 *      Perform write(2); prints error message if fails.
354 */
355
356int
357Write(int file,
358      char *buffer,
359      unsigned int count)
360{
361    int nbytes;
362
363    if (Failed(nbytes = write(file, buffer, count)))
364        error(
365          ERR_ERRNO | ERR_FATAL,
366          "write(%d, 0x%x, %d) failed", file, buffer, count
367        );
368
369    return nbytes;
370}
Note: See TracBrowser for help on using the repository browser.