dosfstools  4.2
About: dosfstools are utilities to create, check and label (MS-DOS) FAT filesystems.
  Fossies Dox: dosfstools-4.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

common.c
Go to the documentation of this file.
1 /* common.c - Common functions
2 
3  Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch>
4  Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
5  Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
6  Copyright (C) 2018 Pali Roh├ír <pali.rohar@gmail.com>
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  The complete text of the GNU General Public License
22  can be found in /usr/share/common-licenses/GPL-3 file.
23 */
24 
25 /* FAT32, VFAT, Atari format support, and various fixes additions May 1998
26  * by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
27 
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <errno.h>
33 #include <wctype.h>
34 #include <termios.h>
35 #include <sys/time.h>
36 #include <unistd.h>
37 
38 #include "common.h"
39 #include "charconv.h"
40 
41 
45 const char *program_name;
46 
47 
48 typedef struct _link {
49  void *data;
50  struct _link *next;
51 } LINK;
52 
53 void die(const char *msg, ...)
54 {
55  va_list args;
56 
57  if (program_name)
58  fprintf(stderr, "%s: ", program_name);
59 
60  va_start(args, msg);
61  vfprintf(stderr, msg, args);
62  va_end(args);
63  fprintf(stderr, "\n");
64  exit(1);
65 }
66 
67 void pdie(const char *msg, ...)
68 {
69  va_list args;
70 
71  if (program_name)
72  fprintf(stderr, "%s: ", program_name);
73 
74  va_start(args, msg);
75  vfprintf(stderr, msg, args);
76  va_end(args);
77  fprintf(stderr, ":%s\n", strerror(errno));
78  exit(1);
79 }
80 
81 void *alloc(int size)
82 {
83  void *this;
84 
85  if ((this = malloc(size)))
86  return this;
87  pdie("malloc");
88  return NULL; /* for GCC */
89 }
90 
91 void *qalloc(void **root, int size)
92 {
93  LINK *link;
94 
95  link = alloc(sizeof(LINK));
96  link->next = *root;
97  *root = link;
98  return link->data = alloc(size);
99 }
100 
101 void qfree(void **root)
102 {
103  LINK *this;
104 
105  while (*root) {
106  this = (LINK *) * root;
107  *root = this->next;
108  free(this->data);
109  free(this);
110  }
111 }
112 
113 int min(int a, int b)
114 {
115  return a < b ? a : b;
116 }
117 
118 
119 #ifndef HAVE_VASPRINTF
120 static int vasprintf(char **strp, const char *fmt, va_list va)
121 {
122  int length;
123  va_list vacopy;
124 
125  va_copy(vacopy, va);
126 
127  length = vsnprintf(NULL, 0, fmt, vacopy);
128  if (length < 0)
129  return length;
130 
131  *strp = malloc(length + 1);
132  if (!*strp) {
133  errno = ENOMEM;
134  return -1;
135  }
136 
137  return vsnprintf(*strp, length + 1, fmt, va);
138 }
139 #endif
140 
141 int xasprintf(char **strp, const char *fmt, ...)
142 {
143  va_list va;
144  int retval;
145 
146  va_start(va, fmt);
147  retval = vasprintf(strp, fmt, va);
148  va_end(va);
149 
150  if (retval < 0)
151  pdie("asprintf");
152 
153  return retval;
154 }
155 
156 
157 int get_choice(int noninteractive_result, const char *noninteractive_msg,
158  int choices, ...)
159 {
160  int choice_values[9];
161  const char *choice_strings[9];
162  int choice;
163  int quit_choice;
164  int print_choices, print_full_choices;
165  va_list va;
166  int i;
167  static int inhibit_quit_choice;
168 
169  if (!interactive) {
170  printf("%s\n", noninteractive_msg);
171  return noninteractive_result;
172  }
173 
174  if (choices < 2 || choices > 9)
175  die("internal error: invalid number %u of choices in get_choice()",
176  choices);
177 
178  va_start(va, choices);
179  for (i = 0; i < choices; i++) {
180  choice_values[i] = va_arg(va, int);
181  choice_strings[i] = va_arg(va, const char *);
182  }
183  va_end(va);
184 
185  print_choices = 1;
186  print_full_choices = 0;
187  while (1) {
188  if (print_choices) {
189  print_choices = 0;
190  for (i = 0; i < choices; i++)
191  printf("%d) %s\n", i + 1, choice_strings[i]);
192 
193  if (print_full_choices) {
194  printf("?) List all choices\n");
195  printf("q) Quit fsck\n");
196  }
197  }
198 
199  printf("[%.*s?%s]? ", choices, "123456789", inhibit_quit_choice ? "" : "q");
200  fflush(stdout);
201 
202  do {
203  choice = getchar();
204  } while (choice == '\n'); /* filter out enter presses */
205 
206  if (choice == EOF)
207  exit(1);
208 
209  printf("%c\n", choice);
210 
211  if (choice > '0' && choice <= '0' + choices)
212  break;
213 
214  if (choice == '?') {
215  print_choices = 1;
216  print_full_choices = 1;
217  }
218 
219  if (!inhibit_quit_choice && (choice == 'q' || choice == 'Q')) {
220  if (!write_immed)
221  printf("No changes have been written to the filesystem yet. If you choose\n"
222  "to quit, it will be left in the same state it was in before you\n"
223  "started this program.\n");
224  else
225  printf("fsck is running in immediate write mode. All changes so far have\n"
226  "already been written and can not be undone now. If you choose to\n"
227  "quit now, these changes will stay in place.\n");
228 
229  inhibit_quit_choice = 1;
230  quit_choice = get_choice(1, "This is never non-interactive.",
231  2,
232  1, "Quit now",
233  2, "Continue");
234  inhibit_quit_choice = 0;
235 
236  if (quit_choice == 1)
237  exit(0);
238  }
239  }
240 
241  return choice_values[choice - '1'];
242 }
243 
244 
245 char *get_line(const char *prompt, char *dest, size_t length)
246 {
247  struct termios tio, tio_orig;
248  int tio_fail;
249  char *retval;
250 
251  tio_fail = tcgetattr(0, &tio_orig);
252  if (!tio_fail) {
253  tio = tio_orig;
254  tio.c_lflag |= ICANON | ECHO;
255  tcsetattr(0, TCSAFLUSH, &tio);
256  }
257 
258  printf("%s: ", prompt);
259  fflush(stdout);
260 
261  retval = fgets(dest, length, stdin);
262 
263  if (!tio_fail)
264  tcsetattr(0, TCSAFLUSH, &tio_orig);
265  return retval;
266 }
267 
268 
269 /*
270  * ++roman: On m68k, check if this is an Atari; if yes, turn on Atari variant
271  * of MS-DOS filesystem by default.
272  */
273 void check_atari(void)
274 {
275 #if defined(__mc68000__) && defined(__linux__) && defined(CONF_CHECK_ATARI)
276  FILE *f;
277  char line[128], *p;
278 
279  if (!(f = fopen("/proc/hardware", "r"))) {
280  perror("/proc/hardware");
281  return;
282  }
283 
284  while (fgets(line, sizeof(line), f)) {
285  if (strncmp(line, "Model:", 6) == 0) {
286  p = line + 6;
287  p += strspn(p, " \t");
288  if (strncmp(p, "Atari ", 6) == 0)
289  atari_format = 1;
290  break;
291  }
292  }
293  fclose(f);
294 #endif
295 }
296 
297 
298 uint32_t generate_volume_id(void)
299 {
300  struct timeval now;
301 
302  if (gettimeofday(&now, NULL) != 0 || now.tv_sec == (time_t)-1 || now.tv_sec < 0) {
303  srand(getpid());
304  /* rand() returns int from [0,RAND_MAX], therefore only 31 bits */
305  return (((uint32_t)(rand() & 0xFFFF)) << 16) | ((uint32_t)(rand() & 0xFFFF));
306  }
307 
308  /* volume ID = current time, fudged for more uniqueness */
309  return ((uint32_t)now.tv_sec << 20) | (uint32_t)now.tv_usec;
310 }
311 
312 /*
313  * Validate volume label
314  *
315  * @param[in] doslabel Label stored according to current DOS codepage
316  *
317  * @return bitmask of errors
318  * 0x01 - lowercase character
319  * 0x02 - character below 0x20
320  * 0x04 - character in disallowed set
321  * 0x08 - empty or space-only label
322  * 0x10 - space at beginning
323  */
324 int validate_volume_label(char *doslabel)
325 {
326  int i;
327  int ret = 0;
328  wchar_t wlabel[12];
329 
330  if (dos_string_to_wchar_string(wlabel, doslabel, sizeof(wlabel))) {
331  for (i = 0; wlabel[i]; i++) {
332  /* FAT specification: Lower case characters are not allowed in DIR_Name
333  (what these characters are is country specific)
334  Original label is stored in DOS OEM code page, so islower() function
335  cannot be used. Therefore convert original label to locale independent
336  wchar_t* and then use iswlower() function for it.
337  */
338  if (iswlower(wlabel[i])) {
339  ret |= 0x01;
340  break;
341  }
342  }
343  }
344 
345  /* According to FAT specification those bytes (after conversion to DOS OEM
346  code page) are not allowed.
347  */
348  for (i = 0; i < 11; i++) {
349  if (doslabel[i] < 0x20)
350  ret |= 0x02;
351  if (doslabel[i] == 0x22 ||
352  (doslabel[i] >= 0x2A && doslabel[i] <= 0x2C) ||
353  doslabel[i] == 0x2E ||
354  doslabel[i] == 0x2F ||
355  (doslabel[i] >= 0x3A && doslabel[i] <= 0x3F) ||
356  (doslabel[i] >= 0x5B && doslabel[i] <= 0x5D) ||
357  doslabel[i] == 0x7C)
358  ret |= 0x04;
359  }
360 
361  if (memcmp(doslabel, " ", 11) == 0)
362  ret |= 0x08;
363 
364  if (doslabel[0] == ' ')
365  ret |= 0x10;
366 
367  return ret;
368 }
int dos_string_to_wchar_string(wchar_t *out, char *in, unsigned int out_size)
Definition: charconv.c:363
static DOS_FILE * root
Definition: check.c:51
void qfree(void **root)
Definition: common.c:101
void pdie(const char *msg,...)
Definition: common.c:67
void die(const char *msg,...)
Definition: common.c:53
int xasprintf(char **strp, const char *fmt,...)
Definition: common.c:141
int validate_volume_label(char *doslabel)
Definition: common.c:324
void * alloc(int size)
Definition: common.c:81
static int vasprintf(char **strp, const char *fmt, va_list va)
Definition: common.c:120
struct _link LINK
void check_atari(void)
Definition: common.c:273
int atari_format
Definition: common.c:44
int write_immed
Definition: common.c:43
int min(int a, int b)
Definition: common.c:113
void * qalloc(void **root, int size)
Definition: common.c:91
uint32_t generate_volume_id(void)
Definition: common.c:298
const char * program_name
Definition: common.c:45
int interactive
Definition: common.c:42
int get_choice(int noninteractive_result, const char *noninteractive_msg, int choices,...)
Definition: common.c:157
char * get_line(const char *prompt, char *dest, size_t length)
Definition: common.c:245