]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/zramctl.c
Merge branch 'mbsencode' of https://github.com/yontalcar/util-linux
[thirdparty/util-linux.git] / sys-utils / zramctl.c
CommitLineData
0624d840 1/*
1c35e625 2 * zramctl - control compressed block devices in RAM
0624d840
KZ
3 *
4 * Copyright (c) 2014 Timofey Titovets <Nefelim4ag@gmail.com>
5 * Copyright (C) 2014 Karel Zak <kzak@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it would be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <getopt.h>
22#include <stdlib.h>
23#include <string.h>
24#include <stdarg.h>
25#include <assert.h>
e1b1c7b0
JS
26#include <sys/types.h>
27#include <dirent.h>
0624d840
KZ
28
29#include <libsmartcols.h>
30
31#include "c.h"
32#include "nls.h"
33#include "closestream.h"
34#include "strutils.h"
35#include "xalloc.h"
36#include "sysfs.h"
37#include "optutils.h"
38#include "ismounted.h"
5388c862 39#include "strv.h"
1ceb4077 40#include "path.h"
62725810 41#include "pathnames.h"
0624d840
KZ
42
43/*#define CONFIG_ZRAM_DEBUG*/
44
45#ifdef CONFIG_ZRAM_DEBUG
46# define DBG(x) do { fputs("zram: ", stderr); x; fputc('\n', stderr); } while(0)
47#else
48# define DBG(x)
49#endif
50
51/* status output columns */
52struct colinfo {
53 const char *name;
54 double whint;
55 int flags;
56 const char *help;
57};
58
59enum {
60 COL_NAME = 0,
61 COL_DISKSIZE,
62 COL_ORIG_SIZE,
63 COL_COMP_SIZE,
64 COL_ALGORITHM,
65 COL_STREAMS,
66 COL_ZEROPAGES,
67 COL_MEMTOTAL,
bffc9174
KZ
68 COL_MEMLIMIT,
69 COL_MEMUSED,
70 COL_MIGRATED,
0624d840
KZ
71 COL_MOUNTPOINT
72};
73
74static const struct colinfo infos[] = {
75 [COL_NAME] = { "NAME", 0.25, 0, N_("zram device name") },
1c35e625 76 [COL_DISKSIZE] = { "DISKSIZE", 5, SCOLS_FL_RIGHT, N_("limit on the uncompressed amount of data") },
0624d840
KZ
77 [COL_ORIG_SIZE] = { "DATA", 5, SCOLS_FL_RIGHT, N_("uncompressed size of stored data") },
78 [COL_COMP_SIZE] = { "COMPR", 5, SCOLS_FL_RIGHT, N_("compressed size of stored data") },
1c35e625 79 [COL_ALGORITHM] = { "ALGORITHM", 3, 0, N_("the selected compression algorithm") },
0624d840
KZ
80 [COL_STREAMS] = { "STREAMS", 3, SCOLS_FL_RIGHT, N_("number of concurrent compress operations") },
81 [COL_ZEROPAGES] = { "ZERO-PAGES", 3, SCOLS_FL_RIGHT, N_("empty pages with no allocated memory") },
82 [COL_MEMTOTAL] = { "TOTAL", 5, SCOLS_FL_RIGHT, N_("all memory including allocator fragmentation and metadata overhead") },
bffc9174 83 [COL_MEMLIMIT] = { "MEM-LIMIT", 5, SCOLS_FL_RIGHT, N_("memory limit used to store compressed data") },
1ab7abac 84 [COL_MEMUSED] = { "MEM-USED", 5, SCOLS_FL_RIGHT, N_("memory zram have been consumed to store compressed data") },
75a8e726 85 [COL_MIGRATED] = { "MIGRATED", 5, SCOLS_FL_RIGHT, N_("number of objects migrated by compaction") },
0624d840 86 [COL_MOUNTPOINT]= { "MOUNTPOINT",0.10, SCOLS_FL_TRUNC, N_("where the device is mounted") },
0624d840
KZ
87};
88
89static int columns[ARRAY_SIZE(infos) * 2] = {-1};
90static int ncolumns;
91
5388c862
KZ
92enum {
93 MM_ORIG_DATA_SIZE = 0,
94 MM_COMPR_DATA_SIZE,
95 MM_MEM_USED_TOTAL,
96 MM_MEM_LIMIT,
97 MM_MEM_USED_MAX,
98 MM_ZERO_PAGES,
99 MM_NUM_MIGRATED
100};
101
102static const char *mm_stat_names[] = {
103 [MM_ORIG_DATA_SIZE] = "orig_data_size",
104 [MM_COMPR_DATA_SIZE] = "compr_data_size",
105 [MM_MEM_USED_TOTAL] = "mem_used_total",
106 [MM_MEM_LIMIT] = "mem_limit",
107 [MM_MEM_USED_MAX] = "mem_used_max",
108 [MM_ZERO_PAGES] = "zero_pages",
109 [MM_NUM_MIGRATED] = "num_migrated"
110};
111
0624d840
KZ
112struct zram {
113 char devname[32];
114 struct sysfs_cxt sysfs;
5388c862
KZ
115 char **mm_stat;
116
62725810
KZ
117 unsigned int mm_stat_probed : 1,
118 control_probed : 1,
119 has_control : 1; /* has /sys/class/zram-control/ */
0624d840
KZ
120};
121
0624d840
KZ
122static unsigned int raw, no_headings, inbytes;
123
0624d840
KZ
124static int get_column_id(int num)
125{
126 assert(num < ncolumns);
127 assert(columns[num] < (int) ARRAY_SIZE(infos));
128 return columns[num];
129}
130
131static const struct colinfo *get_column_info(int num)
132{
133 return &infos[ get_column_id(num) ];
134}
135
136static int column_name_to_id(const char *name, size_t namesz)
137{
138 size_t i;
139
140 for (i = 0; i < ARRAY_SIZE(infos); i++) {
141 const char *cn = infos[i].name;
142
143 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
144 return i;
145 }
146 warnx(_("unknown column: %s"), name);
147 return -1;
148}
149
1ceb4077
KZ
150static void zram_reset_stat(struct zram *z)
151{
152 if (z) {
153 strv_free(z->mm_stat);
154 z->mm_stat = NULL;
155 z->mm_stat_probed = 0;
156 }
157}
158
0624d840
KZ
159static void zram_set_devname(struct zram *z, const char *devname, size_t n)
160{
161 assert(z);
162
163 if (!devname)
164 snprintf(z->devname, sizeof(z->devname), "/dev/zram%zu", n);
165 else {
166 strncpy(z->devname, devname, sizeof(z->devname));
167 z->devname[sizeof(z->devname) - 1] = '\0';
168 }
169
170 DBG(fprintf(stderr, "set devname: %s", z->devname));
171 sysfs_deinit(&z->sysfs);
1ceb4077 172 zram_reset_stat(z);
0624d840
KZ
173}
174
62725810
KZ
175static int zram_get_devnum(struct zram *z)
176{
177 int n;
178
179 assert(z);
180
181 if (sscanf(z->devname, "/dev/zram%d", &n) == 1)
182 return n;
183 return -EINVAL;
184}
185
0624d840
KZ
186static struct zram *new_zram(const char *devname)
187{
188 struct zram *z = xcalloc(1, sizeof(struct zram));
189
190 DBG(fprintf(stderr, "new: %p", z));
191 if (devname)
192 zram_set_devname(z, devname, 0);
193 return z;
194}
195
196static void free_zram(struct zram *z)
197{
198 if (!z)
199 return;
200 DBG(fprintf(stderr, "free: %p", z));
201 sysfs_deinit(&z->sysfs);
1ceb4077 202 zram_reset_stat(z);
0624d840
KZ
203 free(z);
204}
205
206static struct sysfs_cxt *zram_get_sysfs(struct zram *z)
207{
208 assert(z);
209
210 if (!z->sysfs.devno) {
211 dev_t devno = sysfs_devname_to_devno(z->devname, NULL);
212 if (!devno)
213 return NULL;
214 if (sysfs_init(&z->sysfs, devno, NULL))
215 return NULL;
342436c6 216 if (*z->devname != '/') {
9e930041 217 /* canonicalize the device name according to /sys */
342436c6
KZ
218 char name[PATH_MAX];
219 if (sysfs_get_devname(&z->sysfs, name, sizeof(name)))
220 snprintf(z->devname, sizeof(z->devname), "/dev/%s", name);
221 }
0624d840
KZ
222 }
223
224 return &z->sysfs;
225}
226
227static inline int zram_exist(struct zram *z)
228{
229 assert(z);
230
116c9ce2
KZ
231 errno = 0;
232 if (zram_get_sysfs(z) == NULL) {
233 errno = ENODEV;
0624d840 234 return 0;
116c9ce2 235 }
0624d840
KZ
236
237 DBG(fprintf(stderr, "%s exists", z->devname));
238 return 1;
239}
240
241static int zram_set_u64parm(struct zram *z, const char *attr, uint64_t num)
242{
243 struct sysfs_cxt *sysfs = zram_get_sysfs(z);
244 if (!sysfs)
245 return -EINVAL;
246 DBG(fprintf(stderr, "%s writing %ju to %s", z->devname, num, attr));
247 return sysfs_write_u64(sysfs, attr, num);
248}
249
250static int zram_set_strparm(struct zram *z, const char *attr, const char *str)
251{
252 struct sysfs_cxt *sysfs = zram_get_sysfs(z);
253 if (!sysfs)
254 return -EINVAL;
255 DBG(fprintf(stderr, "%s writing %s to %s", z->devname, str, attr));
256 return sysfs_write_string(sysfs, attr, str);
257}
258
259
260static int zram_used(struct zram *z)
261{
262 uint64_t size;
263 struct sysfs_cxt *sysfs = zram_get_sysfs(z);
264
265 if (sysfs &&
266 sysfs_read_u64(sysfs, "disksize", &size) == 0 &&
267 size > 0) {
268
269 DBG(fprintf(stderr, "%s used", z->devname));
270 return 1;
271 }
272 DBG(fprintf(stderr, "%s unused", z->devname));
273 return 0;
274}
275
62725810
KZ
276static int zram_has_control(struct zram *z)
277{
278 if (!z->control_probed) {
279 z->has_control = access(_PATH_SYS_CLASS "/zram-control/", F_OK) == 0 ? 1 : 0;
280 z->control_probed = 1;
281 DBG(fprintf(stderr, "zram-control: %s", z->has_control ? "yes" : "no"));
282 }
283
284 return z->has_control;
285}
286
287static int zram_control_add(struct zram *z)
288{
289 int n;
290
291 if (!zram_has_control(z))
292 return -ENOSYS;
293
294 n = path_read_s32(_PATH_SYS_CLASS "/zram-control/hot_add");
295 if (n < 0)
296 return n;
297
298 DBG(fprintf(stderr, "hot-add: %d", n));
299 zram_set_devname(z, NULL, n);
300 return 0;
301}
302
303static int zram_control_remove(struct zram *z)
304{
305 char str[sizeof stringify_value(INT_MAX)];
306 int n;
307
308 if (!zram_has_control(z))
309 return -ENOSYS;
310
311 n = zram_get_devnum(z);
312 if (n < 0)
313 return n;
314
315 DBG(fprintf(stderr, "hot-remove: %d", n));
316 snprintf(str, sizeof(str), "%d", n);
317 return path_write_str(str, _PATH_SYS_CLASS "/zram-control/hot_remove");
318}
319
0624d840
KZ
320static struct zram *find_free_zram(void)
321{
322 struct zram *z = new_zram(NULL);
323 size_t i;
324 int isfree = 0;
325
326 for (i = 0; isfree == 0; i++) {
327 DBG(fprintf(stderr, "find free: checking zram%zu", i));
328 zram_set_devname(z, NULL, i);
62725810 329 if (!zram_exist(z) && zram_control_add(z) != 0)
0624d840
KZ
330 break;
331 isfree = !zram_used(z);
332 }
333 if (!isfree) {
334 free_zram(z);
335 z = NULL;
336 }
337 return z;
338}
339
624e147b 340static char *get_mm_stat(struct zram *z, size_t idx, int bytes)
5388c862
KZ
341{
342 struct sysfs_cxt *sysfs;
343 const char *name;
344 uint64_t num;
345
346 assert(idx < ARRAY_SIZE(mm_stat_names));
347 assert(z);
348
349 sysfs = zram_get_sysfs(z);
350 if (!sysfs)
351 return NULL;
352
353 /* Linux >= 4.1 uses /sys/block/zram<id>/mm_stat */
354 if (!z->mm_stat && !z->mm_stat_probed) {
355 char *str;
356
357 str = sysfs_strdup(sysfs, "mm_stat");
358 if (str) {
359 z->mm_stat = strv_split(str, " ");
2546d54b
KZ
360
361 /* make sure kernel provides mm_stat as expected */
362 if (strv_length(z->mm_stat) < ARRAY_SIZE(mm_stat_names)) {
363 strv_free(z->mm_stat);
364 z->mm_stat = NULL;
365 }
5388c862
KZ
366 }
367 z->mm_stat_probed = 1;
368 free(str);
369
370 }
371
372 if (z->mm_stat) {
624e147b 373 if (bytes)
5388c862
KZ
374 return xstrdup(z->mm_stat[idx]);
375
376 num = strtou64_or_err(z->mm_stat[idx], _("Failed to parse mm_stat"));
377 return size_to_human_string(SIZE_SUFFIX_1LETTER, num);
378 }
379
380 /* Linux < 4.1 uses /sys/block/zram<id>/<attrname> */
381 name = mm_stat_names[idx];
624e147b 382 if (bytes)
5388c862
KZ
383 return sysfs_strdup(sysfs, name);
384 else if (sysfs_read_u64(sysfs, name, &num) == 0)
385 return size_to_human_string(SIZE_SUFFIX_1LETTER, num);
386 return NULL;
387}
388
0624d840
KZ
389static void fill_table_row(struct libscols_table *tb, struct zram *z)
390{
391 static struct libscols_line *ln;
392 struct sysfs_cxt *sysfs;
393 size_t i;
394 uint64_t num;
395
396 assert(tb);
397 assert(z);
398
399 DBG(fprintf(stderr, "%s: filling status table", z->devname));
400
401 sysfs = zram_get_sysfs(z);
402 if (!sysfs)
403 return;
404
405 ln = scols_table_new_line(tb, NULL);
406 if (!ln)
780ce22c 407 err(EXIT_FAILURE, _("failed to allocate output line"));
0624d840
KZ
408
409 for (i = 0; i < (size_t) ncolumns; i++) {
410 char *str = NULL;
411
412 switch (get_column_id(i)) {
413 case COL_NAME:
414 str = xstrdup(z->devname);
415 break;
416 case COL_DISKSIZE:
417 if (inbytes)
418 str = sysfs_strdup(sysfs, "disksize");
419 else if (sysfs_read_u64(sysfs, "disksize", &num) == 0)
420 str = size_to_human_string(SIZE_SUFFIX_1LETTER, num);
421 break;
0624d840
KZ
422 case COL_ALGORITHM:
423 {
424 char *alg = sysfs_strdup(sysfs, "comp_algorithm");
425 if (!alg)
426 break;
427 if (strstr(alg, "[lzo]") == NULL) {
428 if (strstr(alg, "[lz4]") == NULL)
429 ;
430 else
431 str = xstrdup("lz4");
432 } else
433 str = xstrdup("lzo");
434 free(alg);
435 break;
436 }
437 case COL_MOUNTPOINT:
438 {
439 char path[PATH_MAX] = { '\0' };
440 int fl;
441
442 check_mount_point(z->devname, &fl, path, sizeof(path));
443 if (*path)
444 str = xstrdup(path);
445 break;
446 }
447 case COL_STREAMS:
448 str = sysfs_strdup(sysfs, "max_comp_streams");
449 break;
450 case COL_ZEROPAGES:
5388c862 451 str = get_mm_stat(z, MM_ZERO_PAGES, 1);
0624d840 452 break;
bffc9174
KZ
453 case COL_ORIG_SIZE:
454 str = get_mm_stat(z, MM_ORIG_DATA_SIZE, inbytes);
455 break;
456 case COL_COMP_SIZE:
457 str = get_mm_stat(z, MM_COMPR_DATA_SIZE, inbytes);
458 break;
0624d840 459 case COL_MEMTOTAL:
5388c862 460 str = get_mm_stat(z, MM_MEM_USED_TOTAL, inbytes);
0624d840 461 break;
bffc9174
KZ
462 case COL_MEMLIMIT:
463 str = get_mm_stat(z, MM_MEM_LIMIT, inbytes);
464 break;
465 case COL_MEMUSED:
466 str = get_mm_stat(z, MM_MEM_USED_MAX, inbytes);
467 break;
468 case COL_MIGRATED:
469 str = get_mm_stat(z, MM_NUM_MIGRATED, inbytes);
470 break;
0624d840 471 }
780ce22c 472 if (str && scols_line_refer_data(ln, i, str))
699ad3a1 473 err(EXIT_FAILURE, _("failed to add output data"));
0624d840
KZ
474 }
475}
476
477static void status(struct zram *z)
478{
479 struct libscols_table *tb;
480 size_t i;
e1b1c7b0
JS
481 DIR *dir;
482 struct dirent *d;
0624d840
KZ
483
484 scols_init_debug(0);
485
486 tb = scols_new_table();
487 if (!tb)
780ce22c 488 err(EXIT_FAILURE, _("failed to allocate output table"));
0624d840
KZ
489
490 scols_table_enable_raw(tb, raw);
491 scols_table_enable_noheadings(tb, no_headings);
492
493 for (i = 0; i < (size_t) ncolumns; i++) {
494 const struct colinfo *col = get_column_info(i);
495
496 if (!scols_table_new_column(tb, col->name, col->whint, col->flags))
497 err(EXIT_FAILURE, _("failed to initialize output column"));
498 }
499
e1b1c7b0
JS
500 if (z) {
501 /* just one device specified */
502 fill_table_row(tb, z);
503 goto print_table;
504 }
0624d840 505
e1b1c7b0
JS
506 /* list all used devices */
507 z = new_zram(NULL);
508 if (!(dir = opendir(_PATH_DEV)))
509 err(EXIT_FAILURE, _("cannot open %s"), _PATH_DEV);
510
511 while ((d = readdir(dir))) {
512 int n;
513 if (sscanf(d->d_name, "zram%d", &n) != 1)
514 continue;
515 zram_set_devname(z, NULL, n);
516 if (zram_exist(z) && zram_used(z))
517 fill_table_row(tb, z);
0624d840 518 }
e1b1c7b0
JS
519 closedir(dir);
520 free_zram(z);
0624d840 521
e1b1c7b0 522print_table:
0624d840
KZ
523 scols_print_table(tb);
524 scols_unref_table(tb);
525}
526
86be6a32 527static void __attribute__((__noreturn__)) usage(void)
0624d840 528{
86be6a32 529 FILE *out = stdout;
0624d840
KZ
530 size_t i;
531
532 fputs(USAGE_HEADER, out);
533 fprintf(out, _( " %1$s [options] <device>\n"
1c35e625 534 " %1$s -r <device> [...]\n"
0624d840
KZ
535 " %1$s [options] -f | <device> -s <size>\n"),
536 program_invocation_short_name);
537
451dbcfa
BS
538 fputs(USAGE_SEPARATOR, out);
539 fputs(_("Set up and control zram devices.\n"), out);
540
0624d840 541 fputs(USAGE_OPTIONS, out);
1c35e625 542 fputs(_(" -a, --algorithm lzo|lz4 compression algorithm to use\n"), out);
0624d840 543 fputs(_(" -b, --bytes print sizes in bytes rather than in human readable format\n"), out);
1c35e625 544 fputs(_(" -f, --find find a free device\n"), out);
0624d840
KZ
545 fputs(_(" -n, --noheadings don't print headings\n"), out);
546 fputs(_(" -o, --output <list> columns to use for status output\n"), out);
1c35e625 547 fputs(_(" --raw use raw status output format\n"), out);
0624d840
KZ
548 fputs(_(" -r, --reset reset all specified devices\n"), out);
549 fputs(_(" -s, --size <size> device size\n"), out);
423c0d75 550 fputs(_(" -t, --streams <number> number of compression streams\n"), out);
0624d840
KZ
551
552 fputs(USAGE_SEPARATOR, out);
f45f3ec3 553 printf(USAGE_HELP_OPTIONS(27));
0624d840 554
c3a4cfc5 555 fputs(USAGE_COLUMNS, out);
0624d840
KZ
556 for (i = 0; i < ARRAY_SIZE(infos); i++)
557 fprintf(out, " %11s %s\n", infos[i].name, _(infos[i].help));
558
f45f3ec3 559 printf(USAGE_MAN_TAIL("zramctl(8)"));
86be6a32 560 exit(EXIT_SUCCESS);
0624d840
KZ
561}
562
563/* actions */
564enum {
565 A_NONE = 0,
566 A_STATUS,
567 A_CREATE,
568 A_FINDONLY,
569 A_RESET
570};
571
572int main(int argc, char **argv)
573{
574 uintmax_t size = 0, nstreams = 0;
575 char *algorithm = NULL;
576 int rc = 0, c, find = 0, act = A_NONE;
577 struct zram *zram = NULL;
578
579 enum { OPT_RAW = CHAR_MAX + 1 };
580
581 static const struct option longopts[] = {
582 { "algorithm", required_argument, NULL, 'a' },
1c35e625 583 { "bytes", no_argument, NULL, 'b' },
0624d840
KZ
584 { "find", no_argument, NULL, 'f' },
585 { "help", no_argument, NULL, 'h' },
0624d840
KZ
586 { "output", required_argument, NULL, 'o' },
587 { "noheadings",no_argument, NULL, 'n' },
588 { "reset", no_argument, NULL, 'r' },
589 { "raw", no_argument, NULL, OPT_RAW },
590 { "size", required_argument, NULL, 's' },
591 { "streams", required_argument, NULL, 't' },
592 { "version", no_argument, NULL, 'V' },
593 { NULL, 0, NULL, 0 }
594 };
595
596 static const ul_excl_t excl[] = {
597 { 'f', 'o', 'r' },
598 { 'o', 'r', 's' },
599 { 0 }
600 };
601 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
602
603 setlocale(LC_ALL, "");
604 bindtextdomain(PACKAGE, LOCALEDIR);
605 textdomain(PACKAGE);
606 atexit(close_stdout);
607
608 while ((c = getopt_long(argc, argv, "a:bfho:nrs:t:V", longopts, NULL)) != -1) {
609
610 err_exclusive_options(c, longopts, excl, excl_st);
611
612 switch (c) {
613 case 'a':
614 if (strcmp(optarg,"lzo") && strcmp(optarg,"lz4"))
615 errx(EXIT_FAILURE, _("unsupported algorithm: %s"),
616 optarg);
617 algorithm = optarg;
618 break;
619 case 'b':
620 inbytes = 1;
621 break;
622 case 'f':
623 find = 1;
624 break;
625 case 'o':
626 ncolumns = string_to_idarray(optarg,
627 columns, ARRAY_SIZE(columns),
628 column_name_to_id);
629 if (ncolumns < 0)
630 return EXIT_FAILURE;
631 break;
632 case 's':
633 size = strtosize_or_err(optarg, _("failed to parse size"));
634 act = A_CREATE;
635 break;
636 case 't':
637 nstreams = strtou64_or_err(optarg, _("failed to parse streams"));
638 break;
639 case 'r':
640 act = A_RESET;
641 break;
642 case OPT_RAW:
643 raw = 1;
644 break;
645 case 'n':
646 no_headings = 1;
647 break;
648 case 'V':
649 printf(UTIL_LINUX_VERSION);
650 return EXIT_SUCCESS;
651 case 'h':
86be6a32 652 usage();
0624d840 653 default:
677ec86c 654 errtryhelp(EXIT_FAILURE);
0624d840
KZ
655 }
656 }
657
658 if (find && optind < argc)
659 errx(EXIT_FAILURE, _("option --find is mutually exclusive "
1c35e625 660 "with <device>"));
0624d840
KZ
661 if (act == A_NONE)
662 act = find ? A_FINDONLY : A_STATUS;
663
664 if (act != A_RESET && optind + 1 < argc)
929c7b28 665 errx(EXIT_FAILURE, _("only one <device> at a time is allowed"));
0624d840 666
1fa6c3e0
SK
667 if ((act == A_STATUS || act == A_FINDONLY) && (algorithm || nstreams))
668 errx(EXIT_FAILURE, _("options --algorithm and --streams "
669 "must be combined with --size"));
670
0624d840
KZ
671 switch (act) {
672 case A_STATUS:
0624d840
KZ
673 if (!ncolumns) { /* default columns */
674 columns[ncolumns++] = COL_NAME;
675 columns[ncolumns++] = COL_ALGORITHM;
676 columns[ncolumns++] = COL_DISKSIZE;
677 columns[ncolumns++] = COL_ORIG_SIZE;
678 columns[ncolumns++] = COL_COMP_SIZE;
679 columns[ncolumns++] = COL_MEMTOTAL;
680 columns[ncolumns++] = COL_STREAMS;
681 columns[ncolumns++] = COL_MOUNTPOINT;
682 }
116c9ce2 683 if (optind < argc) {
0624d840 684 zram = new_zram(argv[optind++]);
116c9ce2 685 if (!zram_exist(zram))
0a55b319 686 err(EXIT_FAILURE, "%s", zram->devname);
116c9ce2 687 }
0624d840
KZ
688 status(zram);
689 free_zram(zram);
690 break;
691 case A_RESET:
692 if (optind == argc)
693 errx(EXIT_FAILURE, _("no device specified"));
694 while (optind < argc) {
695 zram = new_zram(argv[optind]);
116c9ce2
KZ
696 if (!zram_exist(zram)
697 || zram_set_u64parm(zram, "reset", 1)) {
0624d840
KZ
698 warn(_("%s: failed to reset"), zram->devname);
699 rc = 1;
700 }
62725810 701 zram_control_remove(zram);
0624d840
KZ
702 free_zram(zram);
703 optind++;
704 }
705 break;
706 case A_FINDONLY:
707 zram = find_free_zram();
708 if (!zram)
1c35e625 709 errx(EXIT_FAILURE, _("no free zram device found"));
0624d840
KZ
710 printf("%s\n", zram->devname);
711 free_zram(zram);
712 break;
713 case A_CREATE:
714 if (find) {
715 zram = find_free_zram();
716 if (!zram)
1c35e625 717 errx(EXIT_FAILURE, _("no free zram device found"));
0624d840
KZ
718 } else if (optind == argc)
719 errx(EXIT_FAILURE, _("no device specified"));
116c9ce2 720 else {
0624d840 721 zram = new_zram(argv[optind]);
116c9ce2 722 if (!zram_exist(zram))
0a55b319 723 err(EXIT_FAILURE, "%s", zram->devname);
116c9ce2 724 }
0624d840
KZ
725
726 if (zram_set_u64parm(zram, "reset", 1))
727 err(EXIT_FAILURE, _("%s: failed to reset"), zram->devname);
728
729 if (nstreams &&
730 zram_set_u64parm(zram, "max_comp_streams", nstreams))
731 err(EXIT_FAILURE, _("%s: failed to set number of streams"), zram->devname);
732
733 if (algorithm &&
734 zram_set_strparm(zram, "comp_algorithm", algorithm))
735 err(EXIT_FAILURE, _("%s: failed to set algorithm"), zram->devname);
736
737 if (zram_set_u64parm(zram, "disksize", size))
738 err(EXIT_FAILURE, _("%s: failed to set disksize (%ju bytes)"),
739 zram->devname, size);
740 if (find)
741 printf("%s\n", zram->devname);
742 free_zram(zram);
743 break;
744 }
745
746 return rc ? EXIT_FAILURE : EXIT_SUCCESS;
747}