12159047fSniklas /* bucomm.c -- Bin Utils COMmon code.
2c074d1c9Sdrahn Copyright 1991, 1992, 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003
3b305b0f1Sespie Free Software Foundation, Inc.
42159047fSniklas
52159047fSniklas This file is part of GNU Binutils.
62159047fSniklas
72159047fSniklas This program is free software; you can redistribute it and/or modify
82159047fSniklas it under the terms of the GNU General Public License as published by
92159047fSniklas the Free Software Foundation; either version 2 of the License, or
102159047fSniklas (at your option) any later version.
112159047fSniklas
122159047fSniklas This program is distributed in the hope that it will be useful,
132159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
142159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
152159047fSniklas GNU General Public License for more details.
162159047fSniklas
172159047fSniklas You should have received a copy of the GNU General Public License
182159047fSniklas along with this program; if not, write to the Free Software
19b305b0f1Sespie Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20b305b0f1Sespie 02111-1307, USA. */
212159047fSniklas
222159047fSniklas /* We might put this in a library someday so it could be dynamically
232159047fSniklas loaded, but for now it's not necessary. */
242159047fSniklas
252159047fSniklas #include "bfd.h"
26c074d1c9Sdrahn #include "bfdver.h"
272159047fSniklas #include "libiberty.h"
282159047fSniklas #include "bucomm.h"
29b305b0f1Sespie #include "filenames.h"
30c074d1c9Sdrahn #include "libbfd.h"
312159047fSniklas
322159047fSniklas #include <sys/stat.h>
332159047fSniklas #include <time.h> /* ctime, maybe time_t */
342159047fSniklas
352159047fSniklas #ifndef HAVE_TIME_T_IN_TIME_H
362159047fSniklas #ifndef HAVE_TIME_T_IN_TYPES_H
372159047fSniklas typedef long time_t;
382159047fSniklas #endif
392159047fSniklas #endif
40c074d1c9Sdrahn
41*007c2a45Smiod static const char * endian_string (enum bfd_endian);
42*007c2a45Smiod static int display_target_list (void);
43*007c2a45Smiod static int display_info_table (int, int);
44*007c2a45Smiod static int display_target_tables (void);
452159047fSniklas
46c074d1c9Sdrahn /* Error reporting. */
472159047fSniklas
482159047fSniklas char *program_name;
492159047fSniklas
502159047fSniklas void
bfd_nonfatal(const char * string)51*007c2a45Smiod bfd_nonfatal (const char *string)
522159047fSniklas {
53c074d1c9Sdrahn const char *errmsg = bfd_errmsg (bfd_get_error ());
542159047fSniklas
552159047fSniklas if (string)
562159047fSniklas fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg);
572159047fSniklas else
582159047fSniklas fprintf (stderr, "%s: %s\n", program_name, errmsg);
592159047fSniklas }
602159047fSniklas
612159047fSniklas void
bfd_fatal(const char * string)62*007c2a45Smiod bfd_fatal (const char *string)
632159047fSniklas {
642159047fSniklas bfd_nonfatal (string);
652159047fSniklas xexit (1);
662159047fSniklas }
672159047fSniklas
68b305b0f1Sespie void
report(const char * format,va_list args)69*007c2a45Smiod report (const char * format, va_list args)
70b305b0f1Sespie {
71b305b0f1Sespie fprintf (stderr, "%s: ", program_name);
72b305b0f1Sespie vfprintf (stderr, format, args);
73b305b0f1Sespie putc ('\n', stderr);
74b305b0f1Sespie }
75b305b0f1Sespie
762159047fSniklas void
fatal(const char * format,...)77c074d1c9Sdrahn fatal VPARAMS ((const char *format, ...))
782159047fSniklas {
79c074d1c9Sdrahn VA_OPEN (args, format);
80c074d1c9Sdrahn VA_FIXEDARG (args, const char *, format);
812159047fSniklas
82b305b0f1Sespie report (format, args);
83c074d1c9Sdrahn VA_CLOSE (args);
842159047fSniklas xexit (1);
852159047fSniklas }
86b305b0f1Sespie
87b305b0f1Sespie void
non_fatal(const char * format,...)88c074d1c9Sdrahn non_fatal VPARAMS ((const char *format, ...))
89b305b0f1Sespie {
90c074d1c9Sdrahn VA_OPEN (args, format);
91c074d1c9Sdrahn VA_FIXEDARG (args, const char *, format);
92b305b0f1Sespie
93b305b0f1Sespie report (format, args);
94c074d1c9Sdrahn VA_CLOSE (args);
95b305b0f1Sespie }
962159047fSniklas
97b305b0f1Sespie /* Set the default BFD target based on the configured target. Doing
98b305b0f1Sespie this permits the binutils to be configured for a particular target,
99b305b0f1Sespie and linked against a shared BFD library which was configured for a
100b305b0f1Sespie different target. */
101b305b0f1Sespie
102b305b0f1Sespie void
set_default_bfd_target(void)103*007c2a45Smiod set_default_bfd_target (void)
104b305b0f1Sespie {
105b305b0f1Sespie /* The macro TARGET is defined by Makefile. */
106b305b0f1Sespie const char *target = TARGET;
107b305b0f1Sespie
108b305b0f1Sespie if (! bfd_set_default_target (target))
109b305b0f1Sespie fatal (_("can't set BFD default target to `%s': %s"),
110b305b0f1Sespie target, bfd_errmsg (bfd_get_error ()));
111b305b0f1Sespie }
112b305b0f1Sespie
113c074d1c9Sdrahn /* After a FALSE return from bfd_check_format_matches with
114b305b0f1Sespie bfd_get_error () == bfd_error_file_ambiguously_recognized, print
115b305b0f1Sespie the possible matching targets. */
1162159047fSniklas
1172159047fSniklas void
list_matching_formats(char ** p)118*007c2a45Smiod list_matching_formats (char **p)
1192159047fSniklas {
120b305b0f1Sespie fprintf (stderr, _("%s: Matching formats:"), program_name);
1212159047fSniklas while (*p)
1222159047fSniklas fprintf (stderr, " %s", *p++);
123b305b0f1Sespie fputc ('\n', stderr);
1242159047fSniklas }
1252159047fSniklas
1262159047fSniklas /* List the supported targets. */
1272159047fSniklas
1282159047fSniklas void
list_supported_targets(const char * name,FILE * f)129*007c2a45Smiod list_supported_targets (const char *name, FILE *f)
1302159047fSniklas {
1312159047fSniklas int t;
132c074d1c9Sdrahn const char **targ_names = bfd_target_list ();
1332159047fSniklas
1342159047fSniklas if (name == NULL)
135b305b0f1Sespie fprintf (f, _("Supported targets:"));
1362159047fSniklas else
137b305b0f1Sespie fprintf (f, _("%s: supported targets:"), name);
138c074d1c9Sdrahn
139c074d1c9Sdrahn for (t = 0; targ_names[t] != NULL; t++)
140c074d1c9Sdrahn fprintf (f, " %s", targ_names[t]);
1412159047fSniklas fprintf (f, "\n");
142c074d1c9Sdrahn free (targ_names);
143c074d1c9Sdrahn }
144c074d1c9Sdrahn
145c074d1c9Sdrahn /* List the supported architectures. */
146c074d1c9Sdrahn
147c074d1c9Sdrahn void
list_supported_architectures(const char * name,FILE * f)148*007c2a45Smiod list_supported_architectures (const char *name, FILE *f)
149c074d1c9Sdrahn {
150c074d1c9Sdrahn const char **arch;
151c074d1c9Sdrahn
152c074d1c9Sdrahn if (name == NULL)
153c074d1c9Sdrahn fprintf (f, _("Supported architectures:"));
154c074d1c9Sdrahn else
155c074d1c9Sdrahn fprintf (f, _("%s: supported architectures:"), name);
156c074d1c9Sdrahn
157c074d1c9Sdrahn for (arch = bfd_arch_list (); *arch; arch++)
158c074d1c9Sdrahn fprintf (f, " %s", *arch);
159c074d1c9Sdrahn fprintf (f, "\n");
160c074d1c9Sdrahn }
161c074d1c9Sdrahn
162c074d1c9Sdrahn /* The length of the longest architecture name + 1. */
163c074d1c9Sdrahn #define LONGEST_ARCH sizeof ("powerpc:common")
164c074d1c9Sdrahn
165c074d1c9Sdrahn static const char *
endian_string(enum bfd_endian endian)166*007c2a45Smiod endian_string (enum bfd_endian endian)
167c074d1c9Sdrahn {
168c074d1c9Sdrahn switch (endian)
169c074d1c9Sdrahn {
170c074d1c9Sdrahn case BFD_ENDIAN_BIG: return "big endian";
171c074d1c9Sdrahn case BFD_ENDIAN_LITTLE: return "little endian";
172c074d1c9Sdrahn default: return "endianness unknown";
173c074d1c9Sdrahn }
174c074d1c9Sdrahn }
175c074d1c9Sdrahn
176c074d1c9Sdrahn /* List the targets that BFD is configured to support, each followed
177c074d1c9Sdrahn by its endianness and the architectures it supports. */
178c074d1c9Sdrahn
179c074d1c9Sdrahn static int
display_target_list(void)180*007c2a45Smiod display_target_list (void)
181c074d1c9Sdrahn {
182c074d1c9Sdrahn char *dummy_name;
183c074d1c9Sdrahn int t;
184c074d1c9Sdrahn int ret = 1;
185c074d1c9Sdrahn
186c074d1c9Sdrahn dummy_name = make_temp_file (NULL);
187c074d1c9Sdrahn for (t = 0; bfd_target_vector[t]; t++)
188c074d1c9Sdrahn {
189c074d1c9Sdrahn const bfd_target *p = bfd_target_vector[t];
190c074d1c9Sdrahn bfd *abfd = bfd_openw (dummy_name, p->name);
191c074d1c9Sdrahn int a;
192c074d1c9Sdrahn
193c074d1c9Sdrahn printf ("%s\n (header %s, data %s)\n", p->name,
194c074d1c9Sdrahn endian_string (p->header_byteorder),
195c074d1c9Sdrahn endian_string (p->byteorder));
196c074d1c9Sdrahn
197c074d1c9Sdrahn if (abfd == NULL)
198c074d1c9Sdrahn {
199c074d1c9Sdrahn bfd_nonfatal (dummy_name);
200c074d1c9Sdrahn ret = 0;
201c074d1c9Sdrahn continue;
202c074d1c9Sdrahn }
203c074d1c9Sdrahn
204c074d1c9Sdrahn if (! bfd_set_format (abfd, bfd_object))
205c074d1c9Sdrahn {
206c074d1c9Sdrahn if (bfd_get_error () != bfd_error_invalid_operation)
207c074d1c9Sdrahn {
208c074d1c9Sdrahn bfd_nonfatal (p->name);
209c074d1c9Sdrahn ret = 0;
210c074d1c9Sdrahn }
211c074d1c9Sdrahn bfd_close_all_done (abfd);
212c074d1c9Sdrahn continue;
213c074d1c9Sdrahn }
214c074d1c9Sdrahn
215c074d1c9Sdrahn for (a = (int) bfd_arch_obscure + 1; a < (int) bfd_arch_last; a++)
216c074d1c9Sdrahn if (bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0))
217c074d1c9Sdrahn printf (" %s\n",
218c074d1c9Sdrahn bfd_printable_arch_mach ((enum bfd_architecture) a, 0));
219c074d1c9Sdrahn bfd_close_all_done (abfd);
220c074d1c9Sdrahn }
221c074d1c9Sdrahn unlink (dummy_name);
222c074d1c9Sdrahn free (dummy_name);
223c074d1c9Sdrahn
224c074d1c9Sdrahn return ret;
225c074d1c9Sdrahn }
226c074d1c9Sdrahn
227c074d1c9Sdrahn /* Print a table showing which architectures are supported for entries
228c074d1c9Sdrahn FIRST through LAST-1 of bfd_target_vector (targets across,
229c074d1c9Sdrahn architectures down). */
230c074d1c9Sdrahn
231c074d1c9Sdrahn static int
display_info_table(int first,int last)232*007c2a45Smiod display_info_table (int first, int last)
233c074d1c9Sdrahn {
234c074d1c9Sdrahn int t;
235c074d1c9Sdrahn int a;
236c074d1c9Sdrahn int ret = 1;
237c074d1c9Sdrahn char *dummy_name;
238c074d1c9Sdrahn
239c074d1c9Sdrahn /* Print heading of target names. */
240c074d1c9Sdrahn printf ("\n%*s", (int) LONGEST_ARCH, " ");
241c074d1c9Sdrahn for (t = first; t < last && bfd_target_vector[t]; t++)
242c074d1c9Sdrahn printf ("%s ", bfd_target_vector[t]->name);
243c074d1c9Sdrahn putchar ('\n');
244c074d1c9Sdrahn
245c074d1c9Sdrahn dummy_name = make_temp_file (NULL);
246c074d1c9Sdrahn for (a = (int) bfd_arch_obscure + 1; a < (int) bfd_arch_last; a++)
247c074d1c9Sdrahn if (strcmp (bfd_printable_arch_mach (a, 0), "UNKNOWN!") != 0)
248c074d1c9Sdrahn {
249c074d1c9Sdrahn printf ("%*s ", (int) LONGEST_ARCH - 1,
250c074d1c9Sdrahn bfd_printable_arch_mach (a, 0));
251c074d1c9Sdrahn for (t = first; t < last && bfd_target_vector[t]; t++)
252c074d1c9Sdrahn {
253c074d1c9Sdrahn const bfd_target *p = bfd_target_vector[t];
254c074d1c9Sdrahn bfd_boolean ok = TRUE;
255c074d1c9Sdrahn bfd *abfd = bfd_openw (dummy_name, p->name);
256c074d1c9Sdrahn
257c074d1c9Sdrahn if (abfd == NULL)
258c074d1c9Sdrahn {
259c074d1c9Sdrahn bfd_nonfatal (p->name);
260c074d1c9Sdrahn ret = 0;
261c074d1c9Sdrahn ok = FALSE;
262c074d1c9Sdrahn }
263c074d1c9Sdrahn
264c074d1c9Sdrahn if (ok)
265c074d1c9Sdrahn {
266c074d1c9Sdrahn if (! bfd_set_format (abfd, bfd_object))
267c074d1c9Sdrahn {
268c074d1c9Sdrahn if (bfd_get_error () != bfd_error_invalid_operation)
269c074d1c9Sdrahn {
270c074d1c9Sdrahn bfd_nonfatal (p->name);
271c074d1c9Sdrahn ret = 0;
272c074d1c9Sdrahn }
273c074d1c9Sdrahn ok = FALSE;
274c074d1c9Sdrahn }
275c074d1c9Sdrahn }
276c074d1c9Sdrahn
277c074d1c9Sdrahn if (ok)
278c074d1c9Sdrahn {
279c074d1c9Sdrahn if (! bfd_set_arch_mach (abfd, a, 0))
280c074d1c9Sdrahn ok = FALSE;
281c074d1c9Sdrahn }
282c074d1c9Sdrahn
283c074d1c9Sdrahn if (ok)
284c074d1c9Sdrahn printf ("%s ", p->name);
285c074d1c9Sdrahn else
286c074d1c9Sdrahn {
287c074d1c9Sdrahn int l = strlen (p->name);
288c074d1c9Sdrahn while (l--)
289c074d1c9Sdrahn putchar ('-');
290c074d1c9Sdrahn putchar (' ');
291c074d1c9Sdrahn }
292c074d1c9Sdrahn if (abfd != NULL)
293c074d1c9Sdrahn bfd_close_all_done (abfd);
294c074d1c9Sdrahn }
295c074d1c9Sdrahn putchar ('\n');
296c074d1c9Sdrahn }
297c074d1c9Sdrahn unlink (dummy_name);
298c074d1c9Sdrahn free (dummy_name);
299c074d1c9Sdrahn
300c074d1c9Sdrahn return ret;
301c074d1c9Sdrahn }
302c074d1c9Sdrahn
303c074d1c9Sdrahn /* Print tables of all the target-architecture combinations that
304c074d1c9Sdrahn BFD has been configured to support. */
305c074d1c9Sdrahn
306c074d1c9Sdrahn static int
display_target_tables(void)307*007c2a45Smiod display_target_tables (void)
308c074d1c9Sdrahn {
309c074d1c9Sdrahn int t;
310c074d1c9Sdrahn int columns;
311c074d1c9Sdrahn int ret = 1;
312c074d1c9Sdrahn char *colum;
313c074d1c9Sdrahn
314c074d1c9Sdrahn columns = 0;
315c074d1c9Sdrahn colum = getenv ("COLUMNS");
316c074d1c9Sdrahn if (colum != NULL)
317c074d1c9Sdrahn columns = atoi (colum);
318c074d1c9Sdrahn if (columns == 0)
319c074d1c9Sdrahn columns = 80;
320c074d1c9Sdrahn
321c074d1c9Sdrahn t = 0;
322c074d1c9Sdrahn while (bfd_target_vector[t] != NULL)
323c074d1c9Sdrahn {
324c074d1c9Sdrahn int oldt = t, wid;
325c074d1c9Sdrahn
326c074d1c9Sdrahn wid = LONGEST_ARCH + strlen (bfd_target_vector[t]->name) + 1;
327c074d1c9Sdrahn ++t;
328c074d1c9Sdrahn while (wid < columns && bfd_target_vector[t] != NULL)
329c074d1c9Sdrahn {
330c074d1c9Sdrahn int newwid;
331c074d1c9Sdrahn
332c074d1c9Sdrahn newwid = wid + strlen (bfd_target_vector[t]->name) + 1;
333c074d1c9Sdrahn if (newwid >= columns)
334c074d1c9Sdrahn break;
335c074d1c9Sdrahn wid = newwid;
336c074d1c9Sdrahn ++t;
337c074d1c9Sdrahn }
338c074d1c9Sdrahn if (! display_info_table (oldt, t))
339c074d1c9Sdrahn ret = 0;
340c074d1c9Sdrahn }
341c074d1c9Sdrahn
342c074d1c9Sdrahn return ret;
343c074d1c9Sdrahn }
344c074d1c9Sdrahn
345c074d1c9Sdrahn int
display_info(void)346*007c2a45Smiod display_info (void)
347c074d1c9Sdrahn {
348c074d1c9Sdrahn printf (_("BFD header file version %s\n"), BFD_VERSION_STRING);
349c074d1c9Sdrahn if (! display_target_list () || ! display_target_tables ())
350c074d1c9Sdrahn return 1;
351c074d1c9Sdrahn else
352c074d1c9Sdrahn return 0;
3532159047fSniklas }
3542159047fSniklas
3552159047fSniklas /* Display the archive header for an element as if it were an ls -l listing:
3562159047fSniklas
3572159047fSniklas Mode User\tGroup\tSize\tDate Name */
3582159047fSniklas
3592159047fSniklas void
print_arelt_descr(FILE * file,bfd * abfd,bfd_boolean verbose)360*007c2a45Smiod print_arelt_descr (FILE *file, bfd *abfd, bfd_boolean verbose)
3612159047fSniklas {
3622159047fSniklas struct stat buf;
3632159047fSniklas
3642159047fSniklas if (verbose)
3652159047fSniklas {
3662159047fSniklas if (bfd_stat_arch_elt (abfd, &buf) == 0)
3672159047fSniklas {
3682159047fSniklas char modebuf[11];
3692159047fSniklas char timebuf[40];
3702159047fSniklas time_t when = buf.st_mtime;
371c074d1c9Sdrahn const char *ctime_result = (const char *) ctime (&when);
3722159047fSniklas
3732159047fSniklas /* POSIX format: skip weekday and seconds from ctime output. */
3742159047fSniklas sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20);
3752159047fSniklas
3762159047fSniklas mode_string (buf.st_mode, modebuf);
3772159047fSniklas modebuf[10] = '\0';
3782159047fSniklas /* POSIX 1003.2/D11 says to skip first character (entry type). */
3792159047fSniklas fprintf (file, "%s %ld/%ld %6ld %s ", modebuf + 1,
3802159047fSniklas (long) buf.st_uid, (long) buf.st_gid,
3812159047fSniklas (long) buf.st_size, timebuf);
3822159047fSniklas }
3832159047fSniklas }
3842159047fSniklas
3852159047fSniklas fprintf (file, "%s\n", bfd_get_filename (abfd));
3862159047fSniklas }
3872159047fSniklas
388b305b0f1Sespie /* Return the name of a temporary file in the same directory as FILENAME. */
3892159047fSniklas
3902159047fSniklas char *
make_tempname(char * filename,int isdir)391*007c2a45Smiod make_tempname (char *filename, int isdir)
3922159047fSniklas {
393b305b0f1Sespie static char template[] = "stXXXXXX";
3942159047fSniklas char *tmpname;
3952159047fSniklas char *slash = strrchr (filename, '/');
3969a986918Sespie char c;
3972159047fSniklas
398b305b0f1Sespie #ifdef HAVE_DOS_BASED_FILE_SYSTEM
399b305b0f1Sespie {
400b305b0f1Sespie /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
401b305b0f1Sespie char *bslash = strrchr (filename, '\\');
402b55d4692Sfgsch if (slash == NULL || (bslash != NULL && bslash > slash))
403b305b0f1Sespie slash = bslash;
404b305b0f1Sespie if (slash == NULL && filename[0] != '\0' && filename[1] == ':')
405b305b0f1Sespie slash = filename + 1;
406b305b0f1Sespie }
407b305b0f1Sespie #endif
408b305b0f1Sespie
4092159047fSniklas if (slash != (char *) NULL)
4102159047fSniklas {
411b305b0f1Sespie c = *slash;
4122159047fSniklas *slash = 0;
413b305b0f1Sespie tmpname = xmalloc (strlen (filename) + sizeof (template) + 2);
4142159047fSniklas strcpy (tmpname, filename);
415b305b0f1Sespie #ifdef HAVE_DOS_BASED_FILE_SYSTEM
416b305b0f1Sespie /* If tmpname is "X:", appending a slash will make it a root
417b305b0f1Sespie directory on drive X, which is NOT the same as the current
418b305b0f1Sespie directory on drive X. */
419b305b0f1Sespie if (tmpname[1] == ':' && tmpname[2] == '\0')
420b305b0f1Sespie strcat (tmpname, ".");
421b305b0f1Sespie #endif
4222159047fSniklas strcat (tmpname, "/");
4232159047fSniklas strcat (tmpname, template);
4242159047fSniklas }
4252159047fSniklas else
4262159047fSniklas {
4272159047fSniklas tmpname = xmalloc (sizeof (template));
4282159047fSniklas strcpy (tmpname, template);
4292159047fSniklas }
4309a986918Sespie
4319a986918Sespie if (isdir)
4329a986918Sespie {
4333d4065ffSespie if (mkdtemp (tmpname) == (char *) NULL)
4349a986918Sespie tmpname = NULL;
4359a986918Sespie }
4369a986918Sespie else
4379a986918Sespie {
4389a986918Sespie int fd;
4399a986918Sespie
4409a986918Sespie fd = mkstemp (tmpname);
4419a986918Sespie if (fd == -1)
4429a986918Sespie tmpname = NULL;
4439a986918Sespie else
4449a986918Sespie close (fd);
4459a986918Sespie }
4469a986918Sespie if (slash != (char *) NULL)
4479a986918Sespie *slash = c;
4489a986918Sespie
4492159047fSniklas return tmpname;
4502159047fSniklas }
4512159047fSniklas
4522159047fSniklas /* Parse a string into a VMA, with a fatal error if it can't be
4532159047fSniklas parsed. */
4542159047fSniklas
4552159047fSniklas bfd_vma
parse_vma(const char * s,const char * arg)456*007c2a45Smiod parse_vma (const char *s, const char *arg)
4572159047fSniklas {
4582159047fSniklas bfd_vma ret;
4592159047fSniklas const char *end;
4602159047fSniklas
4612159047fSniklas ret = bfd_scan_vma (s, &end, 0);
462b305b0f1Sespie
4632159047fSniklas if (*end != '\0')
464b305b0f1Sespie fatal (_("%s: bad number: %s"), arg, s);
465b305b0f1Sespie
4662159047fSniklas return ret;
4672159047fSniklas }
468*007c2a45Smiod
469*007c2a45Smiod /* Returns the size of the named file. If the file does not
470*007c2a45Smiod exist, or if it is not a real file, then a suitable non-fatal
471*007c2a45Smiod error message is printed and zero is returned. */
472*007c2a45Smiod
473*007c2a45Smiod off_t
get_file_size(const char * file_name)474*007c2a45Smiod get_file_size (const char * file_name)
475*007c2a45Smiod {
476*007c2a45Smiod struct stat statbuf;
477*007c2a45Smiod
478*007c2a45Smiod if (stat (file_name, &statbuf) < 0)
479*007c2a45Smiod {
480*007c2a45Smiod if (errno == ENOENT)
481*007c2a45Smiod non_fatal (_("'%s': No such file"), file_name);
482*007c2a45Smiod else
483*007c2a45Smiod non_fatal (_("Warning: could not locate '%s'. reason: %s"),
484*007c2a45Smiod file_name, strerror (errno));
485*007c2a45Smiod }
486*007c2a45Smiod else if (! S_ISREG (statbuf.st_mode))
487*007c2a45Smiod non_fatal (_("Warning: '%s' is not an ordinary file"), file_name);
488*007c2a45Smiod else
489*007c2a45Smiod return statbuf.st_size;
490*007c2a45Smiod
491*007c2a45Smiod return 0;
492*007c2a45Smiod }
493