fatlabel.c (dosfstools-4.1) | : | fatlabel.c (dosfstools-4.2) | ||
---|---|---|---|---|
/* fatlabel.c - User interface | /* fatlabel.c - User interface | |||
Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch> | Copyright (C) 1993 Werner Almesberger <werner.almesberger@lrc.di.epfl.ch> | |||
Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> | Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> | |||
Copyright (C) 2007 Red Hat, Inc. | Copyright (C) 2007 Red Hat, Inc. | |||
Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch> | Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch> | |||
Copyright (C) 2015 Andreas Bombe <aeb@debian.org> | Copyright (C) 2015-2017 Andreas Bombe <aeb@debian.org> | |||
Copyright (C) 2017-2018 Pali Rohár <pali.rohar@gmail.com> | ||||
This program is free software: you can redistribute it and/or modify | This program is free software: you can redistribute it and/or modify | |||
it under the terms of the GNU General Public License as published by | it under the terms of the GNU General Public License as published by | |||
the Free Software Foundation, either version 3 of the License, or | the Free Software Foundation, either version 3 of the License, or | |||
(at your option) any later version. | (at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU General Public License for more details. | GNU General Public License for more details. | |||
You should have received a copy of the GNU General Public License | You should have received a copy of the GNU General Public License | |||
along with this program. If not, see <http://www.gnu.org/licenses/>. | along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
The complete text of the GNU General Public License | The complete text of the GNU General Public License | |||
can be found in /usr/share/common-licenses/GPL-3 file. | can be found in /usr/share/common-licenses/GPL-3 file. | |||
*/ | */ | |||
#include "version.h" | #include "version.h" | |||
#include <stdbool.h> | ||||
#include <errno.h> | ||||
#include <stdio.h> | #include <stdio.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <string.h> | #include <string.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <limits.h> | ||||
#include <unistd.h> | #include <unistd.h> | |||
#include <getopt.h> | #include <getopt.h> | |||
#include <ctype.h> | #include <ctype.h> | |||
#include "common.h" | #include "common.h" | |||
#include "fsck.fat.h" | #include "fsck.fat.h" | |||
#include "io.h" | #include "io.h" | |||
#include "boot.h" | #include "boot.h" | |||
#include "fat.h" | #include "fat.h" | |||
#include "file.h" | #include "file.h" | |||
#include "check.h" | #include "check.h" | |||
#include "charconv.h" | ||||
int interactive = 0, rw = 0, list = 0, test = 0, verbose = 0, write_immed = 0; | int rw = 0, list = 0, test = 0, verbose = 0, no_spaces_in_sfns = 0; | |||
int atari_format = 0; | long fat_table = 0; | |||
unsigned n_files = 0; | unsigned n_files = 0; | |||
void *mem_queue = NULL; | void *mem_queue = NULL; | |||
static void usage(int error) | static void handle_label(bool change, bool reset, const char *device, char *newl abel) | |||
{ | { | |||
FILE *f = error ? stderr : stdout; | DOS_FS fs = { 0 }; | |||
int status = error ? 1 : 0; | off_t offset; | |||
DIR_ENT de; | ||||
fprintf(f, "usage: fatlabel device [label]\n"); | char label[12] = { 0 }; | |||
exit(status); | size_t len; | |||
} | int ret; | |||
int i; | ||||
/* | if (change) { | |||
* ++roman: On m68k, check if this is an Atari; if yes, turn on Atari variant | len = mbstowcs(NULL, newlabel, 0); | |||
* of MS-DOS filesystem by default. | if (len != (size_t)-1 && len > 11) { | |||
*/ | fprintf(stderr, | |||
static void check_atari(void) | "fatlabel: labels can be no longer than 11 characters\n"); | |||
{ | exit(1); | |||
#ifdef __mc68000__ | ||||
FILE *f; | ||||
char line[128], *p; | ||||
if (!(f = fopen("/proc/hardware", "r"))) { | ||||
perror("/proc/hardware"); | ||||
return; | ||||
} | ||||
while (fgets(line, sizeof(line), f)) { | ||||
if (strncmp(line, "Model:", 6) == 0) { | ||||
p = line + 6; | ||||
p += strspn(p, " \t"); | ||||
if (strncmp(p, "Atari ", 6) == 0) | ||||
atari_format = 1; | ||||
break; | ||||
} | } | |||
} | ||||
fclose(f); | ||||
#endif | ||||
} | ||||
int main(int argc, char *argv[]) | if (!local_string_to_dos_string(label, newlabel, 12)) { | |||
{ | fprintf(stderr, | |||
DOS_FS fs = { 0 }; | "fatlabel: error when processing label\n"); | |||
rw = 0; | exit(1); | |||
} | ||||
int i; | for (i = strlen(label); i < 11; ++i) | |||
label[i] = ' '; | ||||
label[11] = 0; | ||||
char *device = NULL; | ret = validate_volume_label(label); | |||
char label[12] = { 0 }; | if (ret & 0x1) { | |||
fprintf(stderr, | ||||
"fatlabel: warning - lowercase labels might not work properly | ||||
on some systems\n"); | ||||
} | ||||
if (ret & 0x2) { | ||||
fprintf(stderr, | ||||
"fatlabel: labels with characters below 0x20 are not allowed\ | ||||
n"); | ||||
exit(1); | ||||
} | ||||
if (ret & 0x4) { | ||||
fprintf(stderr, | ||||
"fatlabel: labels with characters *?.,;:/\\|+=<>[]\" are not | ||||
allowed\n"); | ||||
exit(1); | ||||
} | ||||
if (ret & 0x08) { | ||||
fprintf(stderr, | ||||
"fatlabel: labels can't be empty or white space only\n"); | ||||
exit(1); | ||||
} | ||||
if (ret & 0x10) { | ||||
fprintf(stderr, | ||||
"fatlabel: labels can't start with a space character\n"); | ||||
exit(1); | ||||
} | ||||
} | ||||
off_t offset; | fs_open(device, rw); | |||
DIR_ENT de; | read_boot(&fs); | |||
check_atari(); | if (!change && !reset) { | |||
if (fs.fat_bits == 32) | ||||
read_fat(&fs, 0); | ||||
if (argc < 2 || argc > 3) | offset = find_volume_de(&fs, &de); | |||
usage(1); | if (offset != 0) { | |||
if (de.name[0] == 0x05) | ||||
de.name[0] = 0xe5; | ||||
printf("%s\n", pretty_label((char *)de.name)); | ||||
} | ||||
if (fs.fat_bits == 32) | ||||
release_fat(&fs); | ||||
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) | ||||
usage(0); | ||||
else if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) { | ||||
printf("fatlabel " VERSION " (" VERSION_DATE ")\n"); | ||||
exit(0); | exit(0); | |||
} | } | |||
device = argv[1]; | if (fs.fat_bits == 32) | |||
if (argc == 3) { | read_fat(&fs, 1); | |||
strncpy(label, argv[2], 11); | ||||
if (strlen(argv[2]) > 11) { | if (!reset) | |||
fprintf(stderr, | write_label(&fs, label); | |||
"fatlabel: labels can be no longer than 11 characters\n"); | else | |||
remove_label(&fs); | ||||
if (fs.fat_bits == 32) | ||||
release_fat(&fs); | ||||
} | ||||
static void handle_volid(bool change, bool reset, const char *device, const char | ||||
*newserial) | ||||
{ | ||||
DOS_FS fs = { 0 }; | ||||
char *tmp; | ||||
long long conversion; | ||||
uint32_t serial = 0; | ||||
if (change) { | ||||
errno = 0; | ||||
conversion = strtoll(newserial, &tmp, 16); | ||||
if (!*newserial || isspace(*newserial) || *tmp || conversion < 0) { | ||||
fprintf(stderr, "fatlabel: volume ID must be a hexadecimal number\n") | ||||
; | ||||
exit(1); | exit(1); | |||
} | } | |||
for (i = 0; label[i] && i < 11; i++) | if (conversion > UINT32_MAX) { | |||
/* don't know if here should be more strict !uppercase(label[i]) */ | fprintf(stderr, "fatlabel: given volume ID does not fit in 32 bit\n") | |||
if (islower(label[i])) { | ; | |||
fprintf(stderr, | exit(1); | |||
"fatlabel: warning - lowercase labels might not work prop | } | |||
erly with DOS or Windows\n"); | if (errno) { | |||
break; | fprintf(stderr, "fatlabel: parsing volume ID failed (%s)\n", strerror | |||
} | (errno)); | |||
rw = 1; | exit(1); | |||
} | ||||
serial = conversion; | ||||
} | } | |||
if (reset) | ||||
serial = generate_volume_id(); | ||||
fs_open(device, rw); | fs_open(device, rw); | |||
read_boot(&fs); | read_boot(&fs); | |||
if (fs.fat_bits == 32) | if (!change && !reset) { | |||
read_fat(&fs); | printf("%08x\n", fs.serial); | |||
if (!rw) { | ||||
offset = find_volume_de(&fs, &de); | ||||
if (offset == 0) | ||||
fprintf(stdout, "%s\n", fs.label); | ||||
else | ||||
fprintf(stdout, "%.8s%.3s\n", de.name, de.name + 8); | ||||
exit(0); | exit(0); | |||
} | } | |||
write_label(&fs, label); | write_serial(&fs, serial); | |||
} | ||||
static void usage(int error, int usage_only) | ||||
{ | ||||
FILE *f = error ? stderr : stdout; | ||||
int status = error ? 1 : 0; | ||||
fprintf(f, "Usage: fatlabel [OPTIONS] DEVICE [NEW]\n"); | ||||
if (usage_only) | ||||
exit(status); | ||||
fprintf(f, "Change the FAT filesystem label or serial on DEVICE to NEW or di | ||||
splay the\n"); | ||||
fprintf(f, "existing label or serial if NEW is not given.\n"); | ||||
fprintf(f, "\n"); | ||||
fprintf(f, "Options:\n"); | ||||
fprintf(f, " -i, --volume-id Work on serial number instead of label\n") | ||||
; | ||||
fprintf(f, " -r, --reset Remove label or generate new serial number | ||||
\n"); | ||||
fprintf(f, " -c N, --codepage=N use DOS codepage N to encode/decode label | ||||
(default: %d)\n", DEFAULT_DOS_CODEPAGE); | ||||
fprintf(f, " -V, --version Show version number and terminate\n"); | ||||
fprintf(f, " -h, --help Print this message and terminate\n"); | ||||
exit(status); | ||||
} | ||||
int main(int argc, char *argv[]) | ||||
{ | ||||
const struct option long_options[] = { | ||||
{"volume-id", no_argument, NULL, 'i'}, | ||||
{"reset", no_argument, NULL, 'r'}, | ||||
{"codepage", required_argument, NULL, 'c'}, | ||||
{"version", no_argument, NULL, 'V'}, | ||||
{"help", no_argument, NULL, 'h'}, | ||||
{0,} | ||||
}; | ||||
bool change; | ||||
bool reset = false; | ||||
bool volid_mode = false; | ||||
char *device = NULL; | ||||
char *new = NULL; | ||||
char *tmp; | ||||
long codepage; | ||||
int c; | ||||
check_atari(); | ||||
while ((c = getopt_long(argc, argv, "irc:Vh", long_options, NULL)) != -1) { | ||||
switch (c) { | ||||
case 'i': | ||||
volid_mode = 1; | ||||
break; | ||||
case 'r': | ||||
reset = true; | ||||
break; | ||||
case 'c': | ||||
errno = 0; | ||||
codepage = strtol(optarg, &tmp, 10); | ||||
if (!*optarg || isspace(*optarg) || *tmp || errno || codepage < 0 | ||||
|| codepage > INT_MAX) { | ||||
fprintf(stderr, "Invalid codepage : %s\n", optarg); | ||||
usage(1, 0); | ||||
} | ||||
if (!set_dos_codepage(codepage)) | ||||
usage(1, 0); | ||||
break; | ||||
case 'V': | ||||
printf("fatlabel " VERSION " (" VERSION_DATE ")\n"); | ||||
exit(0); | ||||
break; | ||||
case 'h': | ||||
usage(0, 0); | ||||
break; | ||||
case '?': | ||||
usage(1, 0); | ||||
exit(1); | ||||
default: | ||||
fprintf(stderr, | ||||
"Internal error: getopt_long() returned unexpected value | ||||
%d\n", c); | ||||
exit(2); | ||||
} | ||||
} | ||||
if (!set_dos_codepage(-1)) /* set default codepage if none was given in comm | ||||
and line */ | ||||
exit(1); | ||||
if (optind == argc - 2) { | ||||
change = true; | ||||
} else if (optind == argc - 1) { | ||||
change = false; | ||||
} else { | ||||
usage(1, 1); | ||||
} | ||||
if (change || reset) | ||||
rw = 1; | ||||
if (change && reset) { | ||||
fprintf(stderr, "fatlabel: giving new value with --reset not allowed\n"); | ||||
exit(1); | ||||
} | ||||
device = argv[optind++]; | ||||
if (change) | ||||
new = argv[optind]; | ||||
if (!volid_mode) | ||||
handle_label(change, reset, device, new); | ||||
else | ||||
handle_volid(change, reset, device, new); | ||||
fs_close(rw); | fs_close(rw); | |||
return 0; | return 0; | |||
} | } | |||
End of changes. 22 change blocks. | ||||
75 lines changed or deleted | 238 lines changed or added |