• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *   Copyright (C) 2020 Namjae Jeon <linkinjeon@kernel.org>
4  */
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <getopt.h>
11 #include <errno.h>
12 #include <locale.h>
13 
14 #include "exfat_ondisk.h"
15 #include "libexfat.h"
16 #include "exfat_fs.h"
17 
usage(void)18 static void usage(void)
19 {
20 	fprintf(stderr, "Usage: exfatlabel\n");
21 	fprintf(stderr, "\t-i | --volume-serial                  Switch to volume serial mode\n");
22 	fprintf(stderr, "\t-V | --version                        Show version\n");
23 	fprintf(stderr, "\t-h | --help                           Show help\n");
24 
25 	exit(EXIT_FAILURE);
26 }
27 
28 static struct option opts[] = {
29 	{"volume-serial",	no_argument,		NULL,	'i' },
30 	{"version",		no_argument,		NULL,	'V' },
31 	{"help",		no_argument,		NULL,	'h' },
32 	{"?",			no_argument,		NULL,	'?' },
33 	{NULL,			0,			NULL,	 0  }
34 };
35 
main(int argc,char * argv[])36 int main(int argc, char *argv[])
37 {
38 	int c;
39 	int ret = EXIT_FAILURE;
40 	struct exfat_blk_dev bd;
41 	struct exfat_user_input ui;
42 	bool version_only = false;
43 	int serial_mode = 0;
44 	int flags = 0;
45 
46 	init_user_input(&ui);
47 
48 	if (!setlocale(LC_CTYPE, ""))
49 		exfat_err("failed to init locale/codeset\n");
50 
51 	if (argc == 2)
52 		flags = EXFAT_GET_VOLUME_LABEL;
53 	else if (argc == 3)
54 		flags = EXFAT_SET_VOLUME_LABEL;
55 
56 	opterr = 0;
57 	while ((c = getopt_long(argc, argv, "iVh", opts, NULL)) != EOF)
58 		switch (c) {
59 		case 'i':
60 			serial_mode = true;
61 			if (argc == 3)
62 				flags = EXFAT_GET_VOLUME_SERIAL;
63 			else if (argc == 4)
64 				flags = EXFAT_SET_VOLUME_SERIAL;
65 
66 			break;
67 		case 'V':
68 			version_only = true;
69 			break;
70 		case '?':
71 		case 'h':
72 		default:
73 			usage();
74 	}
75 
76 	show_version();
77 	if (version_only)
78 		exit(EXIT_FAILURE);
79 
80 	if (argc < 2)
81 		usage();
82 
83 	memset(ui.dev_name, 0, sizeof(ui.dev_name));
84 	snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[serial_mode + 1]);
85 
86 	ret = exfat_get_blk_dev_info(&ui, &bd);
87 	if (ret < 0)
88 		goto out;
89 
90 	if (serial_mode) {
91 		/* Mode to change or display volume serial */
92 		if (flags == EXFAT_GET_VOLUME_SERIAL) {
93 			ret = exfat_show_volume_serial(bd.dev_fd);
94 		} else if (flags == EXFAT_SET_VOLUME_SERIAL) {
95 			ui.volume_serial = strtoul(argv[3], NULL, 0);
96 			ret = exfat_set_volume_serial(&bd, &ui);
97 		}
98 	} else {
99 		struct exfat *exfat;
100 		struct pbr *bs;
101 
102 		ret = read_boot_sect(&bd, &bs);
103 		if (ret)
104 			goto close_fd_out;
105 
106 		exfat = exfat_alloc_exfat(&bd, bs);
107 		if (!exfat) {
108 			free(bs);
109 			ret = -ENOMEM;
110 			goto close_fd_out;
111 		}
112 
113 		exfat->root = exfat_alloc_inode(ATTR_SUBDIR);
114 		if (!exfat->root) {
115 			ret = -ENOMEM;
116 			goto free_exfat;
117 		}
118 
119 		exfat->root->first_clus = le32_to_cpu(exfat->bs->bsx.root_cluster);
120 		if (exfat_root_clus_count(exfat)) {
121 			exfat_err("failed to follow the cluster chain of root\n");
122 			exfat_free_inode(exfat->root);
123 			ret = -EINVAL;
124 			goto free_exfat;
125 		}
126 
127 		/* Mode to change or display volume label */
128 		if (flags == EXFAT_GET_VOLUME_LABEL)
129 			ret = exfat_read_volume_label(exfat);
130 		else if (flags == EXFAT_SET_VOLUME_LABEL)
131 			ret = exfat_set_volume_label(exfat, argv[2]);
132 
133 free_exfat:
134 		if (exfat)
135 			exfat_free_exfat(exfat);
136 	}
137 
138 close_fd_out:
139 	close(bd.dev_fd);
140 out:
141 	return ret;
142 }
143