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)  

fatlabel.c
Go to the documentation of this file.
1 /* fatlabel.c - User interface
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) 2007 Red Hat, Inc.
6  Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
7  Copyright (C) 2015-2017 Andreas Bombe <aeb@debian.org>
8  Copyright (C) 2017-2018 Pali Roh├ír <pali.rohar@gmail.com>
9 
10  This program is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program. If not, see <http://www.gnu.org/licenses/>.
22 
23  The complete text of the GNU General Public License
24  can be found in /usr/share/common-licenses/GPL-3 file.
25 */
26 
27 #include "version.h"
28 
29 #include <stdbool.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <limits.h>
36 #include <unistd.h>
37 #include <getopt.h>
38 #include <ctype.h>
39 
40 #include "common.h"
41 #include "fsck.fat.h"
42 #include "io.h"
43 #include "boot.h"
44 #include "fat.h"
45 #include "file.h"
46 #include "check.h"
47 #include "charconv.h"
48 
49 int rw = 0, list = 0, test = 0, verbose = 0, no_spaces_in_sfns = 0;
50 long fat_table = 0;
51 unsigned n_files = 0;
52 void *mem_queue = NULL;
53 
54 
55 static void handle_label(bool change, bool reset, const char *device, char *newlabel)
56 {
57  DOS_FS fs = { 0 };
58  off_t offset;
59  DIR_ENT de;
60 
61  char label[12] = { 0 };
62  size_t len;
63  int ret;
64  int i;
65 
66  if (change) {
67  len = mbstowcs(NULL, newlabel, 0);
68  if (len != (size_t)-1 && len > 11) {
69  fprintf(stderr,
70  "fatlabel: labels can be no longer than 11 characters\n");
71  exit(1);
72  }
73 
74  if (!local_string_to_dos_string(label, newlabel, 12)) {
75  fprintf(stderr,
76  "fatlabel: error when processing label\n");
77  exit(1);
78  }
79 
80  for (i = strlen(label); i < 11; ++i)
81  label[i] = ' ';
82  label[11] = 0;
83 
84  ret = validate_volume_label(label);
85  if (ret & 0x1) {
86  fprintf(stderr,
87  "fatlabel: warning - lowercase labels might not work properly on some systems\n");
88  }
89  if (ret & 0x2) {
90  fprintf(stderr,
91  "fatlabel: labels with characters below 0x20 are not allowed\n");
92  exit(1);
93  }
94  if (ret & 0x4) {
95  fprintf(stderr,
96  "fatlabel: labels with characters *?.,;:/\\|+=<>[]\" are not allowed\n");
97  exit(1);
98  }
99  if (ret & 0x08) {
100  fprintf(stderr,
101  "fatlabel: labels can't be empty or white space only\n");
102  exit(1);
103  }
104  if (ret & 0x10) {
105  fprintf(stderr,
106  "fatlabel: labels can't start with a space character\n");
107  exit(1);
108  }
109  }
110 
111  fs_open(device, rw);
112  read_boot(&fs);
113 
114  if (!change && !reset) {
115  if (fs.fat_bits == 32)
116  read_fat(&fs, 0);
117 
118  offset = find_volume_de(&fs, &de);
119  if (offset != 0) {
120  if (de.name[0] == 0x05)
121  de.name[0] = 0xe5;
122  printf("%s\n", pretty_label((char *)de.name));
123  }
124 
125  if (fs.fat_bits == 32)
126  release_fat(&fs);
127 
128  exit(0);
129  }
130 
131  if (fs.fat_bits == 32)
132  read_fat(&fs, 1);
133 
134  if (!reset)
135  write_label(&fs, label);
136  else
137  remove_label(&fs);
138 
139  if (fs.fat_bits == 32)
140  release_fat(&fs);
141 }
142 
143 
144 static void handle_volid(bool change, bool reset, const char *device, const char *newserial)
145 {
146  DOS_FS fs = { 0 };
147  char *tmp;
148  long long conversion;
149  uint32_t serial = 0;
150 
151  if (change) {
152  errno = 0;
153  conversion = strtoll(newserial, &tmp, 16);
154 
155  if (!*newserial || isspace(*newserial) || *tmp || conversion < 0) {
156  fprintf(stderr, "fatlabel: volume ID must be a hexadecimal number\n");
157  exit(1);
158  }
159  if (conversion > UINT32_MAX) {
160  fprintf(stderr, "fatlabel: given volume ID does not fit in 32 bit\n");
161  exit(1);
162  }
163  if (errno) {
164  fprintf(stderr, "fatlabel: parsing volume ID failed (%s)\n", strerror(errno));
165  exit(1);
166  }
167 
168  serial = conversion;
169  }
170 
171  if (reset)
172  serial = generate_volume_id();
173 
174  fs_open(device, rw);
175  read_boot(&fs);
176  if (!change && !reset) {
177  printf("%08x\n", fs.serial);
178  exit(0);
179  }
180 
181  write_serial(&fs, serial);
182 }
183 
184 
185 static void usage(int error, int usage_only)
186 {
187  FILE *f = error ? stderr : stdout;
188  int status = error ? 1 : 0;
189 
190  fprintf(f, "Usage: fatlabel [OPTIONS] DEVICE [NEW]\n");
191  if (usage_only)
192  exit(status);
193 
194  fprintf(f, "Change the FAT filesystem label or serial on DEVICE to NEW or display the\n");
195  fprintf(f, "existing label or serial if NEW is not given.\n");
196  fprintf(f, "\n");
197  fprintf(f, "Options:\n");
198  fprintf(f, " -i, --volume-id Work on serial number instead of label\n");
199  fprintf(f, " -r, --reset Remove label or generate new serial number\n");
200  fprintf(f, " -c N, --codepage=N use DOS codepage N to encode/decode label (default: %d)\n", DEFAULT_DOS_CODEPAGE);
201  fprintf(f, " -V, --version Show version number and terminate\n");
202  fprintf(f, " -h, --help Print this message and terminate\n");
203  exit(status);
204 }
205 
206 
207 int main(int argc, char *argv[])
208 {
209  const struct option long_options[] = {
210  {"volume-id", no_argument, NULL, 'i'},
211  {"reset", no_argument, NULL, 'r'},
212  {"codepage", required_argument, NULL, 'c'},
213  {"version", no_argument, NULL, 'V'},
214  {"help", no_argument, NULL, 'h'},
215  {0,}
216  };
217  bool change;
218  bool reset = false;
219  bool volid_mode = false;
220  char *device = NULL;
221  char *new = NULL;
222  char *tmp;
223  long codepage;
224  int c;
225 
226  check_atari();
227 
228  while ((c = getopt_long(argc, argv, "irc:Vh", long_options, NULL)) != -1) {
229  switch (c) {
230  case 'i':
231  volid_mode = 1;
232  break;
233 
234  case 'r':
235  reset = true;
236  break;
237 
238  case 'c':
239  errno = 0;
240  codepage = strtol(optarg, &tmp, 10);
241  if (!*optarg || isspace(*optarg) || *tmp || errno || codepage < 0 || codepage > INT_MAX) {
242  fprintf(stderr, "Invalid codepage : %s\n", optarg);
243  usage(1, 0);
244  }
245  if (!set_dos_codepage(codepage))
246  usage(1, 0);
247  break;
248 
249  case 'V':
250  printf("fatlabel " VERSION " (" VERSION_DATE ")\n");
251  exit(0);
252  break;
253 
254  case 'h':
255  usage(0, 0);
256  break;
257 
258  case '?':
259  usage(1, 0);
260  exit(1);
261 
262  default:
263  fprintf(stderr,
264  "Internal error: getopt_long() returned unexpected value %d\n", c);
265  exit(2);
266  }
267  }
268 
269  if (!set_dos_codepage(-1)) /* set default codepage if none was given in command line */
270  exit(1);
271 
272  if (optind == argc - 2) {
273  change = true;
274  } else if (optind == argc - 1) {
275  change = false;
276  } else {
277  usage(1, 1);
278  }
279 
280  if (change || reset)
281  rw = 1;
282 
283  if (change && reset) {
284  fprintf(stderr, "fatlabel: giving new value with --reset not allowed\n");
285  exit(1);
286  }
287 
288  device = argv[optind++];
289  if (change)
290  new = argv[optind];
291 
292  if (!volid_mode)
293  handle_label(change, reset, device, new);
294  else
295  handle_volid(change, reset, device, new);
296 
297  fs_close(rw);
298  return 0;
299 }
void write_label(DOS_FS *fs, char *label)
Definition: boot.c:718
const char * pretty_label(const char *label)
Definition: boot.c:747
off_t find_volume_de(DOS_FS *fs, DIR_ENT *de)
Definition: boot.c:629
void remove_label(DOS_FS *fs)
Definition: boot.c:729
void read_boot(DOS_FS *fs)
Definition: boot.c:415
void write_serial(DOS_FS *fs, uint32_t serial)
Definition: boot.c:624
int local_string_to_dos_string(char *out, char *in, unsigned int out_size)
Definition: charconv.c:358
int set_dos_codepage(int codepage)
Definition: charconv.c:339
#define DEFAULT_DOS_CODEPAGE
Definition: charconv.h:28
int validate_volume_label(char *doslabel)
Definition: common.c:324
void check_atari(void)
Definition: common.c:273
uint32_t generate_volume_id(void)
Definition: common.c:298
void release_fat(DOS_FS *fs)
Definition: fat.c:80
void read_fat(DOS_FS *fs, int mode)
Definition: fat.c:114
int verbose
Definition: fatlabel.c:49
static void handle_volid(bool change, bool reset, const char *device, const char *newserial)
Definition: fatlabel.c:144
int main(int argc, char *argv[])
Definition: fatlabel.c:207
int test
Definition: fatlabel.c:49
static void usage(int error, int usage_only)
Definition: fatlabel.c:185
int rw
Definition: fatlabel.c:49
int list
Definition: fatlabel.c:49
int no_spaces_in_sfns
Definition: fatlabel.c:49
void * mem_queue
Definition: fatlabel.c:52
long fat_table
Definition: fatlabel.c:50
static void handle_label(bool change, bool reset, const char *device, char *newlabel)
Definition: fatlabel.c:55
unsigned n_files
Definition: fatlabel.c:51
int fs_close(int write)
Definition: io.c:163
void fs_open(const char *path, int rw)
Definition: io.c:59
#define error(str)
Definition: mkfs.fat.c:1351
uint8_t name[11]
Definition: fsck.fat.h:130
unsigned int fat_bits
Definition: fsck.fat.h:161
uint32_t serial
Definition: fsck.fat.h:174