]> git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/swaplabel.c
swaplabel: new command
[thirdparty/util-linux.git] / disk-utils / swaplabel.c
1 /*
2 * swaplabel.c - Print or change the label / UUID of a swap partition
3 *
4 * Copyright (C) 2010 Jason Borden <jborden@bluehost.com>
5 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
6 *
7 * Usage: swaplabel [-L label] [-U UUID] device
8 *
9 * This file may be redistributed under the terms of the GNU Public License
10 * version 2 or later.
11 *
12 */
13 #include <stdio.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include <fcntl.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <err.h>
22 #include <blkid.h>
23 #include <getopt.h>
24
25 #ifdef HAVE_LIBUUID
26 # ifdef HAVE_UUID_UUID_H
27 # include <uuid/uuid.h>
28 # else
29 # include <uuid.h>
30 # endif
31 #endif
32
33 #include "c.h"
34 #include "writeall.h"
35 #include "swapheader.h"
36 #include "xstrncpy.h"
37 #include "nls.h"
38
39 #define SWAP_UUID_OFFSET (offsetof(struct swap_header_v1_2, uuid))
40 #define SWAP_LABEL_OFFSET (offsetof(struct swap_header_v1_2, volume_name))
41
42 /*
43 * Returns new libblkid prober. This function call exit() on error.
44 */
45 static blkid_probe get_swap_prober(const char *devname)
46 {
47 blkid_probe pr;
48 int rc;
49 const char *version = NULL;
50 char *swap_filter[] = { "swap", NULL };
51
52 pr = blkid_new_probe_from_filename(devname);
53 if (!pr) {
54 warn(_("%s: unable to probe device"), devname);
55 return NULL;
56 }
57
58 blkid_probe_enable_superblocks(pr, TRUE);
59 blkid_probe_set_superblocks_flags(pr,
60 BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
61 BLKID_SUBLKS_VERSION);
62
63 blkid_probe_filter_superblocks_type(pr, BLKID_FLTR_ONLYIN, swap_filter);
64
65 rc = blkid_do_safeprobe(pr);
66 if (rc == -1)
67 warn(_("%s: unable to probe device"), devname);
68 else if (rc == -2)
69 warnx(_("%s: ambivalent probing result, use wipefs(8)"), devname);
70 else if (rc == 1)
71 warnx(_("%s: not a valid swap partition"), devname);
72
73 if (rc == 0) {
74 /* supported is SWAPSPACE2 only */
75 blkid_probe_lookup_value(pr, "VERSION", &version, NULL);
76 if (strcmp(version, "2"))
77 warnx(_("%s: unsupported swap version '%s'"),
78 devname, version);
79 else
80 return pr;
81 }
82
83 blkid_free_probe(pr);
84 return NULL;
85 }
86
87 /* Print the swap partition information */
88 static int print_info(blkid_probe pr, const char *devname)
89 {
90 const char *data;
91
92 if (!blkid_probe_lookup_value(pr, "LABEL", &data, NULL))
93 printf("LABEL: %s\n", data);
94
95 if (!blkid_probe_lookup_value(pr, "UUID", &data, NULL))
96 printf("UUID: %s\n", data);
97
98 return 0;
99 }
100
101 /* Change the swap partition info */
102 static int change_info(const char *devname, const char *label, const char *uuid)
103 {
104 int fd;
105
106 fd = open(devname, O_RDWR);
107 if (fd < 0) {
108 warn(_("%s: failed to open"), devname);
109 goto err;
110 }
111 #ifdef HAVE_LIBUUID
112 /* Write the uuid if it was provided */
113 if (uuid) {
114 uuid_t newuuid;
115
116 if (uuid_parse(uuid, newuuid) == -1)
117 warnx(_("failed to parse UUID: %s"), uuid);
118 else {
119 if (lseek(fd, SWAP_UUID_OFFSET, SEEK_SET) !=
120 SWAP_UUID_OFFSET) {
121 warn(_("%s: failed to seek to swap UUID"), devname);
122 goto err;
123
124 } else if (write_all(fd, newuuid, sizeof(newuuid))) {
125 warn(_("%s: failed to write UUID"), devname);
126 goto err;
127 }
128 }
129 }
130 #endif
131 /* Write the label if it was provided */
132 if (label) {
133 char newlabel[SWAP_LABEL_LENGTH];
134
135 if (lseek(fd, SWAP_LABEL_OFFSET, SEEK_SET) != SWAP_LABEL_OFFSET) {
136 warn(_("%s: failed to seek to swap label "), devname);
137 goto err;
138 }
139 memset(newlabel, 0, sizeof(newlabel));
140 xstrncpy(newlabel, label, sizeof(newlabel));
141
142 if (strlen(label) > strlen(newlabel))
143 warnx(_("label is too long. Truncating it to '%s'"),
144 newlabel);
145 if (write_all(fd, newlabel, sizeof(newlabel))) {
146 warn(_("%s: failed to write label"), devname);
147 goto err;
148 }
149 }
150
151 close(fd);
152 return 0;
153 err:
154 if (fd >= 0)
155 close(fd);
156 return -1;
157 }
158
159 static void __attribute__((__noreturn__)) usage(FILE *out)
160 {
161 fprintf(out, _("Usage: %s [options] <device>\n\nOptions:\n"),
162 program_invocation_short_name);
163
164 fprintf(out, _(
165 " -h, --help this help\n"
166 " -L, --label <label> specify a new label\n"
167 " -U, --uuid <uuid> specify a new uuid\n"));
168
169 fprintf(out, _("\nFor more information see swaplabel(8).\n"));
170
171 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
172 }
173
174 int main(int argc, char *argv[])
175 {
176 blkid_probe pr = NULL;
177 char *uuid = NULL, *label = NULL, *devname;
178 int c, rc = -1;
179
180 struct option longopts[] = {
181 { "help", 0, 0, 'h' },
182 { "label", 1, 0, 'L' },
183 { "uuid", 1, 0, 'U' },
184 { NULL, 0, 0, 0 }
185 };
186
187 setlocale(LC_ALL, "");
188 bindtextdomain(PACKAGE, LOCALEDIR);
189 textdomain(PACKAGE);
190
191 while ((c = getopt_long(argc, argv, "hL:U:", longopts, NULL)) != -1) {
192 switch (c) {
193 case 'h':
194 usage(stdout);
195 break;
196 case 'L':
197 label = optarg;
198 break;
199 case 'U':
200 #ifdef HAVE_LIBUUID
201 uuid = optarg;
202 #else
203 warnx(_("ignore -U (UUIDs are unsupported)"));
204 #endif
205 break;
206 default:
207 usage(stderr);
208 break;
209 }
210 }
211
212 if (optind == argc)
213 usage(stderr);
214
215 devname = argv[optind];
216 pr = get_swap_prober(devname);
217 if (pr) {
218 if (uuid || label)
219 rc = change_info(devname, label, uuid);
220 else
221 rc = print_info(pr, devname);
222 blkid_free_probe(pr);
223 }
224 return rc ? EXIT_FAILURE : EXIT_SUCCESS;
225 }
226