LCOV - code coverage report
Current view: top level - mkfs - main_mkfs.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 65.1 % 895 583
Test Date: 2024-03-07 16:24:06 Functions: 87.1 % 31 27

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

Generated by: LCOV version 2.0-1