]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/blkdiscard.c
build-sys: check for libtoolize rather than libtool
[thirdparty/util-linux.git] / sys-utils / blkdiscard.c
CommitLineData
d964b669
LC
1/*
2 * blkdiscard.c -- discard the part (or whole) of the block device.
3 *
4 * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
5 * Written by Lukas Czerner <lczerner@redhat.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * This program uses BLKDISCARD ioctl to discard part or the whole block
21 * device if the device supports it. You can specify range (start and
22 * length) to be discarded, or simply discard the whole device.
23 */
24
25
26#include <string.h>
27#include <unistd.h>
28#include <stdlib.h>
29#include <stdio.h>
30#include <stdint.h>
31#include <fcntl.h>
32#include <limits.h>
33#include <getopt.h>
34
35#include <sys/ioctl.h>
36#include <sys/stat.h>
37#include <linux/fs.h>
38
39#include "nls.h"
40#include "strutils.h"
41#include "c.h"
42#include "closestream.h"
43
44#ifndef BLKDISCARD
45#define BLKDISCARD _IO(0x12,119)
46#endif
47
48#ifndef BLKSECDISCARD
49#define BLKSECDISCARD _IO(0x12,125)
50#endif
51
52static void __attribute__((__noreturn__)) usage(FILE *out)
53{
54 fputs(USAGE_HEADER, out);
55 fprintf(out,
56 _(" %s [options] <device>\n"), program_invocation_short_name);
57 fputs(USAGE_OPTIONS, out);
58 fputs(_(" -o, --offset <num> offset in bytes to discard from\n"
59 " -l, --length <num> length of bytes to discard from the offset\n"
60 " -s, --secure perform secure discard\n"
61 " -v, --verbose print aligned length and offset\n"),
62 out);
63 fputs(USAGE_SEPARATOR, out);
64 fputs(USAGE_HELP, out);
65 fputs(USAGE_VERSION, out);
66 fprintf(out, USAGE_MAN_TAIL("blkdiscard(8)"));
67 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
68}
69
70int main(int argc, char **argv)
71{
72 char *path;
88839459
TT
73 int c, fd, verbose = 0, secure = 0, secsize;
74 uint64_t end, blksize, range[2];
d964b669
LC
75 struct stat sb;
76
77 static const struct option longopts[] = {
78 { "help", 0, 0, 'h' },
79 { "version", 0, 0, 'V' },
80 { "offset", 1, 0, 'o' },
81 { "length", 1, 0, 'l' },
82 { "secure", 0, 0, 's' },
83 { "verbose", 0, 0, 'v' },
84 { NULL, 0, 0, 0 }
85 };
86
87 setlocale(LC_ALL, "");
88 bindtextdomain(PACKAGE, LOCALEDIR);
89 textdomain(PACKAGE);
90 atexit(close_stdout);
91
92 range[0] = 0;
93 range[1] = ULLONG_MAX;
94
95 while ((c = getopt_long(argc, argv, "hVsvo:l:", longopts, NULL)) != -1) {
96 switch(c) {
97 case 'h':
98 usage(stdout);
99 break;
100 case 'V':
101 printf(UTIL_LINUX_VERSION);
102 return EXIT_SUCCESS;
103 case 'l':
104 range[1] = strtosize_or_err(optarg,
105 _("failed to parse length"));
106 break;
107 case 'o':
108 range[0] = strtosize_or_err(optarg,
109 _("failed to parse offset"));
110 break;
111 case 's':
112 secure = 1;
113 break;
114 case 'v':
115 verbose = 1;
116 break;
117 default:
118 usage(stderr);
119 break;
120 }
121 }
122
123 if (optind == argc)
4ce393f4 124 errx(EXIT_FAILURE, _("no device specified"));
d964b669
LC
125
126 path = argv[optind++];
127
128 if (optind != argc) {
129 warnx(_("unexpected number of arguments"));
130 usage(stderr);
131 }
132
d964b669
LC
133 fd = open(path, O_WRONLY);
134 if (fd < 0)
135 err(EXIT_FAILURE, _("cannot open %s"), path);
136
77751922
KZ
137 if (fstat(fd, &sb) == -1)
138 err(EXIT_FAILURE, _("stat failed %s"), path);
139 if (!S_ISBLK(sb.st_mode))
140 errx(EXIT_FAILURE, _("%s: not a block device"), path);
141
d964b669
LC
142 if (ioctl(fd, BLKGETSIZE64, &blksize))
143 err(EXIT_FAILURE, _("%s: BLKGETSIZE64 ioctl failed"), path);
d964b669
LC
144 if (ioctl(fd, BLKSSZGET, &secsize))
145 err(EXIT_FAILURE, _("%s: BLKSSZGET ioctl failed"), path);
146
147 /* align range to the sector size */
148 range[0] = (range[0] + secsize - 1) & ~(secsize - 1);
149 range[1] &= ~(secsize - 1);
150
151 /* is the range end behind the end of the device ?*/
152 end = range[0] + range[1];
153 if (end < range[0] || end > blksize)
154 range[1] = blksize - range[0];
155
156 if (secure) {
157 if (ioctl(fd, BLKSECDISCARD, &range))
158 err(EXIT_FAILURE, _("%s: BLKSECDISCARD ioctl failed"), path);
159 } else {
160 if (ioctl(fd, BLKDISCARD, &range))
161 err(EXIT_FAILURE, _("%s: BLKDISCARD ioctl failed"), path);
162 }
163
164 if (verbose)
165 /* TRANSLATORS: The standard value here is a very large number. */
166 printf(_("%s: Discarded %" PRIu64 " bytes from the "
167 "offset %" PRIu64"\n"), path,
168 (uint64_t) range[1], (uint64_t) range[0]);
169
170 close(fd);
171 return EXIT_SUCCESS;
172}