1/* trunc.c: Set the size of an existing file, or create a file of a
2 *          specified size.
3 *
4 * Copyright (C) 2008 Micah J. Cowan
5 *
6 * Copying and distribution of this file, with or without modification,
7 * are permitted in any medium without royalty provided the copyright
8 * notice and this notice are preserved. */
9
10#include <errno.h>
11#include <fcntl.h>
12#include <sys/stat.h>
13#include <unistd.h>
14#include <stdlib.h>
15#include <stdio.h>
16
17#define PROGRAM_NAME  "trunc"
18
19void
20usage (FILE *f)
21{
22  fputs (
23PROGRAM_NAME " [-c] file sz\n\
24\n\
25Set the filesize of FILE to SIZE.\n\
26\n\
27  -c: create FILE if it doesn't exist.\n\
28\n\
29  Multiplier suffixes for SIZE (case-insensitive):\n\
30      k: SIZE * 1024\n\
31      m: SIZE * 1024 * 1024\n", f);
32}
33
34off_t
35get_size (const char str[])
36{
37  unsigned long val;
38  int suffix;
39  char *end;
40
41  errno = 0;
42  val = strtoul(str, &end, 10);
43  if (end == str)
44    {
45      fputs (PROGRAM_NAME ": size is not a number.\n", stderr);
46      usage (stderr);
47      exit (EXIT_FAILURE);
48    }
49  else if (errno == ERANGE
50           || (unsigned long)(off_t)val != val)
51    {
52      fputs (PROGRAM_NAME ": size is out of range.\n", stderr);
53      exit (EXIT_FAILURE);
54    }
55
56  suffix = tolower ((unsigned char) end[0]);
57  if (suffix == 'k')
58    {
59      val *= 1024;
60    }
61  else if (suffix == 'm')
62    {
63      val *= 1024 * 1024;
64    }
65
66  return val;
67}
68
69int
70main (int argc, char *argv[])
71{
72  const char *fname;
73  const char *szstr;
74  off_t      sz;
75  int        create = 0;
76  int        option;
77  int        fd;
78
79  /* Parse options. */
80  while ((option = getopt (argc, argv, "c")) != -1)
81    {
82      switch (option) {
83        case 'c':
84          create = 1;
85          break;
86        case '?':
87          fprintf (stderr, PROGRAM_NAME ": Unrecognized option `%c'.\n\n",
88                   optopt);
89          usage (stderr);
90          exit (EXIT_FAILURE);
91        default:
92          /* We shouldn't reach here. */
93          abort();
94      }
95    }
96
97  if (argv[optind] == NULL
98      || argv[optind+1] == NULL
99      || argv[optind+2] != NULL)
100    {
101      usage (stderr);
102      exit (EXIT_FAILURE);
103    }
104
105  fname = argv[optind];
106  szstr = argv[optind+1];
107
108  sz = get_size(szstr);
109  if (create)
110    {
111      mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
112      fd = open(fname, O_WRONLY | O_CREAT, mode);
113    }
114  else
115    {
116      fd = open(fname, O_WRONLY);
117    }
118
119  if (fd == -1)
120    {
121      perror (PROGRAM_NAME ": open");
122      exit (EXIT_FAILURE);
123    }
124
125  if (ftruncate(fd, sz) == -1)
126    {
127      perror (PROGRAM_NAME ": truncate");
128      exit (EXIT_FAILURE);
129    }
130
131  return 0;
132}
133