]> git.sven.stormbind.net Git - sven/exfatprogs.git/blob - label/label.c
releasing package exfatprogs version 1.2.3-1
[sven/exfatprogs.git] / label / label.c
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
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
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         unsigned long volume_serial;
46
47         init_user_input(&ui);
48
49         if (!setlocale(LC_CTYPE, ""))
50                 exfat_err("failed to init locale/codeset\n");
51
52         if (argc == 2)
53                 flags = EXFAT_GET_VOLUME_LABEL;
54         else if (argc == 3)
55                 flags = EXFAT_SET_VOLUME_LABEL;
56
57         opterr = 0;
58         while ((c = getopt_long(argc, argv, "iVh", opts, NULL)) != EOF)
59                 switch (c) {
60                 case 'i':
61                         serial_mode = true;
62                         if (argc == 3)
63                                 flags = EXFAT_GET_VOLUME_SERIAL;
64                         else if (argc == 4)
65                                 flags = EXFAT_SET_VOLUME_SERIAL;
66
67                         break;
68                 case 'V':
69                         version_only = true;
70                         break;
71                 case '?':
72                 case 'h':
73                 default:
74                         usage();
75         }
76
77         show_version();
78         if (version_only)
79                 exit(EXIT_FAILURE);
80
81         if (argc < 2)
82                 usage();
83
84         memset(ui.dev_name, 0, sizeof(ui.dev_name));
85         snprintf(ui.dev_name, sizeof(ui.dev_name), "%s", argv[serial_mode + 1]);
86
87         ret = exfat_get_blk_dev_info(&ui, &bd);
88         if (ret < 0)
89                 goto out;
90
91         if (serial_mode) {
92                 /* Mode to change or display volume serial */
93                 if (flags == EXFAT_GET_VOLUME_SERIAL) {
94                         ret = exfat_show_volume_serial(bd.dev_fd);
95                 } else if (flags == EXFAT_SET_VOLUME_SERIAL) {
96                         ret = exfat_parse_ulong(argv[3], &volume_serial);
97                         if (volume_serial > UINT_MAX)
98                                 ret = -ERANGE;
99
100
101                         if (ret < 0) {
102                                 exfat_err("invalid serial number(%s)\n", argv[3]);
103                                 goto close_fd_out;
104                         }
105
106                         ui.volume_serial = volume_serial;
107                         ret = exfat_set_volume_serial(&bd, &ui);
108                 }
109         } else {
110                 struct exfat *exfat;
111                 struct pbr *bs;
112
113                 ret = read_boot_sect(&bd, &bs);
114                 if (ret)
115                         goto close_fd_out;
116
117                 exfat = exfat_alloc_exfat(&bd, bs);
118                 if (!exfat) {
119                         ret = -ENOMEM;
120                         goto close_fd_out;
121                 }
122
123                 exfat->root = exfat_alloc_inode(ATTR_SUBDIR);
124                 if (!exfat->root) {
125                         ret = -ENOMEM;
126                         goto free_exfat;
127                 }
128
129                 exfat->root->first_clus = le32_to_cpu(exfat->bs->bsx.root_cluster);
130                 if (exfat_root_clus_count(exfat)) {
131                         exfat_err("failed to follow the cluster chain of root\n");
132                         exfat_free_inode(exfat->root);
133                         ret = -EINVAL;
134                         goto free_exfat;
135                 }
136
137                 /* Mode to change or display volume label */
138                 if (flags == EXFAT_GET_VOLUME_LABEL)
139                         ret = exfat_read_volume_label(exfat);
140                 else if (flags == EXFAT_SET_VOLUME_LABEL)
141                         ret = exfat_set_volume_label(exfat, argv[2]);
142
143 free_exfat:
144                 if (exfat)
145                         exfat_free_exfat(exfat);
146         }
147
148 close_fd_out:
149         close(bd.dev_fd);
150 out:
151         return ret;
152 }