1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2019 Namjae Jeon <linkinjeon@kernel.org>
14 #include "exfat_ondisk.h"
17 static void usage(void)
19 fprintf(stderr, "Usage: tune.exfat\n");
20 fprintf(stderr, "\t-l | --print-label Print volume label\n");
21 fprintf(stderr, "\t-L | --volume-label=label Set volume label\n");
22 fprintf(stderr, "\t-V | --version Show version\n");
23 fprintf(stderr, "\t-v | --verbose Print debug\n");
24 fprintf(stderr, "\t-h | --help Show help\n");
29 static struct option opts[] = {
30 {"print-label", no_argument, NULL, 'l' },
31 {"set-label", required_argument, NULL, 'L' },
32 {"version", no_argument, NULL, 'V' },
33 {"verbose", no_argument, NULL, 'v' },
34 {"help", no_argument, NULL, 'h' },
35 {"?", no_argument, NULL, '?' },
39 static off_t exfat_get_root_entry_offset(struct exfat_blk_dev *bd)
43 unsigned int cluster_size;
46 bs = (struct pbr *)malloc(sizeof(struct pbr));
48 exfat_err("failed to allocate memory\n");
52 nbytes = exfat_read(bd->dev_fd, bs, sizeof(struct pbr), 0);
53 if (nbytes != sizeof(struct pbr)) {
54 exfat_err("boot sector read failed: %d\n", errno);
58 cluster_size = (1 << bs->bsx.sect_per_clus_bits) * bd->sector_size;
59 root_clu_off = le32_to_cpu(bs->bsx.clu_offset) * bd->sector_size +
60 le32_to_cpu(bs->bsx.root_cluster - EXFAT_REVERVED_CLUSTERS)
67 static int exfat_get_volume_label(struct exfat_blk_dev *bd, off_t root_clu_off)
69 struct exfat_dentry *vol_entry;
70 char volume_label[VOLUME_LABEL_BUFFER_SIZE];
71 __le16 disk_label[VOLUME_LABEL_MAX_LEN];
74 vol_entry = malloc(sizeof(struct exfat_dentry));
76 exfat_err("failed to allocate memory\n");
80 nbytes = exfat_read(bd->dev_fd, vol_entry,
81 sizeof(struct exfat_dentry), root_clu_off);
82 if (nbytes != sizeof(struct exfat_dentry)) {
83 exfat_err("volume entry read failed: %d\n", errno);
87 memcpy(disk_label, vol_entry->vol_label, sizeof(disk_label));
88 memset(volume_label, 0, sizeof(volume_label));
89 if (exfat_utf16_dec(disk_label, vol_entry->vol_char_cnt*2,
90 volume_label, sizeof(volume_label)) < 0) {
91 exfat_err("failed to decode volume label\n");
95 exfat_info("label: %s\n", volume_label);
99 static int exfat_set_volume_label(struct exfat_blk_dev *bd,
100 char *label_input, off_t root_clu_off)
102 struct exfat_dentry vol;
104 __u16 volume_label[VOLUME_LABEL_MAX_LEN];
105 int volume_label_len;
107 volume_label_len = exfat_utf16_enc(label_input,
108 volume_label, sizeof(volume_label));
109 if (volume_label_len < 0) {
110 exfat_err("failed to encode volume label\n");
114 vol.type = EXFAT_VOLUME;
115 memset(vol.vol_label, 0, sizeof(vol.vol_label));
116 memcpy(vol.vol_label, volume_label, volume_label_len);
117 vol.vol_char_cnt = volume_label_len/2;
119 nbytes = exfat_write(bd->dev_fd, &vol, sizeof(struct exfat_dentry),
121 if (nbytes != sizeof(struct exfat_dentry)) {
122 exfat_err("volume entry write failed: %d\n", errno);
127 exfat_info("new label: %s\n", label_input);
131 #define EXFAT_GET_LABEL 0x1
132 #define EXFAT_SET_LABEL 0x2
134 int main(int argc, char *argv[])
137 int ret = EXIT_FAILURE;
138 struct exfat_blk_dev bd;
139 struct exfat_user_input ui;
140 bool version_only = false;
142 char label_input[VOLUME_LABEL_BUFFER_SIZE];
145 init_user_input(&ui);
147 if (!setlocale(LC_CTYPE, ""))
148 exfat_err("failed to init locale/codeset\n");
151 while ((c = getopt_long(argc, argv, "L:lVvh", opts, NULL)) != EOF)
154 flags = EXFAT_GET_LABEL;
157 snprintf(label_input, sizeof(label_input), "%s",
159 flags = EXFAT_SET_LABEL;
165 print_level = EXFAT_DEBUG;
180 memset(ui.dev_name, 0, sizeof(ui.dev_name));
181 snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[argc - 1]);
183 ret = exfat_get_blk_dev_info(&ui, &bd);
187 root_clu_off = exfat_get_root_entry_offset(&bd);
188 if (root_clu_off < 0)
191 if (flags == EXFAT_GET_LABEL)
192 ret = exfat_get_volume_label(&bd, root_clu_off);
193 else if (flags == EXFAT_SET_LABEL)
194 ret = exfat_set_volume_label(&bd, label_input, root_clu_off);