LCOV - code coverage report
Current view: top level - mkfs - main_mkfs.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 588 900 65.3 %
Date: 2023-09-27 13:48:55 Functions: 27 31 87.1 %

          Line data    Source code
       1             : #include "clusterautoconfig.h"
       2             : 
       3             : #include <stdio.h>
       4             : #include <stdlib.h>
       5             : #include <string.h>
       6             : #include <stdint.h>
       7             : #include <inttypes.h>
       8             : #include <sys/types.h>
       9             : #include <sys/stat.h>
      10             : #include <fcntl.h>
      11             : #include <unistd.h>
      12             : #include <time.h>
      13             : #include <errno.h>
      14             : #include <stdarg.h>
      15             : #include <mntent.h>
      16             : #include <ctype.h>
      17             : #include <poll.h>
      18             : #include <signal.h>
      19             : #include <sys/time.h>
      20             : #include <libintl.h>
      21             : #include <sys/ioctl.h>
      22             : #include <limits.h>
      23             : #include <blkid.h>
      24             : #include <locale.h>
      25             : #include <uuid.h>
      26             : 
      27             : #define _(String) gettext(String)
      28             : 
      29             : #include "libgfs2.h"
      30             : #include "gfs2_mkfs.h"
      31             : #include "progress.h"
      32             : #include "struct_print.h"
      33             : 
      34           0 : static void print_usage(const char *prog_name)
      35             : {
      36             :         int i;
      37             :         const char *option, *param, *desc;
      38           0 :         const char *options[] = {
      39             :             /* Translators: This is a usage string printed with --help.
      40             :                <size> and <number> here are the commandline parameters,
      41             :                e.g. mkfs.gfs2 -b <size> -j <number> /dev/sda */
      42           0 :             "-b", _("<size>"),   _("File system block size, in bytes"),
      43           0 :             "-c", _("<size>"),   _("Size of quota change file, in megabytes"),
      44           0 :             "-D", NULL,          _("Enable debugging code"),
      45           0 :             "-h", NULL,          _("Display this help, then exit"),
      46           0 :             "-J", _("<size>"),   _("Size of journals, in megabytes"),
      47           0 :             "-j", _("<number>"), _("Number of journals"),
      48           0 :             "-K", NULL,          _("Don't try to discard unused blocks"),
      49           0 :             "-O", NULL,          _("Don't ask for confirmation"),
      50           0 :             "-o", _("<key>[=<value>][,...]"), _("Specify extended options. See '-o help'."),
      51           0 :             "-p", _("<name>"),   _("Name of the locking protocol"),
      52           0 :             "-q", NULL,          _("Don't print anything"),
      53           0 :             "-r", _("<size>"),   _("Size of resource groups, in megabytes"),
      54           0 :             "-t", _("<name>"),   _("Name of the lock table"),
      55           0 :             "-U", _("<UUID>"),   _("The UUID of the file system"),
      56           0 :             "-V", NULL,          _("Display program version information, then exit"),
      57             :             NULL, NULL, NULL /* Must be kept at the end */
      58             :         };
      59             : 
      60           0 :         printf("%s\n", _("Usage:"));
      61           0 :         printf("%s [%s] <%s> [%s]\n\n", prog_name, _("options"), _("device"), _("size"));
      62           0 :         printf(_("Create a gfs2 file system on a device. If a size, in blocks, is not "
      63             :                  "specified, the whole device will be used."));
      64           0 :         printf("\n\n%s\n", _("Options:"));
      65             : 
      66           0 :         for (i = 0; options[i] != NULL; i += 3) {
      67           0 :                 option = options[i];
      68           0 :                 param = options[i + 1];
      69           0 :                 desc = options[i + 2];
      70           0 :                 printf("%3s %-22s %s\n", option, param ? param : "", desc);
      71             :         }
      72           0 : }
      73             : 
      74           0 : static void print_ext_opts(void)
      75             : {
      76             :         int i;
      77           0 :         const char *options[] = {
      78           0 :                 "help", _("Display this help, then exit"),
      79           0 :                 "swidth=N",  _("Specify the stripe width of the device, overriding probed values"),
      80           0 :                 "sunit=N", _("Specify the stripe unit of the device, overriding probed values"),
      81           0 :                 "align=[0|1]", _("Disable or enable alignment of resource groups"),
      82           0 :                 "format=N", _("Specify the format version number"),
      83             :                 NULL, NULL
      84             :         };
      85           0 :         printf(_("Extended options:\n"));
      86           0 :         for (i = 0; options[i] != NULL; i += 2) {
      87           0 :                 printf("%15s  %-22s\n", options[i], options[i + 1]);
      88             :         }
      89           0 : }
      90             : 
      91             : /**
      92             :  * Values probed by libblkid:
      93             :  *  alignment_offset: offset, in bytes, of the start of the dev from its natural alignment
      94             :  *  logical_sector_size: smallest addressable unit
      95             :  *  minimum_io_size: device's preferred unit of I/O. RAID stripe unit.
      96             :  *  optimal_io_size: biggest I/O we can submit without incurring a penalty. RAID stripe width.
      97             :  *  physical_sector_size: the smallest unit we can write atomically
      98             :  */
      99             : struct mkfs_dev {
     100             :         int fd;
     101             :         const char *path;
     102             :         struct stat stat;
     103             :         uint64_t size;
     104             :         unsigned long alignment_offset;
     105             :         unsigned long logical_sector_size;
     106             :         unsigned long minimum_io_size;
     107             :         unsigned long optimal_io_size;
     108             :         unsigned long physical_sector_size;
     109             : 
     110             :         unsigned int got_topol:1;
     111             : };
     112             : 
     113             : /* Number of resource groups */
     114             : static uint64_t nrgrp = 0;
     115             : 
     116             : struct mkfs_opts {
     117             :         unsigned bsize;
     118             :         unsigned qcsize;
     119             :         unsigned jsize;
     120             :         unsigned rgsize;
     121             :         unsigned long sunit;
     122             :         unsigned long swidth;
     123             :         unsigned format;
     124             :         uint64_t fssize;
     125             :         int journals;
     126             :         const char *lockproto;
     127             :         const char *locktable;
     128             :         const char *uuid;
     129             :         struct mkfs_dev dev;
     130             :         unsigned discard:1;
     131             :         unsigned root_inherit_jd:1;
     132             : 
     133             :         unsigned got_bsize:1;
     134             :         unsigned got_qcsize:1;
     135             :         unsigned got_jsize:1;
     136             :         unsigned got_rgsize:1;
     137             :         unsigned got_sunit:1;
     138             :         unsigned got_swidth:1;
     139             :         unsigned got_fssize:1;
     140             :         unsigned got_journals:1;
     141             :         unsigned got_lockproto:1;
     142             :         unsigned got_locktable:1;
     143             :         unsigned got_device:1;
     144             :         unsigned got_topol:1;
     145             :         unsigned got_format:1;
     146             :         unsigned got_uuid:1;
     147             : 
     148             :         unsigned override:1;
     149             :         unsigned quiet:1;
     150             :         unsigned debug:1;
     151             :         unsigned confirm:1;
     152             :         unsigned align;
     153             : };
     154             : 
     155          97 : static void opts_init(struct mkfs_opts *opts)
     156             : {
     157          97 :         memset(opts, 0, sizeof(*opts));
     158          97 :         opts->discard = 1;
     159          97 :         opts->journals = 1;
     160          97 :         opts->bsize = LGFS2_DEFAULT_BSIZE;
     161          97 :         opts->jsize = LGFS2_DEFAULT_JSIZE;
     162          97 :         opts->qcsize = LGFS2_DEFAULT_QCSIZE;
     163          97 :         opts->rgsize = LGFS2_DEFAULT_RGSIZE;
     164          97 :         opts->lockproto = "lock_dlm";
     165          97 :         opts->locktable = "";
     166          97 :         opts->confirm = 1;
     167          97 :         opts->align = 1;
     168          97 :         opts->format = GFS2_FORMAT_FS;
     169          97 : }
     170             : 
     171             : static struct lgfs2_inum *mkfs_journals = NULL;
     172             : 
     173             : #ifndef BLKDISCARD
     174             : #define BLKDISCARD      _IO(0x12,119)
     175             : #endif
     176             : 
     177           0 : static int discard_blocks(int fd, uint64_t len, int debug)
     178             : {
     179             :         uint64_t range[2];
     180             : 
     181           0 :         range[0] = 0;
     182           0 :         range[1] = len;
     183           0 :         if (debug)
     184             :                 /* Translators: "discard" is a request sent to a storage device to
     185             :                  * discard a range of blocks. */
     186           0 :                 printf(_("Issuing discard request: range: %"PRIu64" - %"PRIu64"..."),
     187             :                        range[0], range[1]);
     188           0 :         if (ioctl(fd, BLKDISCARD, &range) < 0) {
     189           0 :                 if (debug)
     190           0 :                         printf("%s = %d\n", _("error"), errno);
     191           0 :                 return errno;
     192             :         }
     193           0 :         if (debug)
     194           0 :                 printf(_("Successful.\n"));
     195           0 :         return 0;
     196             : }
     197             : 
     198             : /**
     199             :  * Convert a human-readable size string to a long long.
     200             :  * Copied and adapted from xfs_mkfs.c.
     201             :  */
     202          58 : static long long cvtnum(unsigned int blocksize, unsigned int sectorsize, const char *s)
     203             : {
     204             :         long long i;
     205             :         char *sp;
     206             : 
     207          58 :         i = strtoll(s, &sp, 0);
     208          58 :         if (i == 0 && sp == s)
     209           1 :                 return -1LL;
     210          57 :         if (*sp == '\0')
     211          57 :                 return i;
     212             : 
     213           0 :         *sp = tolower(*sp);
     214           0 :         if (*sp == 'b' && sp[1] == '\0') {
     215           0 :                 if (blocksize)
     216           0 :                         return i * blocksize;
     217           0 :                 fprintf(stderr, _("Block size not available yet.\n"));
     218           0 :                 return -1LL;
     219             :         }
     220           0 :         if (*sp == 's' && sp[1] == '\0') {
     221           0 :                 if (sectorsize)
     222           0 :                         return i * sectorsize;
     223           0 :                 return i * GFS2_BASIC_BLOCK;
     224             :         }
     225           0 :         if (*sp == 'k' && sp[1] == '\0')
     226           0 :                 return 1024LL * i;
     227           0 :         if (*sp == 'm' && sp[1] == '\0')
     228           0 :                 return 1024LL * 1024LL * i;
     229           0 :         if (*sp == 'g' && sp[1] == '\0')
     230           0 :                 return 1024LL * 1024LL * 1024LL * i;
     231           0 :         if (*sp == 't' && sp[1] == '\0')
     232           0 :                 return 1024LL * 1024LL * 1024LL * 1024LL * i;
     233           0 :         if (*sp == 'p' && sp[1] == '\0')
     234           0 :                 return 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * i;
     235           0 :         if (*sp == 'e' && sp[1] == '\0')
     236           0 :                 return 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * i;
     237           0 :         return -1LL;
     238             : }
     239             : 
     240          59 : static int parse_ulong(struct mkfs_opts *opts, const char *key, const char *val, unsigned long *pn,
     241             :                        unsigned long max)
     242             : {
     243             :         long long l;
     244          59 :         if (val == NULL || *val == '\0') {
     245           1 :                 fprintf(stderr, _("Missing argument to '%s'\n"), key);
     246           1 :                 return -1;
     247             :         }
     248          58 :         l = cvtnum(opts->bsize, 0, val);
     249          58 :         if ((max > 0 && l > max) || l < 0) {
     250           4 :                 fprintf(stderr, _("Value of '%s' is invalid\n"), key);
     251           4 :                 return -1;
     252             :         }
     253          54 :         *pn = (unsigned long)l;
     254          54 :         return 0;
     255             : }
     256             : 
     257           1 : static int parse_bool(struct mkfs_opts *opts, const char *key, const char *val, unsigned *pbool)
     258             : {
     259           1 :         if (strnlen(val, 2) == 1) {
     260           1 :                 if (*val == '0') {
     261           1 :                         *pbool = 0;
     262           1 :                         return 0;
     263             :                 }
     264           0 :                 if (*val == '1') {
     265           0 :                         *pbool = 1;
     266           0 :                         return 0;
     267             :                 }
     268             :         }
     269           0 :         fprintf(stderr, _("Option '%s' must be either 1 or 0\n"), key);
     270           0 :         return -1;
     271             : }
     272             : 
     273           9 : static int parse_topology(struct mkfs_opts *opts, char *str)
     274             : {
     275             :         char *opt;
     276           9 :         unsigned i = 0;
     277           9 :         unsigned long *topol[5] = {
     278           9 :                 &opts->dev.alignment_offset,
     279           9 :                 &opts->dev.logical_sector_size,
     280           9 :                 &opts->dev.minimum_io_size,
     281           9 :                 &opts->dev.optimal_io_size,
     282           9 :                 &opts->dev.physical_sector_size
     283             :         };
     284             : 
     285          54 :         while ((opt = strsep(&str, ":")) != NULL) {
     286          45 :                 if (i > 4) {
     287           0 :                         fprintf(stderr, "Too many topology values.\n");
     288           0 :                         return 1;
     289             :                 }
     290          45 :                 if (parse_ulong(opts, "test_topology", opt, topol[i], 0))
     291           0 :                         return 1;
     292          45 :                 i++;
     293             :         }
     294           9 :         if (i < 5) {
     295           0 :                 fprintf(stderr, "Too few topology values.\n");
     296           0 :                 return 1;
     297             :         }
     298           9 :         return 0;
     299             : }
     300             : 
     301           9 : static int parse_format(struct mkfs_opts *opts, char *str)
     302             : {
     303             :         unsigned long ln;
     304             : 
     305           9 :         if (parse_ulong(opts, "format", str, &ln, LGFS2_FS_FORMAT_MAX) != 0)
     306           2 :                 return -1;
     307             : 
     308           7 :         if (ln < LGFS2_FS_FORMAT_MIN) {
     309           2 :                 fprintf(stderr, _("Invalid filesystem format: %s\n"), str);
     310           2 :                 return -1;
     311             :         }
     312           5 :         opts->format = ln;
     313           5 :         opts->got_format = 1;
     314           5 :         return 0;
     315             : }
     316             : 
     317           6 : static int parse_root_inherit_jd(struct mkfs_opts *opts, const char *str)
     318             : {
     319           6 :         unsigned long n = 0;
     320             : 
     321           6 :         if (str == NULL) { /* -o root_inherit_jdata */
     322           1 :                 opts->root_inherit_jd = 1;
     323           1 :                 return 0;
     324             :         }
     325             :         /* -o root_inherit_jdata=N */
     326           5 :         if (parse_ulong(opts, "root_inherit_jdata", str, &n, 1) != 0)
     327           3 :                 return -1;
     328           2 :         opts->root_inherit_jd = (unsigned)n;
     329           2 :         return 0;
     330             : }
     331             : 
     332          25 : static int opt_parse_extended(char *str, struct mkfs_opts *opts)
     333             : {
     334             :         char *opt;
     335          43 :         while ((opt = strsep(&str, ",")) != NULL) {
     336          25 :                 char *key = strsep(&opt, "=");
     337          25 :                 char *val = strsep(&opt, "=");
     338          25 :                 if (key == NULL || *key == '\0') {
     339           0 :                         fprintf(stderr, _("Missing argument to '-o' option\n"));
     340           0 :                         return -1;
     341             :                 }
     342          25 :                 if (strcmp("sunit", key) == 0) {
     343           0 :                         if (parse_ulong(opts, "sunit", val, &opts->sunit, 0) != 0)
     344           0 :                                 return -1;
     345           0 :                         opts->got_sunit = 1;
     346          25 :                 } else if (strcmp("swidth", key) == 0) {
     347           0 :                         if (parse_ulong(opts, "swidth", val, &opts->swidth, 0) != 0)
     348           0 :                                 return -1;
     349           0 :                         opts->got_swidth = 1;
     350          25 :                 } else if (strcmp("align", key) == 0) {
     351           1 :                         if (parse_bool(opts, "align", val, &opts->align) != 0)
     352           0 :                                 return -1;
     353          24 :                 } else if (strcmp("test_topology", key) == 0) {
     354           9 :                         if (parse_topology(opts, val) != 0)
     355           0 :                                 return -1;
     356          17 :                         opts->got_topol = (opts->dev.logical_sector_size != 0 &&
     357           8 :                                            opts->dev.physical_sector_size != 0);
     358          15 :                 } else if (strcmp("format", key) == 0) {
     359           9 :                         if (parse_format(opts, val) != 0)
     360           4 :                                 return -1;
     361           6 :                 } else if (strcmp("root_inherit_jdata", key) == 0) {
     362           6 :                         if (parse_root_inherit_jd(opts, val) != 0)
     363           3 :                                 return -1;
     364           0 :                 } else if (strcmp("help", key) == 0) {
     365           0 :                         print_ext_opts();
     366           0 :                         return 1;
     367             :                 } else {
     368           0 :                         fprintf(stderr, _("Invalid extended option (specified with -o): '%s'\n"), key);
     369           0 :                         print_ext_opts();
     370           0 :                         return -1;
     371             :                 }
     372             :         }
     373          18 :         return 0;
     374             : }
     375             : 
     376          97 : static int opts_get(int argc, char *argv[], struct mkfs_opts *opts)
     377             : {
     378             :         int ret;
     379             :         int c;
     380             :         while (1) {
     381         541 :                 c = getopt(argc, argv, "-b:c:DhJ:j:KOo:p:qr:t:U:V");
     382         541 :                 if (c == -1)
     383          88 :                         break;
     384             : 
     385         453 :                 switch (c) {
     386          13 :                 case 'b':
     387          13 :                         opts->bsize = atoi(optarg);
     388          13 :                         opts->got_bsize = 1;
     389          13 :                         break;
     390           4 :                 case 'c':
     391           4 :                         opts->qcsize = atoi(optarg);
     392           4 :                         opts->got_qcsize = 1;
     393           4 :                         break;
     394          81 :                 case 'D':
     395          81 :                         opts->debug = 1;
     396          81 :                         break;
     397           0 :                 case 'h':
     398           0 :                         print_usage(argv[0]);
     399           0 :                         return 1;
     400           6 :                 case 'J':
     401           6 :                         opts->jsize = atoi(optarg);
     402           6 :                         opts->got_jsize = 1;
     403           6 :                         break;
     404           3 :                 case 'j':
     405           3 :                         opts->journals = atoi(optarg);
     406           3 :                         opts->got_journals = 1;
     407           3 :                         break;
     408           0 :                 case 'K':
     409           0 :                         opts->discard = 0;
     410           0 :                         break;
     411          96 :                 case 'O':
     412          96 :                         opts->override = 1;
     413          96 :                         break;
     414          96 :                 case 'p':
     415          96 :                         opts->lockproto = optarg;
     416          96 :                         opts->got_lockproto = 1;
     417          96 :                         break;
     418          10 :                 case 't':
     419          10 :                         opts->locktable = optarg;
     420          10 :                         opts->got_locktable = 1;
     421          10 :                         break;
     422           0 :                 case 'q':
     423           0 :                         opts->quiet = 1;
     424           0 :                         break;
     425          17 :                 case 'r':
     426          17 :                         opts->rgsize = atoi(optarg);
     427          17 :                         opts->got_rgsize = 1;
     428          17 :                         break;
     429          25 :                 case 'o':
     430          25 :                         ret = opt_parse_extended(optarg, opts);
     431          25 :                         if (ret != 0)
     432           7 :                                 return ret;
     433          18 :                         break;
     434           4 :                 case 'U':
     435           4 :                         opts->uuid = optarg;
     436           4 :                         opts->got_uuid = 1;
     437           4 :                         break;
     438           0 :                 case 'V':
     439           0 :                         printf("mkfs.gfs2 %s (built %s %s)\n", VERSION,
     440             :                                __DATE__, __TIME__);
     441           0 :                         printf(REDHAT_COPYRIGHT "\n");
     442           0 :                         return 1;
     443             :                         break;
     444           2 :                 case ':':
     445             :                 case '?':
     446           2 :                         fprintf(stderr, _("Please use '-h' for help.\n"));
     447           2 :                         return -1;
     448             :                         break;
     449          96 :                 case 1:
     450          96 :                         if (strcmp(optarg, "gfs2") == 0)
     451           0 :                                 continue;
     452          96 :                         if (!opts->got_device) {
     453          89 :                                 opts->dev.path = optarg;
     454          89 :                                 opts->got_device = 1;
     455           7 :                         } else if (!opts->got_fssize && isdigit(optarg[0])) {
     456           7 :                                 opts->fssize = atol(optarg);
     457           7 :                                 opts->got_fssize = 1;
     458             :                         } else {
     459           0 :                                 fprintf(stderr, _("More than one device specified (try -h for help)\n"));
     460           0 :                                 return -1;
     461             :                         }
     462          96 :                         break;
     463           0 :                 default:
     464           0 :                         fprintf(stderr, _("Invalid option: %c\n"), c);
     465           0 :                         return -1;
     466             :                 };
     467             :         }
     468          88 :         return 0;
     469             : }
     470             : 
     471             : /**
     472             :  * Make sure the GFS2 is set up to use the right lock protocol
     473             :  * @lockproto: the lock protocol to mount
     474             :  * @locktable: the locktable name
     475             :  *
     476             :  */
     477             : 
     478          88 : static int test_locking(struct mkfs_opts *opts)
     479             : {
     480             :         const char *c;
     481             :         /* Translators: A lock table is a string identifying a gfs2 file system
     482             :          * in a cluster, e.g. cluster_name:fs_name */
     483          88 :         const char *errprefix = _("Invalid lock table:");
     484         176 :         int table_required = (strcmp(opts->lockproto, "lock_gulm") == 0)
     485          88 :                           || (strcmp(opts->lockproto, "lock_dlm") == 0);
     486             : 
     487          88 :         if ((strcmp(opts->lockproto, "lock_nolock") != 0) && !table_required) {
     488           1 :                 fprintf(stderr, _("Invalid lock protocol: %s\n"), opts->lockproto);
     489           1 :                 return -1;
     490             :         }
     491             :         /* When lock_*lm is given as the lock protocol, require a lock table too */
     492          87 :         if (!opts->got_locktable) {
     493          77 :                 if (table_required) {
     494           0 :                         fprintf(stderr, _("No lock table specified.\n"));
     495           0 :                         return -1;
     496             :                 }
     497          77 :                 return 0;
     498             :         }
     499             :         /* User gave a lock table option, validate it */
     500          10 :         if (*opts->locktable == '\0') {
     501           2 :                 fprintf(stderr, _("Lock table is empty.\n"));
     502           2 :                 return -1;
     503             :         }
     504         337 :         for (c = opts->locktable; *c; c++) {
     505         329 :                 if (!isalnum(*c) && (*c != '-') && (*c != '_') && (*c != ':')) {
     506           0 :                         fprintf(stderr, "%s %s '%c'\n", errprefix, _("invalid character"), *c);
     507           0 :                         return -1;
     508             :                 }
     509             :         }
     510           8 :         c = strstr(opts->locktable, ":");
     511           8 :         if (!c) {
     512           0 :                 fprintf(stderr, "%s %s\n", errprefix, _("missing colon"));
     513           0 :                 return -1;
     514             :         }
     515             : 
     516           8 :         if (c == opts->locktable) {
     517           0 :                 fprintf(stderr, "%s %s\n", errprefix, _("cluster name is missing"));
     518           0 :                 return -1;
     519             :         }
     520           8 :         if (c - opts->locktable > 32) {
     521           2 :                 fprintf(stderr, "%s %s\n", errprefix, _("cluster name is too long"));
     522           2 :                 return -1;
     523             :         }
     524             : 
     525           6 :         c++;
     526           6 :         if (strstr(c, ":")) {
     527           0 :                 fprintf(stderr, "%s %s\n", errprefix, _("contains more than one colon"));
     528           0 :                 return -1;
     529             :         }
     530           6 :         if (!strlen(c)) {
     531           0 :                 fprintf(stderr, "%s %s\n", errprefix, _("file system name is missing"));
     532           0 :                 return -1;
     533             :         }
     534           6 :         if (strlen(c) > 30) {
     535           2 :                 fprintf(stderr, "%s %s\n", errprefix, _("file system name is too long"));
     536           2 :                 return -1;
     537             :         }
     538           4 :         return 0;
     539             : }
     540             : 
     541           0 : static int are_you_sure(void)
     542             : {
     543           0 :         while (1) {
     544           0 :                 char *line = NULL;
     545           0 :                 size_t len = 0;
     546             :                 int ret;
     547             :                 int res;
     548             : 
     549             :                 /* Translators: We use rpmatch(3) to match the answers to y/n
     550             :                    questions in the user's own language, so the [y/n] here must also be
     551             :                    translated to match one of the letters in the pattern printed by
     552             :                    `locale -k yesexpr` and one of the letters in the pattern printed by
     553             :                    `locale -k noexpr` */
     554           0 :                 printf( _("Are you sure you want to proceed? [y/n] "));
     555           0 :                 ret = getline(&line, &len, stdin);
     556           0 :                 if (ret < 0) {
     557           0 :                         printf("\n");
     558           0 :                         free(line);
     559           0 :                         return 0;
     560             :                 }
     561           0 :                 res = rpmatch(line);
     562           0 :                 free(line);
     563           0 :                 if (ret == 0)
     564           0 :                         continue;
     565           0 :                 if (res == 1) /* Yes */
     566           0 :                         return 1;
     567           0 :                 if (res == 0) /* No */
     568           0 :                         return 0;
     569             :                 /* Unrecognized input; go again. */
     570             :         }
     571             : }
     572             : 
     573          75 : static int choose_blocksize(struct mkfs_opts *opts, unsigned *pbsize)
     574             : {
     575             :         unsigned int x;
     576          75 :         unsigned int bsize = opts->bsize;
     577          75 :         struct mkfs_dev *dev = &opts->dev;
     578          75 :         int got_topol = (dev->got_topol || opts->got_topol);
     579             : 
     580          75 :         if (got_topol && opts->debug) {
     581           8 :                 printf("alignment_offset: %lu\n", dev->alignment_offset);
     582           8 :                 printf("logical_sector_size: %lu\n", dev->logical_sector_size);
     583           8 :                 printf("minimum_io_size: %lu\n", dev->minimum_io_size);
     584           8 :                 printf("optimal_io_size: %lu\n", dev->optimal_io_size);
     585           8 :                 printf("physical_sector_size: %lu\n", dev->physical_sector_size);
     586             :         }
     587          75 :         if (got_topol && dev->alignment_offset != 0) {
     588           2 :                 fprintf(stderr,
     589           2 :                   _("Warning: device is not properly aligned. This may harm performance.\n"));
     590           2 :                 dev->physical_sector_size = dev->logical_sector_size;
     591             :         }
     592          75 :         if (!opts->got_bsize && got_topol) {
     593           7 :                 if (dev->optimal_io_size <= getpagesize() &&
     594           1 :                     dev->optimal_io_size >= LGFS2_DEFAULT_BSIZE)
     595           0 :                         bsize = dev->optimal_io_size;
     596           7 :                 else if (dev->physical_sector_size <= getpagesize() &&
     597           7 :                          dev->physical_sector_size >= LGFS2_DEFAULT_BSIZE)
     598           0 :                         bsize = dev->physical_sector_size;
     599             :         }
     600             :         /* Block sizes must be a power of two from 512 to 65536 */
     601         275 :         for (x = 512; x; x <<= 1)
     602         275 :                 if (x == bsize)
     603          75 :                         break;
     604             : 
     605          75 :         if (!x || bsize > getpagesize()) {
     606           0 :                 fprintf(stderr, _("Block size must be a power of two between 512 and %d\n"),
     607             :                         getpagesize());
     608           0 :                 return -1;
     609             :         }
     610          75 :         if (bsize < dev->logical_sector_size) {
     611           0 :                 fprintf(stderr, _("Error: Block size %d is less than minimum logical "
     612             :                        "block size (%lu).\n"), bsize, dev->logical_sector_size);
     613           0 :                 return -1;
     614             :         }
     615          75 :         if (bsize < dev->physical_sector_size) {
     616           0 :                 printf( _("Warning: Block size %d is inefficient because it "
     617             :                           "is less than the physical block size (%lu).\n"),
     618             :                           bsize, dev->physical_sector_size);
     619           0 :                 opts->confirm = 1;
     620             :         }
     621          75 :         *pbsize = bsize;
     622          75 :         return 0;
     623             : }
     624             : 
     625          88 : static int opts_check(struct mkfs_opts *opts)
     626             : {
     627          88 :         if (!opts->got_device) {
     628           0 :                 fprintf(stderr, _("No device specified. Use -h for help\n"));
     629           0 :                 return -1;
     630             :         }
     631             : 
     632          88 :         if (test_locking(opts) != 0)
     633           7 :                 return -1;
     634             : 
     635          81 :         if (LGFS2_MIN_RGSIZE > opts->rgsize || opts->rgsize > LGFS2_MAX_RGSIZE) {
     636             :                 /* Translators: gfs2 file systems are split into equal sized chunks called
     637             :                    resource groups. We're checking that the user gave a valid size for them. */
     638           2 :                 fprintf(stderr, _("Bad resource group size\n"));
     639           2 :                 return -1;
     640             :         }
     641             : 
     642          79 :         if (!opts->journals) {
     643           0 :                 fprintf(stderr, _("No journals specified\n"));
     644           0 :                 return -1;
     645             :         }
     646          79 :         if (opts->journals < 0) {
     647           0 :                 fprintf(stderr, _("Number of journals cannot be negative: %d\n"), opts->journals);
     648           0 :                 return -1;
     649             :         }
     650          79 :         if (opts->jsize < LGFS2_MIN_JSIZE || opts->jsize > LGFS2_MAX_JSIZE) {
     651           2 :                 fprintf(stderr, _("Bad journal size\n"));
     652           2 :                 return -1;
     653             :         }
     654             : 
     655          77 :         if (!opts->qcsize || opts->qcsize > 64) {
     656           2 :                 fprintf(stderr, _("Bad quota change size\n"));
     657           2 :                 return -1;
     658             :         }
     659             : 
     660          75 :         if ((opts->got_sunit && !opts->got_swidth) || (!opts->got_sunit && opts->got_swidth)) {
     661           0 :                 fprintf(stderr, _("Stripe unit and stripe width must be specified together\n"));
     662           0 :                 return -1;
     663             :         }
     664          75 :         return 0;
     665             : }
     666             : 
     667          70 : static void print_results(struct lgfs2_sbd *sb, struct mkfs_opts *opts)
     668             : {
     669             :         char readable_uuid[36+1];
     670             : 
     671          70 :         uuid_unparse(sb->sd_uuid, readable_uuid);
     672             : 
     673          70 :         printf("%-27s%s\n", _("Device:"), opts->dev.path);
     674          70 :         printf("%-27s%u\n", _("Block size:"), sb->sd_bsize);
     675          70 :         printf("%-27s%.2f %s (%"PRIu64" %s)\n", _("Device size:"),
     676             :                /* Translators: "GB" here means "gigabytes" */
     677          70 :                (opts->dev.size / ((float)(1 << 30))), _("GB"),
     678          70 :                (opts->dev.size / sb->sd_bsize), _("blocks"));
     679          70 :         printf("%-27s%.2f %s (%"PRIu64" %s)\n", _("Filesystem size:"),
     680          70 :                (sb->fssize / ((float)(1 << 30)) * sb->sd_bsize), _("GB"), sb->fssize, _("blocks"));
     681          70 :         printf("%-27s%u\n", _("Journals:"), opts->journals);
     682          70 :         printf("%-27s%uMB\n", _("Journal size:"), opts->jsize);
     683          70 :         printf("%-27s%"PRIu64"\n", _("Resource groups:"), nrgrp);
     684          70 :         printf("%-27s\"%s\"\n", _("Locking protocol:"), opts->lockproto);
     685          70 :         printf("%-27s\"%s\"\n", _("Lock table:"), opts->locktable);
     686             :         /* Translators: "UUID" = universally unique identifier. */
     687          70 :         printf("%-27s%s\n", _("UUID:"), readable_uuid);
     688          70 : }
     689             : 
     690          70 : static int warn_of_destruction(const char *path)
     691             : {
     692             :         struct stat lnkstat;
     693          70 :         char *abspath = NULL;
     694             : 
     695          70 :         if (lstat(path, &lnkstat) == -1) {
     696           0 :                 perror(_("Failed to lstat the device"));
     697           0 :                 return -1;
     698             :         }
     699          70 :         if (S_ISLNK(lnkstat.st_mode)) {
     700             :                 /* coverity[toctou:SUPPRESS] */
     701           0 :                 abspath = realpath(path, NULL);
     702           0 :                 if (abspath == NULL) {
     703           0 :                         perror(_("Could not find the absolute path of the device"));
     704           0 :                         return -1;
     705             :                 }
     706             :                 /* Translators: Example: "/dev/vg/lv is a symbolic link to /dev/dm-2" */
     707           0 :                 printf( _("%s is a symbolic link to %s\n"), path, abspath);
     708           0 :                 path = abspath;
     709             :         }
     710          70 :         printf(_("This will destroy any data on %s\n"), path);
     711          70 :         free(abspath);
     712          70 :         return 0;
     713             : }
     714             : 
     715          70 : static int build_per_node(struct lgfs2_sbd *sdp, struct mkfs_opts *opts)
     716             : {
     717             :         struct lgfs2_inode *per_node;
     718             :         unsigned int j;
     719             : 
     720             :         /* coverity[identity_transfer:SUPPRESS] False positive */
     721          70 :         per_node = lgfs2_createi(sdp->master_dir, "per_node", S_IFDIR | 0700,
     722             :                            GFS2_DIF_SYSTEM);
     723          70 :         if (per_node == NULL) {
     724           0 :                 fprintf(stderr, _("Error building '%s': %s\n"), "per_node", strerror(errno));
     725           0 :                 return -1;
     726             :         }
     727         147 :         for (j = 0; j < sdp->md.journals; j++) {
     728             :                 struct lgfs2_inode *ip;
     729             : 
     730             :                 /* coverity[identity_transfer:SUPPRESS] False positive */
     731          77 :                 ip = lgfs2_build_inum_range(per_node, j);
     732          77 :                 if (ip == NULL) {
     733           0 :                         fprintf(stderr, _("Error building '%s': %s\n"), "inum_range",
     734           0 :                                 strerror(errno));
     735           0 :                         lgfs2_inode_put(&per_node);
     736           0 :                         return 1;
     737             :                 }
     738          77 :                 if (opts->debug) {
     739          62 :                         printf("\nInum Range %u:\n", j);
     740          62 :                         dinode_print(ip->i_bh->b_data);
     741             :                 }
     742          77 :                 lgfs2_inode_put(&ip);
     743             : 
     744             :                 /* coverity[identity_transfer:SUPPRESS] False positive */
     745          77 :                 ip = lgfs2_build_statfs_change(per_node, j);
     746          77 :                 if (ip == NULL) {
     747           0 :                         fprintf(stderr, _("Error building '%s': %s\n"), "statfs_change",
     748           0 :                                 strerror(errno));
     749           0 :                         lgfs2_inode_put(&per_node);
     750           0 :                         return 1;
     751             :                 }
     752          77 :                 if (opts->debug) {
     753          62 :                         printf("\nStatFS Change %u:\n", j);
     754          62 :                         dinode_print(ip->i_bh->b_data);
     755             :                 }
     756          77 :                 lgfs2_inode_put(&ip);
     757             : 
     758             :                 /* coverity[identity_transfer:SUPPRESS] False positive */
     759          77 :                 ip = lgfs2_build_quota_change(per_node, j);
     760          77 :                 if (ip == NULL) {
     761           0 :                         fprintf(stderr, _("Error building '%s': %s\n"), "quota_change",
     762           0 :                                 strerror(errno));
     763             :                         /* coverity[deref_arg:SUPPRESS] */
     764           0 :                         lgfs2_inode_put(&per_node);
     765           0 :                         return 1;
     766             :                 }
     767          77 :                 if (opts->debug) {
     768          62 :                         printf("\nQuota Change %u:\n", j);
     769          62 :                         dinode_print(ip->i_bh->b_data);
     770             :                 }
     771          77 :                 lgfs2_inode_put(&ip);
     772             :         }
     773          70 :         if (opts->debug) {
     774          55 :                 printf("\nper_node:\n");
     775          55 :                 dinode_print(per_node->i_bh->b_data);
     776             :         }
     777          70 :         lgfs2_inode_put(&per_node);
     778          70 :         return 0;
     779             : }
     780             : 
     781        3800 : static int zero_gap(struct lgfs2_sbd *sdp, uint64_t addr, size_t blocks)
     782             : {
     783             :         struct iovec *iov;
     784             :         char *zerobuf;
     785             :         ssize_t wrote;
     786             :         unsigned i;
     787             : 
     788        3800 :         if (blocks == 0)
     789           0 :                 return 0;
     790        3800 :         iov = calloc(blocks, sizeof(*iov));
     791        3800 :         if (iov == NULL) {
     792           0 :                 perror(_("Failed to zero blocks\n"));
     793           0 :                 return 1;
     794             :         }
     795        3800 :         zerobuf = calloc(1, sdp->sd_bsize);
     796        3800 :         if (zerobuf == NULL) {
     797           0 :                 perror(_("Failed to zero blocks\n"));
     798           0 :                 free(iov);
     799           0 :                 return 1;
     800             :         }
     801       16273 :         for (i = 0; i < blocks; i++) {
     802       12473 :                 iov[i].iov_base = zerobuf;
     803       12473 :                 iov[i].iov_len = sdp->sd_bsize;
     804             :         }
     805        3800 :         wrote = pwritev(sdp->device_fd, iov, blocks, addr * sdp->sd_bsize);
     806        3800 :         if (wrote != blocks * sdp->sd_bsize) {
     807           0 :                 fprintf(stderr, _("Zeroing write failed at block %"PRIu64"\n"), addr);
     808           0 :                 free(zerobuf);
     809           0 :                 free(iov);
     810           0 :                 return 1;
     811             :         }
     812        3800 :         free(zerobuf);
     813        3800 :         free(iov);
     814        3800 :         return 0;
     815             : }
     816             : 
     817          70 : static lgfs2_rgrps_t rgs_init(struct mkfs_opts *opts, struct lgfs2_sbd *sdp)
     818             : {
     819             :         lgfs2_rgrps_t rgs;
     820          70 :         uint64_t al_base = 0;
     821          70 :         uint64_t al_off = 0;
     822             : 
     823          70 :         if (opts->align && opts->got_sunit) {
     824           0 :                 if ((opts->sunit % sdp->sd_bsize) != 0) {
     825           0 :                         fprintf(stderr, _("Stripe unit (%lu) must be a multiple of block size (%u)\n"),
     826             :                                 opts->sunit, sdp->sd_bsize);
     827           0 :                         return NULL;
     828           0 :                 } else if ((opts->swidth % opts->sunit) != 0) {
     829           0 :                         fprintf(stderr, _("Stripe width (%lu) must be a multiple of stripe unit (%lu)\n"),
     830             :                                 opts->swidth, opts->sunit);
     831           0 :                         return NULL;
     832             :                 } else {
     833           0 :                         al_base = opts->swidth / sdp->sd_bsize;
     834           0 :                         al_off = opts->sunit / sdp->sd_bsize;
     835             :                 }
     836          70 :         } else if (opts->align) {
     837          69 :                 if (opts->dev.optimal_io_size <= opts->dev.physical_sector_size ||
     838           7 :                     opts->dev.minimum_io_size <= opts->dev.physical_sector_size ||
     839           6 :                     (opts->dev.optimal_io_size % opts->dev.minimum_io_size) != 0) {
     840             :                         /* If optimal_io_size is not a multiple of minimum_io_size then
     841             :                            the values are not reliable swidth and sunit values, so disable
     842             :                            rgrp alignment */
     843          64 :                         opts->align = 0;
     844             :                 } else {
     845           5 :                         al_base = opts->dev.optimal_io_size / sdp->sd_bsize;
     846           5 :                         al_off = opts->dev.minimum_io_size / sdp->sd_bsize;
     847             :                 }
     848             :         }
     849             : 
     850          70 :         rgs = lgfs2_rgrps_init(sdp, al_base, al_off);
     851          70 :         if (rgs == NULL) {
     852           0 :                 perror(_("Could not initialise resource groups"));
     853           0 :                 return NULL;
     854             :         }
     855             : 
     856          70 :         if (opts->debug) {
     857          55 :                 printf("  rgrp align = ");
     858          55 :                 if (opts->align)
     859           5 :                         printf("%"PRIu64"+%"PRIu64" blocks\n", al_base, al_off);
     860             :                 else
     861          50 :                         printf("(disabled)\n");
     862             :         }
     863             : 
     864          70 :         return rgs;
     865             : }
     866             : 
     867        6429 : static int place_rgrp(struct lgfs2_sbd *sdp, lgfs2_rgrp_t rg, int debug)
     868             : {
     869        6429 :         uint64_t prev_end = (GFS2_SB_ADDR * GFS2_BASIC_BLOCK / sdp->sd_bsize) + 1;
     870        6429 :         lgfs2_rgrp_t prev = lgfs2_rgrp_prev(rg);
     871             :         struct gfs2_rindex ri;
     872             :         uint64_t addr;
     873        6429 :         int err = 0;
     874             : 
     875        6429 :         if (prev != NULL) {
     876        6359 :                 lgfs2_rindex_out(prev, &ri);
     877        6359 :                 prev_end = be64_to_cpu(ri.ri_data0) + be32_to_cpu(ri.ri_data);
     878             :         }
     879             : 
     880        6429 :         lgfs2_rindex_out(rg, &ri);
     881        6429 :         addr = be64_to_cpu(ri.ri_addr);
     882             : 
     883       10229 :         while (prev_end < addr) {
     884        3800 :                 size_t gap_len = addr - prev_end;
     885             : 
     886        3800 :                 if (gap_len > IOV_MAX)
     887           3 :                         gap_len = IOV_MAX;
     888        3800 :                 err = zero_gap(sdp, prev_end, gap_len);
     889        3800 :                 if (err != 0)
     890           0 :                         return -1;
     891        3800 :                 prev_end += gap_len;
     892             :         }
     893        6429 :         err = lgfs2_rgrp_write(sdp->device_fd, rg);
     894        6429 :         if (err != 0) {
     895           0 :                 perror(_("Failed to write resource group"));
     896           0 :                 return -1;
     897             :         }
     898        6429 :         if (debug) {
     899        5354 :                 rindex_print(&ri);
     900        5354 :                 printf("\n");
     901             :         }
     902        6429 :         sdp->blks_total += be32_to_cpu(ri.ri_data);
     903        6429 :         sdp->fssize = be64_to_cpu(ri.ri_data0) + be32_to_cpu(ri.ri_data);
     904        6429 :         nrgrp++;
     905        6429 :         return 0;
     906             : }
     907             : 
     908        6499 : static int add_rgrp(lgfs2_rgrps_t rgs, uint64_t *addr, uint32_t len, lgfs2_rgrp_t *rg)
     909             : {
     910             :         struct gfs2_rindex ri;
     911             :         uint64_t nextaddr;
     912             : 
     913             :         /* When we get to the end of the device, it's only an error if we have
     914             :            more structures left to write, i.e. when len is != 0. */
     915        6499 :         nextaddr = lgfs2_rindex_entry_new(rgs, &ri, *addr, len);
     916        6499 :         if (nextaddr == 0) {
     917          70 :                 if (len != 0) {
     918           0 :                         perror(_("Failed to create resource group index entry"));
     919           0 :                         return -1;
     920             :                 } else {
     921          70 :                         return 1;
     922             :                 }
     923             :         }
     924        6429 :         *rg = lgfs2_rgrps_append(rgs, &ri, nextaddr - *addr);
     925        6429 :         if (*rg == NULL) {
     926           0 :                 perror(_("Failed to create resource group"));
     927           0 :                 return -1;
     928             :         }
     929        6429 :         *addr = nextaddr;
     930        6429 :         return 0;
     931             : }
     932             : 
     933          70 : static int place_journals(struct lgfs2_sbd *sdp, lgfs2_rgrps_t rgs, struct mkfs_opts *opts, uint64_t *rgaddr)
     934             : {
     935             :         struct gfs2_progress_bar progress;
     936          70 :         uint64_t jfsize = lgfs2_space_for_data(sdp, sdp->sd_bsize, opts->jsize << 20);
     937          70 :         uint32_t rgsize = lgfs2_rgsize_for_data(jfsize, sdp->sd_bsize);
     938             :         unsigned j;
     939             : 
     940          70 :         gfs2_progress_init(&progress, opts->journals, _("Adding journals: "), opts->quiet);
     941             : 
     942             :         /* We'll build the jindex later so remember where we put the journals */
     943          70 :         mkfs_journals = calloc(opts->journals, sizeof(*mkfs_journals));
     944          70 :         if (mkfs_journals == NULL)
     945           0 :                 return 1;
     946          70 :         *rgaddr = lgfs2_rgrp_align_addr(rgs, LGFS2_SB_ADDR(sdp) + 1);
     947          70 :         rgsize = lgfs2_rgrp_align_len(rgs, rgsize);
     948             : 
     949         147 :         for (j = 0; j < opts->journals; j++) {
     950             :                 int result;
     951             :                 lgfs2_rgrp_t rg;
     952          77 :                 struct lgfs2_inode in = {0};
     953             :                 struct gfs2_rindex ri;
     954             : 
     955          77 :                 gfs2_progress_update(&progress, (j + 1));
     956             : 
     957          77 :                 if (opts->debug)
     958          62 :                         printf(_("Placing resource group for journal%u\n"), j);
     959             : 
     960          77 :                 result = add_rgrp(rgs, rgaddr, rgsize, &rg);
     961          77 :                 if (result > 0)
     962           0 :                         break;
     963          77 :                 else if (result < 0)
     964           0 :                         return result;
     965             : 
     966          77 :                 result = lgfs2_rgrp_bitbuf_alloc(rg);
     967          77 :                 if (result != 0) {
     968           0 :                         perror(_("Failed to allocate space for bitmap buffer"));
     969           0 :                         return result;
     970             :                 }
     971             :                 /* Allocate at the beginning of the rgrp, bypassing extent search */
     972          77 :                 lgfs2_rindex_out(rg, &ri);
     973          77 :                 in.i_num.in_addr = be64_to_cpu(ri.ri_data0);
     974             :                 /* In order to keep writes sequential here, we have to allocate
     975             :                    the journal, then write the rgrp header (which is now in its
     976             :                    final form) and then write the journal out */
     977          77 :                 result = lgfs2_file_alloc(rg, opts->jsize << 20, &in, GFS2_DIF_SYSTEM, S_IFREG | 0600);
     978          77 :                 if (result != 0) {
     979           0 :                         fprintf(stderr, _("Failed to allocate space for journal %u\n"), j);
     980           0 :                         return result;
     981             :                 }
     982             : 
     983          77 :                 result = place_rgrp(sdp, rg, opts->debug);
     984          77 :                 if (result != 0)
     985           0 :                         return result;
     986             : 
     987          77 :                 lgfs2_rgrp_bitbuf_free(rg);
     988             : 
     989          77 :                 result = lgfs2_write_filemeta(&in);
     990          77 :                 if (result != 0) {
     991           0 :                         fprintf(stderr, _("Failed to write journal %u: %s\n"),
     992           0 :                                 j, strerror(errno));
     993           0 :                         return result;
     994             :                 }
     995             : 
     996          77 :                 result = lgfs2_write_journal_data(&in);
     997          77 :                 if (result != 0) {
     998           0 :                         fprintf(stderr, _("Failed to write data blocks for journal %u: %s\n"),
     999           0 :                                 j, strerror(errno));
    1000           0 :                         return result;
    1001             :                 }
    1002          77 :                 mkfs_journals[j] = in.i_num;
    1003             :         }
    1004          70 :         gfs2_progress_close(&progress, _("Done\n"));
    1005             : 
    1006          70 :         return 0;
    1007             : }
    1008             : 
    1009          70 : static int place_rgrps(struct lgfs2_sbd *sdp, lgfs2_rgrps_t rgs, uint64_t *rgaddr, struct mkfs_opts *opts)
    1010             : {
    1011             :         struct gfs2_progress_bar progress;
    1012          70 :         uint32_t rgblks = ((opts->rgsize << 20) / sdp->sd_bsize);
    1013             :         uint32_t rgnum;
    1014             :         int result;
    1015             : 
    1016          70 :         rgnum = lgfs2_rgrps_plan(rgs, sdp->device.length - *rgaddr, rgblks);
    1017          70 :         gfs2_progress_init(&progress, (rgnum + opts->journals), _("Building resource groups: "), opts->quiet);
    1018             : 
    1019        6352 :         while (1) {
    1020             :                 lgfs2_rgrp_t rg;
    1021        6422 :                 result = add_rgrp(rgs, rgaddr, 0, &rg);
    1022        6422 :                 if (result > 0)
    1023          70 :                         break;
    1024        6352 :                 else if (result < 0)
    1025           0 :                         return result;
    1026             : 
    1027        6352 :                 result = place_rgrp(sdp, rg, opts->debug);
    1028        6352 :                 if (result != 0) {
    1029           0 :                         fprintf(stderr, _("Failed to build resource groups\n"));
    1030           0 :                         return result;
    1031             :                 }
    1032        6352 :                 gfs2_progress_update(&progress, nrgrp);
    1033             :         }
    1034          70 :         if (lgfs2_rgrps_write_final(sdp->device_fd, rgs) != 0) {
    1035           0 :                 perror(_("Failed to write final resource group"));
    1036           0 :                 return 0;
    1037             :         }
    1038          70 :         gfs2_progress_close(&progress, _("Done\n"));
    1039             : 
    1040          70 :         return 0;
    1041             : }
    1042             : 
    1043          70 : static int create_jindex(struct lgfs2_sbd *sdp, struct mkfs_opts *opts, struct lgfs2_inum *jnls)
    1044             : {
    1045             :         struct lgfs2_inode *jindex;
    1046             : 
    1047          70 :         jindex = lgfs2_build_jindex(sdp->master_dir, jnls, opts->journals);
    1048          70 :         if (jindex == NULL) {
    1049           0 :                 fprintf(stderr, _("Error building '%s': %s\n"), "jindex", strerror(errno));
    1050           0 :                 return 1;
    1051             :         }
    1052          70 :         if (opts->debug) {
    1053          55 :                 printf("Jindex:\n");
    1054          55 :                 dinode_print(jindex->i_bh->b_data);
    1055             :         }
    1056          70 :         lgfs2_inode_put(&jindex);
    1057          70 :         return 0;
    1058             : }
    1059             : 
    1060             : 
    1061             : /*
    1062             :  * Find a reasonable journal file size (in blocks) given the number of blocks
    1063             :  * in the filesystem.  For very small filesystems, it is not reasonable to
    1064             :  * have a journal that fills more than half of the filesystem.
    1065             :  *
    1066             :  * n.b. comments assume 4k blocks
    1067             :  *
    1068             :  * This was copied and adapted from e2fsprogs.
    1069             :  */
    1070          66 : static int default_journal_size(unsigned bsize, uint64_t num_blocks)
    1071             : {
    1072          66 :         int min_blocks = (LGFS2_MIN_JSIZE << 20) / bsize;
    1073             : 
    1074          66 :         if (num_blocks < 2 * min_blocks)
    1075           0 :                 return -1;
    1076          66 :         if (num_blocks < 131072)        /* 512 MB */
    1077           2 :                 return min_blocks;              /* 8 MB */
    1078          64 :         if (num_blocks < 512*1024)      /* 2 GB */
    1079           1 :                 return (4096);                  /* 16 MB */
    1080          63 :         if (num_blocks < 2048*1024)     /* 8 GB */
    1081           0 :                 return (8192);                  /* 32 MB */
    1082          63 :         if (num_blocks < 4096*1024)     /* 16 GB */
    1083           2 :                 return (16384);                 /* 64 MB */
    1084          61 :         if (num_blocks < 262144*1024)   /*  1 TB */
    1085          61 :                 return (32768);                 /* 128 MB */
    1086           0 :         if (num_blocks < 2621440UL*1024)  /* 10 TB */
    1087           0 :                 return (131072);                /* 512 MB */
    1088           0 :         return 262144;                          /*   1 GB */
    1089             : }
    1090             : 
    1091          75 : static int sbd_init(struct lgfs2_sbd *sdp, struct mkfs_opts *opts, unsigned bsize)
    1092             : {
    1093          75 :         memset(sdp, 0, sizeof(struct lgfs2_sbd));
    1094          75 :         sdp->sd_time = time(NULL);
    1095          75 :         sdp->rgtree.osi_node = NULL;
    1096          75 :         sdp->rgsize = opts->rgsize;
    1097          75 :         sdp->qcsize = opts->qcsize;
    1098          75 :         sdp->jsize = opts->jsize;
    1099          75 :         sdp->md.journals = opts->journals;
    1100          75 :         sdp->device_fd = opts->dev.fd;
    1101          75 :         sdp->sd_bsize = bsize;
    1102          75 :         sdp->sd_fs_format = opts->format;
    1103          75 :         sdp->sd_multihost_format = GFS2_FORMAT_MULTI;
    1104          75 :         sdp->sd_bsize = bsize;
    1105          75 :         sdp->sd_bsize_shift = ffs(bsize) - 1;
    1106             : 
    1107          75 :         if (opts->got_uuid) {
    1108           4 :                 int err = uuid_parse(opts->uuid, sdp->sd_uuid);
    1109           4 :                 if (err != 0) {
    1110           3 :                         fprintf(stderr, _("Failed to parse UUID option."));
    1111           3 :                         return -1;
    1112             :                 }
    1113             :         } else
    1114          71 :                 uuid_generate(sdp->sd_uuid);
    1115             : 
    1116          72 :         if (lgfs2_compute_constants(sdp)) {
    1117           0 :                 perror(_("Failed to compute file system constants"));
    1118           0 :                 return -1;
    1119             :         }
    1120          72 :         sdp->device.length = opts->dev.size / sdp->sd_bsize;
    1121          72 :         if (opts->got_fssize) {
    1122           7 :                 if (opts->fssize > sdp->device.length) {
    1123           2 :                         fprintf(stderr, _("Specified size is bigger than the device."));
    1124           2 :                         fprintf(stderr, "%s %.2f %s (%"PRIu64" %s)\n", _("Device size:"),
    1125           2 :                                opts->dev.size / ((float)(1 << 30)), _("GB"),
    1126           2 :                                opts->dev.size / sdp->sd_bsize, _("blocks"));
    1127           2 :                         return -1;
    1128             :                 }
    1129           5 :                 sdp->device.length = opts->fssize;
    1130             :         }
    1131             :         /* opts->jsize has already been max/min checked but we need to check it
    1132             :            makes sense for the device size, or set a sensible default, if one
    1133             :            will fit. For user-provided journal sizes, limit it to half of the fs. */
    1134          70 :         if (!opts->got_jsize) {
    1135          66 :                 int default_jsize = default_journal_size(sdp->sd_bsize, sdp->device.length / opts->journals);
    1136             :                 unsigned jsize_mb;
    1137             : 
    1138          66 :                 if (default_jsize < 0) {
    1139           0 :                         fprintf(stderr, _("gfs2 will not fit on this device.\n"));
    1140           0 :                         return -1;
    1141             :                 }
    1142          66 :                 jsize_mb = (default_jsize * sdp->sd_bsize) >> 20;
    1143          66 :                 if (jsize_mb < LGFS2_MIN_JSIZE)
    1144           1 :                         opts->jsize = LGFS2_MIN_JSIZE;
    1145             :                 else
    1146          65 :                         opts->jsize = jsize_mb;
    1147           4 :         } else if ((((opts->jsize * opts->journals) << 20) / sdp->sd_bsize) > (sdp->device.length / 2)) {
    1148           0 :                 unsigned max_jsize = (sdp->device.length / 2 * sdp->sd_bsize / opts->journals) >> 20;
    1149             : 
    1150           0 :                 fprintf(stderr, _("gfs2 will not fit on this device.\n"));
    1151           0 :                 if (max_jsize >= LGFS2_MIN_JSIZE)
    1152           0 :                         fprintf(stderr, _("Maximum size for %u journals on this device is %uMB.\n"),
    1153             :                                 opts->journals, max_jsize);
    1154           0 :                 return -1;
    1155             :         }
    1156          70 :         sdp->jsize = opts->jsize;
    1157          70 :         return 0;
    1158             : }
    1159             : 
    1160          67 : static int probe_contents(struct mkfs_dev *dev)
    1161             : {
    1162             :         int ret;
    1163             :         const char *contents;
    1164          67 :         blkid_probe pr = blkid_new_probe();
    1165          67 :         if (pr == NULL || blkid_probe_set_device(pr, dev->fd, 0, 0) != 0
    1166          67 :                        || blkid_probe_enable_superblocks(pr, 1) != 0
    1167          67 :                        || blkid_probe_enable_partitions(pr, 1) != 0) {
    1168           0 :                 fprintf(stderr, _("Failed to create probe\n"));
    1169           0 :                 return -1;
    1170             :         }
    1171             : 
    1172          67 :         if (!S_ISREG(dev->stat.st_mode) && blkid_probe_enable_topology(pr, 1) != 0) {
    1173           0 :                 fprintf(stderr, _("Failed to create probe\n"));
    1174           0 :                 return -1;
    1175             :         }
    1176             : 
    1177          67 :         ret = blkid_do_fullprobe(pr);
    1178          67 :         if (ret == -1) {
    1179           0 :                 fprintf(stderr, _("Failed to probe device\n"));
    1180           0 :                 return -1;
    1181             :         }
    1182             : 
    1183          67 :         if (ret == 1)
    1184          54 :                 return 0;
    1185             : 
    1186          13 :         if (!blkid_probe_lookup_value(pr, "TYPE", &contents, NULL)) {
    1187          13 :                 printf(_("It appears to contain an existing filesystem (%s)\n"), contents);
    1188           0 :         } else if (!blkid_probe_lookup_value(pr, "PTTYPE", &contents, NULL)) {
    1189           0 :                 printf(_("It appears to contain a partition table (%s).\n"), contents);
    1190             :         }
    1191             : 
    1192          13 :         if (!S_ISREG(dev->stat.st_mode)) {
    1193           0 :                 blkid_topology tp = blkid_probe_get_topology(pr);
    1194           0 :                 if (tp != NULL) {
    1195           0 :                         dev->alignment_offset = blkid_topology_get_alignment_offset(tp);
    1196           0 :                         dev->logical_sector_size = blkid_topology_get_logical_sector_size(tp);
    1197           0 :                         dev->minimum_io_size = blkid_topology_get_minimum_io_size(tp);
    1198           0 :                         dev->optimal_io_size = blkid_topology_get_optimal_io_size(tp);
    1199           0 :                         dev->physical_sector_size = blkid_topology_get_physical_sector_size(tp);
    1200           0 :                         dev->got_topol = (dev->logical_sector_size != 0 &&
    1201           0 :                                           dev->physical_sector_size != 0);
    1202             :                 }
    1203             :         }
    1204             : 
    1205          13 :         blkid_free_probe(pr);
    1206          13 :         return 0;
    1207             : }
    1208             : 
    1209          75 : static int open_dev(struct mkfs_dev *dev, int withprobe)
    1210             : {
    1211             :         int error;
    1212             : 
    1213          75 :         dev->fd = open(dev->path, O_RDWR|O_CLOEXEC|O_EXCL);
    1214          75 :         if (dev->fd < 0) {
    1215           0 :                 perror(dev->path);
    1216           0 :                 return 1;
    1217             :         }
    1218             : 
    1219             :         /* Freshen up the cache */
    1220          75 :         (void)posix_fadvise(dev->fd, 0, 0, POSIX_FADV_DONTNEED);
    1221             : 
    1222          75 :         error = fstat(dev->fd, &dev->stat);
    1223          75 :         if (error < 0) {
    1224           0 :                 perror(dev->path);
    1225           0 :                 return 1;
    1226             :         }
    1227             : 
    1228          75 :         if (S_ISREG(dev->stat.st_mode)) {
    1229          75 :                 dev->size = dev->stat.st_size;
    1230           0 :         } else if (S_ISBLK(dev->stat.st_mode)) {
    1231           0 :                 dev->size = lseek(dev->fd, 0, SEEK_END);
    1232           0 :                 if (dev->size < 1) {
    1233           0 :                         fprintf(stderr, _("Device '%s' is too small\n"), dev->path);
    1234           0 :                         return 1;
    1235             :                 }
    1236             :         } else {
    1237           0 :                 fprintf(stderr, _("'%s' is not a block device or regular file\n"), dev->path);
    1238           0 :                 return 1;
    1239             :         }
    1240          75 :         if (withprobe && (probe_contents(dev) != 0))
    1241           0 :                 return 1;
    1242          75 :         return 0;
    1243             : }
    1244             : 
    1245             : #ifndef UNITTESTS
    1246          97 : int main(int argc, char *argv[])
    1247             : {
    1248             :         struct gfs2_statfs_change sc;
    1249             :         struct lgfs2_sbd sbd;
    1250             :         struct mkfs_opts opts;
    1251             :         struct lgfs2_inode *ip;
    1252             :         lgfs2_rgrps_t rgs;
    1253             :         uint64_t rgaddr;
    1254             :         int error;
    1255             :         unsigned bsize;
    1256             : 
    1257          97 :         setlocale(LC_ALL, "");
    1258          97 :         textdomain("gfs2-utils");
    1259          97 :         srandom(time(NULL) ^ getpid());
    1260             : 
    1261          97 :         opts_init(&opts);
    1262          97 :         error = opts_get(argc, argv, &opts);
    1263          97 :         if (error == 1)
    1264           0 :                 exit(0);
    1265          97 :         if (error != 0)
    1266           9 :                 exit(-1);
    1267          88 :         error = opts_check(&opts);
    1268          88 :         if (error != 0)
    1269          13 :                 exit(error);
    1270             : 
    1271          75 :         error = open_dev(&opts.dev, !opts.got_topol);
    1272          75 :         if (error != 0)
    1273           0 :                 exit(error);
    1274          75 :         error = choose_blocksize(&opts, &bsize);
    1275          75 :         if (error != 0)
    1276           0 :                 exit(-1);
    1277             : 
    1278          75 :         if (S_ISREG(opts.dev.stat.st_mode)) {
    1279          75 :                 opts.got_bsize = 1; /* Use default block size for regular files */
    1280             :         }
    1281          75 :         if (sbd_init(&sbd, &opts, bsize) != 0)
    1282           5 :                 exit(-1);
    1283          70 :         if (opts.debug) {
    1284          55 :                 printf(_("File system options:\n"));
    1285          55 :                 printf("  bsize = %u\n", sbd.sd_bsize);
    1286          55 :                 printf("  qcsize = %u\n", sbd.qcsize);
    1287          55 :                 printf("  jsize = %u\n", sbd.jsize);
    1288          55 :                 printf("  journals = %u\n", sbd.md.journals);
    1289          55 :                 printf("  proto = %s\n", opts.lockproto);
    1290          55 :                 printf("  table = %s\n", opts.locktable);
    1291          55 :                 printf("  rgsize = %u\n", sbd.rgsize);
    1292          55 :                 printf("  fssize = %"PRIu64"\n", opts.fssize);
    1293          55 :                 printf("  sunit = %lu\n", opts.sunit);
    1294          55 :                 printf("  swidth = %lu\n", opts.swidth);
    1295          55 :                 printf("  format = %u\n", opts.format);
    1296             :         }
    1297          70 :         rgs = rgs_init(&opts, &sbd);
    1298          70 :         if (rgs == NULL)
    1299           0 :                 exit(-1);
    1300          70 :         if (warn_of_destruction(opts.dev.path) != 0)
    1301           0 :                 exit(-1);
    1302             : 
    1303          70 :         if (opts.confirm && !opts.override)
    1304           0 :                 if (!are_you_sure())
    1305           0 :                         exit(-1);
    1306             : 
    1307          70 :         if (!S_ISREG(opts.dev.stat.st_mode) && opts.discard) {
    1308           0 :                 if (!opts.quiet) {
    1309           0 :                         printf("%s", _("Discarding device contents (may take a while on large devices): "));
    1310           0 :                         fflush(stdout);
    1311             :                 }
    1312           0 :                 discard_blocks(opts.dev.fd, opts.dev.size, opts.debug);
    1313             : 
    1314           0 :                 if (!opts.quiet)
    1315           0 :                         printf("%s", _("Done\n"));
    1316             :         }
    1317          70 :         rgaddr = lgfs2_rgrp_align_addr(rgs, LGFS2_SB_ADDR(&sbd) + 1);
    1318          70 :         error = place_journals(&sbd, rgs, &opts, &rgaddr);
    1319          70 :         if (error != 0) {
    1320           0 :                 fprintf(stderr, _("Failed to create journals\n"));
    1321           0 :                 exit(1);
    1322             :         }
    1323          70 :         error = place_rgrps(&sbd, rgs, &rgaddr, &opts);
    1324          70 :         if (error) {
    1325           0 :                 fprintf(stderr, _("Failed to build resource groups\n"));
    1326           0 :                 exit(1);
    1327             :         }
    1328          70 :         lgfs2_attach_rgrps(&sbd, rgs); // Temporary
    1329             : 
    1330          70 :         error = lgfs2_build_master(&sbd);
    1331          70 :         if (error) {
    1332           0 :                 fprintf(stderr, _("Error building '%s': %s\n"), "master", strerror(errno));
    1333           0 :                 exit(EXIT_FAILURE);
    1334             :         }
    1335          70 :         if (opts.debug) {
    1336          55 :                 printf("Metafs inode:\n");
    1337          55 :                 dinode_print(sbd.master_dir->i_bh->b_data);
    1338             :         }
    1339          70 :         sbd.sd_meta_dir = sbd.master_dir->i_num;
    1340             : 
    1341          70 :         error = create_jindex(&sbd, &opts, mkfs_journals);
    1342          70 :         free(mkfs_journals);
    1343          70 :         if (error != 0)
    1344           0 :                 exit(1);
    1345             : 
    1346          70 :         error = build_per_node(&sbd, &opts);
    1347          70 :         if (error != 0)
    1348           0 :                 exit(1);
    1349             : 
    1350          70 :         sbd.md.inum = lgfs2_build_inum(&sbd);
    1351          70 :         if (sbd.md.inum == NULL) {
    1352           0 :                 fprintf(stderr, _("Error building '%s': %s\n"), "inum", strerror(errno));
    1353           0 :                 exit(EXIT_FAILURE);
    1354             :         }
    1355          70 :         if (opts.debug) {
    1356          55 :                 printf("\nInum Inode:\n");
    1357          55 :                 dinode_print(sbd.md.inum->i_bh->b_data);
    1358             :         }
    1359          70 :         sbd.md.statfs = lgfs2_build_statfs(&sbd);
    1360          70 :         if (sbd.md.statfs == NULL) {
    1361           0 :                 fprintf(stderr, _("Error building '%s': %s\n"), "statfs", strerror(errno));
    1362           0 :                 exit(EXIT_FAILURE);
    1363             :         }
    1364          70 :         if (opts.debug) {
    1365          55 :                 printf("\nStatFS Inode:\n");
    1366          55 :                 dinode_print(sbd.md.statfs->i_bh->b_data);
    1367             :         }
    1368          70 :         ip = lgfs2_build_rindex(&sbd);
    1369          70 :         if (ip == NULL) {
    1370           0 :                 fprintf(stderr, _("Error building '%s': %s\n"), "rindex", strerror(errno));
    1371           0 :                 exit(EXIT_FAILURE);
    1372             :         }
    1373          70 :         if (opts.debug) {
    1374          55 :                 printf("\nResource Index:\n");
    1375          55 :                 dinode_print(ip->i_bh->b_data);
    1376             :         }
    1377          70 :         lgfs2_inode_put(&ip);
    1378          70 :         if (!opts.quiet) {
    1379          70 :                 printf("%s", _("Creating quota file: "));
    1380          70 :                 fflush(stdout);
    1381             :         }
    1382          70 :         ip = lgfs2_build_quota(&sbd);
    1383          70 :         if (ip == NULL) {
    1384           0 :                 fprintf(stderr, _("Error building '%s': %s\n"), "quota", strerror(errno));
    1385           0 :                 exit(EXIT_FAILURE);
    1386             :         }
    1387          70 :         if (opts.debug) {
    1388          55 :                 printf("\nQuota:\n");
    1389          55 :                 dinode_print(ip->i_bh->b_data);
    1390             :         }
    1391          70 :         lgfs2_inode_put(&ip);
    1392          70 :         if (!opts.quiet)
    1393          70 :                 printf("%s", _("Done\n"));
    1394             : 
    1395          70 :         lgfs2_build_root(&sbd);
    1396          70 :         if (opts.root_inherit_jd) {
    1397           2 :                 sbd.md.rooti->i_flags |= GFS2_DIF_INHERIT_JDATA;
    1398           2 :                 lgfs2_dinode_out(sbd.md.rooti, sbd.md.rooti->i_bh->b_data);
    1399             :         }
    1400          70 :         if (opts.debug) {
    1401          55 :                 printf("\nRoot directory:\n");
    1402          55 :                 dinode_print(sbd.md.rooti->i_bh->b_data);
    1403             :         }
    1404          70 :         sbd.sd_root_dir = sbd.md.rooti->i_num;
    1405             : 
    1406          70 :         strncpy(sbd.sd_lockproto, opts.lockproto, GFS2_LOCKNAME_LEN - 1);
    1407          70 :         strncpy(sbd.sd_locktable, opts.locktable, GFS2_LOCKNAME_LEN - 1);
    1408          70 :         sbd.sd_lockproto[GFS2_LOCKNAME_LEN - 1] = '\0';
    1409          70 :         sbd.sd_locktable[GFS2_LOCKNAME_LEN - 1] = '\0';
    1410             : 
    1411          70 :         lgfs2_init_inum(&sbd);
    1412          70 :         if (opts.debug)
    1413          55 :                 printf("\nNext Inum: %"PRIu64"\n", sbd.md.next_inum);
    1414             : 
    1415          70 :         lgfs2_init_statfs(&sbd, &sc);
    1416          70 :         if (opts.debug) {
    1417          55 :                 printf("\nStatfs:\n");
    1418          55 :                 statfs_change_print(&sc);
    1419             :         }
    1420          70 :         lgfs2_inode_put(&sbd.md.rooti);
    1421          70 :         lgfs2_inode_put(&sbd.master_dir);
    1422          70 :         lgfs2_inode_put(&sbd.md.inum);
    1423          70 :         lgfs2_inode_put(&sbd.md.statfs);
    1424             : 
    1425          70 :         lgfs2_rgrps_free(&rgs);
    1426             : 
    1427          70 :         if (!opts.quiet) {
    1428          70 :                 printf("%s", _("Writing superblock and syncing: "));
    1429          70 :                 fflush(stdout);
    1430             :         }
    1431             : 
    1432          70 :         error = lgfs2_sb_write(&sbd, opts.dev.fd);
    1433          70 :         if (error) {
    1434           0 :                 perror(_("Failed to write superblock\n"));
    1435           0 :                 exit(EXIT_FAILURE);
    1436             :         }
    1437             : 
    1438          70 :         error = fsync(opts.dev.fd);
    1439          70 :         if (error){
    1440           0 :                 perror(opts.dev.path);
    1441           0 :                 exit(EXIT_FAILURE);
    1442             :         }
    1443          70 :         error = close(opts.dev.fd);
    1444          70 :         if (error){
    1445           0 :                 perror(opts.dev.path);
    1446           0 :                 exit(EXIT_FAILURE);
    1447             :         }
    1448             : 
    1449          70 :         if (!opts.quiet) {
    1450          70 :                 printf("%s", _("Done\n"));
    1451          70 :                 print_results(&sbd, &opts);
    1452             :         }
    1453          70 :         return 0;
    1454             : }
    1455             : #endif /* UNITTESTS */

Generated by: LCOV version 1.14