Don't always enable MTD mode unless MTD device is specified

On MTD devices, don't always enable MTD mode - the installer needs to
be able to access both the GPT disk and the MTD disk, so only
enable it if we install to /dev/fts

BRANCH=none
BUG=chromium:221745
TEST=make runtests

Change-Id: I7688e6bc758ef47cfb9d468c1224ef43b2043d02
Reviewed-on: https://gerrit.chromium.org/gerrit/62662
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Commit-Queue: Albert Chaulk <achaulk@chromium.org>
Tested-by: Albert Chaulk <achaulk@chromium.org>
diff --git a/cgpt/cgpt.c b/cgpt/cgpt.c
index e02bf4d..e49d430 100644
--- a/cgpt/cgpt.c
+++ b/cgpt/cgpt.c
@@ -18,8 +18,6 @@
 const char* command;
 void (*uuid_generator)(uint8_t* buffer);
 
-extern struct nand_layout nand;
-
 struct {
   const char *name;
   int (*fp)(int argc, char *argv[]);
@@ -54,33 +52,37 @@
 }
 
 static int parse_nand_option(const char *arg) {
+  int bytes_per_page, pages_per_block, fts_block_offset, fts_block_size;
+
   if ('=' != arg[0])
     return -1;
 
   arg++;
-  nand.bytes_per_page = atoi(arg);
+  bytes_per_page = atoi(arg);
   arg = strchr(arg, ',');
   if (!arg)
     return -1;
 
   arg++;
-  nand.pages_per_block = atoi(arg);
+  pages_per_block = atoi(arg);
   arg = strchr(arg, ',');
   if (!arg)
     return -1;
 
   arg++;
-  nand.fts_block_offset = atoi(arg);
+  fts_block_offset = atoi(arg);
   arg = strchr(arg, ',');
   if (!arg)
     return -1;
 
   arg++;
-  nand.fts_block_size = atoi(arg);
-  if (nand.fts_block_size == 0 || !is_pow2(nand.pages_per_block) ||
-    !is_pow2(nand.bytes_per_page) || nand.bytes_per_page < 512) {
+  fts_block_size = atoi(arg);
+  if (fts_block_size == 0 || !is_pow2(pages_per_block) ||
+      !is_pow2(bytes_per_page) || bytes_per_page < 512) {
     return -1;
   }
+  EnableNandImage(bytes_per_page, pages_per_block, fts_block_offset,
+                  fts_block_size);
   return 0;
 }
 
@@ -98,12 +100,10 @@
     progname = argv[0];
 
 
-  memset(&nand, 0, sizeof(nand));
   for (i = 1; i < argc; ++i) {
     if (0 == strncmp(argv[i], "-N", 2)) {
       if (!parse_nand_option(argv[i] + 2)) {
         int j;
-        nand.enabled = 1;
 
         // Remove it form the list.
         for (j = i; j < argc - 1; j++)
@@ -118,8 +118,6 @@
     }
   }
 
-  TryInitMtd();
-
   if (argc < 2) {
     Usage();
     return CGPT_FAILED;
diff --git a/cgpt/cgpt.h b/cgpt/cgpt.h
index 038a6d4..c6b0b9b 100644
--- a/cgpt/cgpt.h
+++ b/cgpt/cgpt.h
@@ -58,14 +58,15 @@
   int bytes_per_page, pages_per_block, fts_block_offset, fts_block_size;
 };
 
+/* Write a NAND/MTD image instead of GPT. */
+void EnableNandImage(int bytes_per_page, int pages_per_block,
+                     int fts_block_offset, int fts_block_size);
 
 /* mode should be O_RDONLY or O_RDWR */
 int DriveOpen(const char *drive_path, struct drive *drive, int mode);
 int DriveClose(struct drive *drive, int update_as_needed);
 int CheckValid(const struct drive *drive);
 
-void TryInitMtd(void);
-
 /* Loads sectors from 'drive'.
  * *buf is pointed to an allocated memory when returned, and should be
  * freed.
diff --git a/cgpt/cgpt_add.c b/cgpt/cgpt_add.c
index 117b4a1..e0e24b8 100644
--- a/cgpt/cgpt_add.c
+++ b/cgpt/cgpt_add.c
@@ -203,7 +203,6 @@
   if (params == NULL)
     return CGPT_FAILED;
 
-  TryInitMtd();
   if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR))
     return CGPT_FAILED;
 
@@ -241,7 +240,6 @@
   if (params == NULL)
     return CGPT_FAILED;
 
-  TryInitMtd();
   if (CGPT_OK != DriveOpen(params->drive_name, &drive, O_RDWR))
     return CGPT_FAILED;
 
diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c
index 8b3b8a4..1a1c9e8 100644
--- a/cgpt/cgpt_common.c
+++ b/cgpt/cgpt_common.c
@@ -27,9 +27,16 @@
 #include "flash_ts_api.h"
 #include "vboot_host.h"
 
-struct nand_layout nand = {
-  0, 0, 0, 0, 0
-};
+struct nand_layout nand;
+
+void EnableNandImage(int bytes_per_page, int pages_per_block,
+                     int fts_block_offset, int fts_block_size) {
+  nand.enabled = 1;
+  nand.bytes_per_page = bytes_per_page;
+  nand.pages_per_block = pages_per_block;
+  nand.fts_block_offset = fts_block_offset;
+  nand.fts_block_size = fts_block_size;
+}
 
 void Error(const char *format, ...) {
   va_list ap;
@@ -150,20 +157,23 @@
   return -1;
 }
 
-void TryInitMtd(void) {
+int TryInitMtd(const char *dev) {
   static int already_inited = 0;
-  if (nand.enabled || already_inited)
-    return;
+  if (already_inited)
+    return nand.use_host_ioctl;
 
   already_inited = 1;
 
   /* If we're running on the live system, we can just use /dev/fts and not
-   * actually need the specific parameters.
+   * actually need the specific parameters. This needs to be accessed via
+   * ioctl and not normal I/O.
    */
-  if (!access(FTS_DEVICE, R_OK | W_OK)) {
+  if (!strcmp(dev, FTS_DEVICE) && !access(FTS_DEVICE, R_OK | W_OK)) {
     nand.enabled = 1;
     nand.use_host_ioctl = 1;
+    return 1;
   }
+  return 0;
 }
 
 int FlashGet(const char *key, uint8_t *data, uint32_t *bufsz) {
@@ -174,7 +184,7 @@
   if (nand.use_host_ioctl) {
     struct flash_ts_io_req req;
     strncpy(req.key, key, sizeof(req.key));
-    int fd = open("/dev/fts", O_RDWR);
+    int fd = open(FTS_DEVICE, O_RDWR);
     if (fd < 0)
       return -1;
     if (ioctl(fd, FLASH_TS_IO_GET, &req))
@@ -220,7 +230,7 @@
     strncpy(req.key, key, sizeof(req.key));
     strncpy(req.val, hex, sizeof(req.val));
     free(hex);
-    int fd = open("/dev/fts", O_RDWR);
+    int fd = open(FTS_DEVICE, O_RDWR);
     if (fd < 0)
       return -1;
     if (ioctl(fd, FLASH_TS_IO_SET, &req))
@@ -248,9 +258,9 @@
                         mtd->flash_block_bytes,
                         mtd->sector_bytes, /* Needed for Load() and Save() */
                         drive);
+    if (ret)
+      return ret;
   }
-  if (ret)
-    return ret;
 
   memset(&mtd->primary, 0, sizeof(mtd->primary));
   sz = sizeof(mtd->primary);
@@ -262,6 +272,14 @@
   if (sz < MTD_DRIVE_V1_SIZE)
     memset(&mtd->primary, 0, sizeof(mtd->primary));
 
+  if (nand.use_host_ioctl) {
+    /* If we are using /dev/fts, we can't stat() the size, so re-use
+     * our internal value to set it.
+     */
+    drive->size = mtd->primary.last_offset + 1;
+    mtd->drive_sectors = drive->size / mtd->sector_bytes;
+  }
+
   mtd->current_kernel = -1;
   mtd->current_priority = 0;
   mtd->modified = 0;
@@ -384,31 +402,37 @@
   // Clear struct for proper error handling.
   memset(drive, 0, sizeof(struct drive));
 
-  drive->is_mtd = is_mtd;
-  drive->fd = open(drive_path, mode | O_LARGEFILE | O_NOFOLLOW);
-  if (drive->fd == -1) {
-    Error("Can't open %s: %s\n", drive_path, strerror(errno));
-    return CGPT_FAILED;
-  }
-
-  if (fstat(drive->fd, &stat) == -1) {
-    Error("Can't fstat %s: %s\n", drive_path, strerror(errno));
-    goto error_close;
-  }
-  if ((stat.st_mode & S_IFMT) != S_IFREG) {
-    if (ioctl(drive->fd, BLKGETSIZE64, &drive->size) < 0) {
-      Error("Can't read drive size from %s: %s\n", drive_path, strerror(errno));
-      goto error_close;
-    }
-    if (ioctl(drive->fd, BLKSSZGET, &sector_bytes) < 0) {
-      Error("Can't read sector size from %s: %s\n",
-            drive_path, strerror(errno));
-      goto error_close;
-    }
-  } else {
+  if (TryInitMtd(drive_path)) {
+    is_mtd = 1;
     sector_bytes = 512;  /* bytes */
-    drive->size = stat.st_size;
+  } else {
+    drive->fd = open(drive_path, mode | O_LARGEFILE | O_NOFOLLOW);
+    if (drive->fd == -1) {
+      Error("Can't open %s: %s\n", drive_path, strerror(errno));
+      return CGPT_FAILED;
+    }
+
+    if (fstat(drive->fd, &stat) == -1) {
+      Error("Can't fstat %s: %s\n", drive_path, strerror(errno));
+      goto error_close;
+    }
+    if ((stat.st_mode & S_IFMT) != S_IFREG) {
+      if (ioctl(drive->fd, BLKGETSIZE64, &drive->size) < 0) {
+        Error("Can't read drive size from %s: %s\n", drive_path,
+              strerror(errno));
+        goto error_close;
+      }
+      if (ioctl(drive->fd, BLKSSZGET, &sector_bytes) < 0) {
+        Error("Can't read sector size from %s: %s\n",
+              drive_path, strerror(errno));
+        goto error_close;
+      }
+    } else {
+      sector_bytes = 512;  /* bytes */
+      drive->size = stat.st_size;
+    }
   }
+  drive->is_mtd = is_mtd;
 
   if (is_mtd) {
     drive->mtd.fts_block_offset = nand.fts_block_offset;