github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/gadget/ondisk_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019-2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package gadget_test 21 22 import ( 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 27 . "gopkg.in/check.v1" 28 29 "github.com/snapcore/snapd/gadget" 30 "github.com/snapcore/snapd/gadget/quantity" 31 "github.com/snapcore/snapd/testutil" 32 ) 33 34 type ondiskTestSuite struct { 35 testutil.BaseTest 36 37 dir string 38 39 gadgetRoot string 40 } 41 42 var _ = Suite(&ondiskTestSuite{}) 43 44 func (s *ondiskTestSuite) SetUpTest(c *C) { 45 s.BaseTest.SetUpTest(c) 46 47 s.dir = c.MkDir() 48 49 s.gadgetRoot = c.MkDir() 50 err := makeMockGadget(s.gadgetRoot, gadgetContent) 51 c.Assert(err, IsNil) 52 } 53 54 const mockSfdiskScriptBiosSeed = ` 55 >&2 echo "Some warning from sfdisk" 56 echo '{ 57 "partitiontable": { 58 "label": "gpt", 59 "id": "9151F25B-CDF0-48F1-9EDE-68CBD616E2CA", 60 "device": "/dev/node", 61 "unit": "sectors", 62 "firstlba": 34, 63 "lastlba": 8388574, 64 "partitions": [ 65 { 66 "node": "/dev/node1", 67 "start": 2048, 68 "size": 2048, 69 "type": "21686148-6449-6E6F-744E-656564454649", 70 "uuid": "2E59D969-52AB-430B-88AC-F83873519F6F", 71 "name": "BIOS Boot" 72 }, 73 { 74 "node": "/dev/node2", 75 "start": 4096, 76 "size": 2457600, 77 "type": "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", 78 "uuid": "44C3D5C3-CAE1-4306-83E8-DF437ACDB32F", 79 "name": "Recovery" 80 } 81 ] 82 } 83 }'` 84 85 const mockLsblkScriptBiosSeed = ` 86 [ "$3" == "/dev/node1" ] && echo '{ 87 "blockdevices": [ {"name": "node1", "fstype": null, "label": null, "uuid": null, "mountpoint": null} ] 88 }' 89 [ "$3" == "/dev/node2" ] && echo '{ 90 "blockdevices": [ {"name": "node2", "fstype": "vfat", "label": "ubuntu-seed", "uuid": "A644-B807", "mountpoint": null} ] 91 }' 92 exit 0` 93 94 func makeMockGadget(gadgetRoot, gadgetContent string) error { 95 if err := os.MkdirAll(filepath.Join(gadgetRoot, "meta"), 0755); err != nil { 96 return err 97 } 98 if err := ioutil.WriteFile(filepath.Join(gadgetRoot, "meta", "gadget.yaml"), []byte(gadgetContent), 0644); err != nil { 99 return err 100 } 101 if err := ioutil.WriteFile(filepath.Join(gadgetRoot, "pc-boot.img"), []byte("pc-boot.img content"), 0644); err != nil { 102 return err 103 } 104 if err := ioutil.WriteFile(filepath.Join(gadgetRoot, "pc-core.img"), []byte("pc-core.img content"), 0644); err != nil { 105 return err 106 } 107 if err := ioutil.WriteFile(filepath.Join(gadgetRoot, "grubx64.efi"), []byte("grubx64.efi content"), 0644); err != nil { 108 return err 109 } 110 111 return nil 112 } 113 114 const gadgetContent = `volumes: 115 pc: 116 bootloader: grub 117 structure: 118 - name: mbr 119 type: mbr 120 size: 440 121 content: 122 - image: pc-boot.img 123 - name: BIOS Boot 124 type: DA,21686148-6449-6E6F-744E-656564454649 125 size: 1M 126 offset: 1M 127 offset-write: mbr+92 128 content: 129 - image: pc-core.img 130 - name: Recovery 131 role: system-seed 132 filesystem: vfat 133 # UEFI will boot the ESP partition by default first 134 type: EF,C12A7328-F81F-11D2-BA4B-00A0C93EC93B 135 size: 1200M 136 content: 137 - source: grubx64.efi 138 target: EFI/boot/grubx64.efi 139 - name: Save 140 role: system-save 141 filesystem: ext4 142 type: 83,0FC63DAF-8483-4772-8E79-3D69D8477DE4 143 size: 128M 144 - name: Writable 145 role: system-data 146 filesystem: ext4 147 type: 83,0FC63DAF-8483-4772-8E79-3D69D8477DE4 148 size: 1200M 149 ` 150 151 func (s *ondiskTestSuite) TestDeviceInfoGPT(c *C) { 152 cmdSfdisk := testutil.MockCommand(c, "sfdisk", mockSfdiskScriptBiosSeed) 153 defer cmdSfdisk.Restore() 154 155 cmdLsblk := testutil.MockCommand(c, "lsblk", mockLsblkScriptBiosSeed) 156 defer cmdLsblk.Restore() 157 158 cmdBlockdev := testutil.MockCommand(c, "blockdev", ` 159 if [ "$1" == --getss ]; then 160 # sector size 161 echo 512 162 exit 0 163 fi 164 echo "unexpected cmdline opts: $*" 165 exit 1 166 `) 167 defer cmdBlockdev.Restore() 168 169 dl, err := gadget.OnDiskVolumeFromDevice("/dev/node") 170 c.Assert(err, IsNil) 171 c.Assert(cmdSfdisk.Calls(), DeepEquals, [][]string{ 172 {"sfdisk", "--json", "/dev/node"}, 173 }) 174 c.Assert(cmdLsblk.Calls(), DeepEquals, [][]string{ 175 {"lsblk", "--fs", "--json", "/dev/node1"}, 176 {"lsblk", "--fs", "--json", "/dev/node2"}, 177 }) 178 c.Assert(cmdBlockdev.Calls(), DeepEquals, [][]string{ 179 {"blockdev", "--getss", "/dev/node"}, 180 }) 181 c.Assert(err, IsNil) 182 c.Assert(dl, DeepEquals, &gadget.OnDiskVolume{ 183 Device: "/dev/node", 184 ID: "9151F25B-CDF0-48F1-9EDE-68CBD616E2CA", 185 Schema: "gpt", 186 SectorSize: quantity.Size(512), 187 Size: quantity.Size(8388575 * 512), 188 Structure: []gadget.OnDiskStructure{ 189 { 190 LaidOutStructure: gadget.LaidOutStructure{ 191 VolumeStructure: &gadget.VolumeStructure{ 192 Name: "BIOS Boot", 193 Size: 0x100000, 194 Label: "", 195 Type: "21686148-6449-6E6F-744E-656564454649", 196 Filesystem: "", 197 }, 198 StartOffset: 0x100000, 199 Index: 1, 200 }, 201 Node: "/dev/node1", 202 }, 203 { 204 LaidOutStructure: gadget.LaidOutStructure{ 205 VolumeStructure: &gadget.VolumeStructure{ 206 Name: "Recovery", 207 Size: 0x4b000000, 208 Label: "ubuntu-seed", 209 Type: "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", 210 Filesystem: "vfat", 211 }, 212 StartOffset: 0x200000, 213 Index: 2, 214 }, 215 Node: "/dev/node2", 216 }, 217 }, 218 }) 219 } 220 221 func (s *ondiskTestSuite) TestDeviceInfoGPT4096SectorSize(c *C) { 222 cmdSfdisk := testutil.MockCommand(c, "sfdisk", mockSfdiskScriptBiosSeed) 223 defer cmdSfdisk.Restore() 224 225 cmdLsblk := testutil.MockCommand(c, "lsblk", mockLsblkScriptBiosSeed) 226 defer cmdLsblk.Restore() 227 228 cmdBlockdev := testutil.MockCommand(c, "blockdev", ` 229 if [ "$1" == --getss ]; then 230 # sector size 231 echo 4096 232 exit 0 233 fi 234 echo "unexpected cmdline opts: $*" 235 exit 1 236 `) 237 defer cmdBlockdev.Restore() 238 239 dl, err := gadget.OnDiskVolumeFromDevice("/dev/node") 240 c.Assert(err, IsNil) 241 c.Assert(cmdSfdisk.Calls(), DeepEquals, [][]string{ 242 {"sfdisk", "--json", "/dev/node"}, 243 }) 244 c.Assert(cmdLsblk.Calls(), DeepEquals, [][]string{ 245 {"lsblk", "--fs", "--json", "/dev/node1"}, 246 {"lsblk", "--fs", "--json", "/dev/node2"}, 247 }) 248 c.Assert(cmdBlockdev.Calls(), DeepEquals, [][]string{ 249 {"blockdev", "--getss", "/dev/node"}, 250 }) 251 c.Assert(err, IsNil) 252 c.Assert(dl, DeepEquals, &gadget.OnDiskVolume{ 253 Device: "/dev/node", 254 ID: "9151F25B-CDF0-48F1-9EDE-68CBD616E2CA", 255 Schema: "gpt", 256 SectorSize: quantity.Size(4096), 257 Size: quantity.Size(8388575 * 4096), 258 Structure: []gadget.OnDiskStructure{ 259 { 260 LaidOutStructure: gadget.LaidOutStructure{ 261 VolumeStructure: &gadget.VolumeStructure{ 262 Name: "BIOS Boot", 263 Size: 0x800000, 264 Label: "", 265 Type: "21686148-6449-6E6F-744E-656564454649", 266 Filesystem: "", 267 }, 268 StartOffset: 0x800000, 269 Index: 1, 270 }, 271 Node: "/dev/node1", 272 }, 273 { 274 LaidOutStructure: gadget.LaidOutStructure{ 275 VolumeStructure: &gadget.VolumeStructure{ 276 Name: "Recovery", 277 Size: 0x258000000, 278 Label: "ubuntu-seed", 279 Type: "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", 280 Filesystem: "vfat", 281 }, 282 StartOffset: 0x1000000, 283 Index: 2, 284 }, 285 Node: "/dev/node2", 286 }, 287 }, 288 }) 289 } 290 291 func (s *ondiskTestSuite) TestDeviceInfoMBR(c *C) { 292 const mockSfdiskWithMBR = ` 293 >&2 echo "Some warning from sfdisk" 294 echo '{ 295 "partitiontable": { 296 "label": "dos", 297 "device": "/dev/node", 298 "unit": "sectors", 299 "partitions": [ 300 {"node": "/dev/node1", "start": 4096, "size": 2457600, "type": "c"}, 301 {"node": "/dev/node2", "start": 2461696, "size": 1048576, "type": "d"}, 302 {"node": "/dev/node3", "start": 3510272, "size": 1048576, "type": "d"}, 303 {"node": "/dev/node4", "start": 4558848, "size": 1048576, "type": "d"} 304 ] 305 } 306 }'` 307 const mockLsblkForMBR = ` 308 [ "$3" == "/dev/node1" ] && echo '{ 309 "blockdevices": [ {"name": "node1", "fstype": "vfat", "label": "ubuntu-seed", "uuid": "A644-B807", "mountpoint": null} ] 310 }' 311 [ "$3" == "/dev/node2" ] && echo '{ 312 "blockdevices": [ {"name": "node2", "fstype": "vfat", "label": "ubuntu-boot", "uuid": "A644-B808", "mountpoint": null} ] 313 }' 314 [ "$3" == "/dev/node3" ] && echo '{ 315 "blockdevices": [ {"name": "node3", "fstype": "ext4", "label": "ubuntu-save", "mountpoint": null} ] 316 }' 317 [ "$3" == "/dev/node4" ] && echo '{ 318 "blockdevices": [ {"name": "node3", "fstype": "ext4", "label": "ubuntu-data", "mountpoint": null} ] 319 }' 320 exit 0` 321 322 cmdSfdisk := testutil.MockCommand(c, "sfdisk", mockSfdiskWithMBR) 323 defer cmdSfdisk.Restore() 324 325 cmdLsblk := testutil.MockCommand(c, "lsblk", mockLsblkForMBR) 326 defer cmdLsblk.Restore() 327 328 cmdBlockdev := testutil.MockCommand(c, "blockdev", ` 329 if [ "$1" == --getss ]; then 330 # sector size 331 echo 512 332 exit 0 333 elif [ "$1" == --getsz ]; then 334 # disk size in 512-byte sectors 335 echo 12345670 336 exit 0 337 fi 338 echo "unexpected cmdline opts: $*" 339 exit 1 340 `) 341 defer cmdBlockdev.Restore() 342 343 dl, err := gadget.OnDiskVolumeFromDevice("/dev/node") 344 c.Assert(err, IsNil) 345 c.Assert(cmdSfdisk.Calls(), DeepEquals, [][]string{ 346 {"sfdisk", "--json", "/dev/node"}, 347 }) 348 c.Assert(cmdLsblk.Calls(), DeepEquals, [][]string{ 349 {"lsblk", "--fs", "--json", "/dev/node1"}, 350 {"lsblk", "--fs", "--json", "/dev/node2"}, 351 {"lsblk", "--fs", "--json", "/dev/node3"}, 352 {"lsblk", "--fs", "--json", "/dev/node4"}, 353 }) 354 c.Assert(cmdBlockdev.Calls(), DeepEquals, [][]string{ 355 {"blockdev", "--getss", "/dev/node"}, 356 {"blockdev", "--getsz", "/dev/node"}, 357 }) 358 c.Assert(err, IsNil) 359 360 c.Assert(dl, DeepEquals, &gadget.OnDiskVolume{ 361 Device: "/dev/node", 362 Schema: "dos", 363 SectorSize: quantity.Size(512), 364 Size: quantity.Size(12345670 * 512), 365 Structure: []gadget.OnDiskStructure{ 366 { 367 LaidOutStructure: gadget.LaidOutStructure{ 368 VolumeStructure: &gadget.VolumeStructure{ 369 Size: 2457600 * 512, 370 Label: "ubuntu-seed", 371 Type: "0C", 372 Filesystem: "vfat", 373 }, 374 StartOffset: 4096 * 512, 375 Index: 1, 376 }, 377 Node: "/dev/node1", 378 }, 379 { 380 LaidOutStructure: gadget.LaidOutStructure{ 381 VolumeStructure: &gadget.VolumeStructure{ 382 Size: 1048576 * 512, 383 Label: "ubuntu-boot", 384 Type: "0D", 385 Filesystem: "vfat", 386 }, 387 StartOffset: (4096 + 2457600) * 512, 388 Index: 2, 389 }, 390 Node: "/dev/node2", 391 }, 392 { 393 LaidOutStructure: gadget.LaidOutStructure{ 394 VolumeStructure: &gadget.VolumeStructure{ 395 Size: 1048576 * 512, 396 Label: "ubuntu-save", 397 Type: "0D", 398 Filesystem: "ext4", 399 }, 400 StartOffset: (4096 + 2457600 + 1048576) * 512, 401 Index: 3, 402 }, 403 Node: "/dev/node3", 404 }, 405 { 406 LaidOutStructure: gadget.LaidOutStructure{ 407 VolumeStructure: &gadget.VolumeStructure{ 408 Size: 1048576 * 512, 409 Label: "ubuntu-data", 410 Type: "0D", 411 Filesystem: "ext4", 412 }, 413 StartOffset: (4096 + 2457600 + 1048576 + 1048576) * 512, 414 Index: 4, 415 }, 416 Node: "/dev/node4", 417 }, 418 }, 419 }) 420 } 421 422 func (s *ondiskTestSuite) TestDeviceInfoMBR4096SectorSize(c *C) { 423 const mockSfdiskWithMBR = ` 424 >&2 echo "Some warning from sfdisk" 425 echo '{ 426 "partitiontable": { 427 "label": "dos", 428 "device": "/dev/node", 429 "unit": "sectors", 430 "partitions": [ 431 {"node": "/dev/node1", "start":256, "size":2560, "type": "c"}, 432 {"node": "/dev/node2", "start":2816, "size":2560, "type": "d"}, 433 {"node": "/dev/node3", "start":5376, "size":128000, "type": "d"}, 434 {"node": "/dev/node4", "start":133376, "size":6202079, "type": "d"} 435 ] 436 } 437 }'` 438 const mockLsblkForMBR = ` 439 [ "$3" == "/dev/node1" ] && echo '{ 440 "blockdevices": [ {"name": "node1", "fstype": "vfat", "label": "ubuntu-seed", "uuid": "A644-B807", "mountpoint": null} ] 441 }' 442 [ "$3" == "/dev/node2" ] && echo '{ 443 "blockdevices": [ {"name": "node2", "fstype": "vfat", "label": "ubuntu-boot", "uuid": "A644-B808", "mountpoint": null} ] 444 }' 445 [ "$3" == "/dev/node3" ] && echo '{ 446 "blockdevices": [ {"name": "node3", "fstype": "ext4", "label": "ubuntu-save", "mountpoint": null} ] 447 }' 448 [ "$3" == "/dev/node4" ] && echo '{ 449 "blockdevices": [ {"name": "node3", "fstype": "ext4", "label": "ubuntu-data", "mountpoint": null} ] 450 }' 451 exit 0` 452 453 cmdSfdisk := testutil.MockCommand(c, "sfdisk", mockSfdiskWithMBR) 454 defer cmdSfdisk.Restore() 455 456 cmdLsblk := testutil.MockCommand(c, "lsblk", mockLsblkForMBR) 457 defer cmdLsblk.Restore() 458 459 cmdBlockdev := testutil.MockCommand(c, "blockdev", ` 460 if [ "$1" == --getss ]; then 461 # sector size 462 echo 4096 463 exit 0 464 elif [ "$1" == --getsz ]; then 465 # disk size in 512-byte sectors 466 echo 50683904 467 exit 0 468 fi 469 echo "unexpected cmdline opts: $*" 470 exit 1 471 `) 472 defer cmdBlockdev.Restore() 473 474 dl, err := gadget.OnDiskVolumeFromDevice("/dev/node") 475 c.Assert(err, IsNil) 476 c.Assert(cmdSfdisk.Calls(), DeepEquals, [][]string{ 477 {"sfdisk", "--json", "/dev/node"}, 478 }) 479 c.Assert(cmdLsblk.Calls(), DeepEquals, [][]string{ 480 {"lsblk", "--fs", "--json", "/dev/node1"}, 481 {"lsblk", "--fs", "--json", "/dev/node2"}, 482 {"lsblk", "--fs", "--json", "/dev/node3"}, 483 {"lsblk", "--fs", "--json", "/dev/node4"}, 484 }) 485 c.Assert(cmdBlockdev.Calls(), DeepEquals, [][]string{ 486 {"blockdev", "--getss", "/dev/node"}, 487 {"blockdev", "--getsz", "/dev/node"}, 488 }) 489 c.Assert(err, IsNil) 490 491 c.Assert(dl, DeepEquals, &gadget.OnDiskVolume{ 492 Device: "/dev/node", 493 Schema: "dos", 494 SectorSize: quantity.Size(4096), 495 Size: quantity.Size(6335488 * 4096), 496 Structure: []gadget.OnDiskStructure{ 497 { 498 LaidOutStructure: gadget.LaidOutStructure{ 499 VolumeStructure: &gadget.VolumeStructure{ 500 Size: 2560 * 4096, 501 Label: "ubuntu-seed", 502 Type: "0C", 503 Filesystem: "vfat", 504 }, 505 StartOffset: 256 * 4096, 506 Index: 1, 507 }, 508 Node: "/dev/node1", 509 }, 510 { 511 LaidOutStructure: gadget.LaidOutStructure{ 512 VolumeStructure: &gadget.VolumeStructure{ 513 Size: 2560 * 4096, 514 Label: "ubuntu-boot", 515 Type: "0D", 516 Filesystem: "vfat", 517 }, 518 StartOffset: (256 + 2560) * 4096, 519 Index: 2, 520 }, 521 Node: "/dev/node2", 522 }, 523 { 524 LaidOutStructure: gadget.LaidOutStructure{ 525 VolumeStructure: &gadget.VolumeStructure{ 526 Size: 128000 * 4096, 527 Label: "ubuntu-save", 528 Type: "0D", 529 Filesystem: "ext4", 530 }, 531 StartOffset: (256 + 2560 + 2560) * 4096, 532 Index: 3, 533 }, 534 Node: "/dev/node3", 535 }, 536 { 537 LaidOutStructure: gadget.LaidOutStructure{ 538 VolumeStructure: &gadget.VolumeStructure{ 539 Size: 6202079 * 4096, 540 Label: "ubuntu-data", 541 Type: "0D", 542 Filesystem: "ext4", 543 }, 544 StartOffset: (256 + 2560 + 2560 + 128000) * 4096, 545 Index: 4, 546 }, 547 Node: "/dev/node4", 548 }, 549 }, 550 }) 551 } 552 553 func (s *ondiskTestSuite) TestDeviceInfoNotSectors(c *C) { 554 cmdSfdisk := testutil.MockCommand(c, "sfdisk", `echo '{ 555 "partitiontable": { 556 "label": "gpt", 557 "id": "9151F25B-CDF0-48F1-9EDE-68CBD616E2CA", 558 "device": "/dev/node", 559 "unit": "not_sectors", 560 "firstlba": 34, 561 "lastlba": 8388574, 562 "partitions": [ 563 {"node": "/dev/node1", "start": 2048, "size": 2048, "type": "21686148-6449-6E6F-744E-656564454649", "uuid": "2E59D969-52AB-430B-88AC-F83873519F6F", "name": "BIOS Boot"} 564 ] 565 } 566 }'`) 567 defer cmdSfdisk.Restore() 568 569 _, err := gadget.OnDiskVolumeFromDevice("/dev/node") 570 c.Assert(err, ErrorMatches, "cannot position partitions: unknown unit .*") 571 } 572 573 func (s *ondiskTestSuite) TestDeviceInfoSectorSizeNotMultiple512Unhappy(c *C) { 574 cmdSfdisk := testutil.MockCommand(c, "sfdisk", `echo '{ 575 "partitiontable": { 576 "label": "gpt", 577 "id": "9151F25B-CDF0-48F1-9EDE-68CBD616E2CA", 578 "device": "/dev/node", 579 "unit": "sectors", 580 "firstlba": 34, 581 "lastlba": 8388574, 582 "partitions": [ 583 {"node": "/dev/node1", "start": 2048, "size": 2048, "type": "21686148-6449-6E6F-744E-656564454649", "uuid": "2E59D969-52AB-430B-88AC-F83873519F6F", "name": "BIOS Boot"} 584 ] 585 } 586 }'`) 587 defer cmdSfdisk.Restore() 588 589 cmdBlockdev := testutil.MockCommand(c, "blockdev", ` 590 if [ "$1" == --getss ]; then 591 # sector size 592 echo 513 593 exit 0 594 fi 595 echo "unexpected cmdline opts: $*" 596 exit 1 597 `) 598 defer cmdBlockdev.Restore() 599 600 _, err := gadget.OnDiskVolumeFromDevice("/dev/node") 601 c.Assert(err, ErrorMatches, `cannot calculate structure size: sector size \(513\) is not a multiple of 512`) 602 603 c.Assert(cmdSfdisk.Calls(), DeepEquals, [][]string{ 604 {"sfdisk", "--json", "/dev/node"}, 605 }) 606 607 c.Assert(cmdBlockdev.Calls(), DeepEquals, [][]string{ 608 {"blockdev", "--getss", "/dev/node"}, 609 }) 610 611 } 612 613 func (s *ondiskTestSuite) TestDeviceInfoFilesystemInfoError(c *C) { 614 cmdSfdisk := testutil.MockCommand(c, "sfdisk", `echo '{ 615 "partitiontable": { 616 "label": "gpt", 617 "id": "9151F25B-CDF0-48F1-9EDE-68CBD616E2CA", 618 "device": "/dev/node", 619 "unit": "sectors", 620 "firstlba": 34, 621 "lastlba": 8388574, 622 "partitions": [ 623 {"node": "/dev/node1", "start": 2048, "size": 2048, "type": "21686148-6449-6E6F-744E-656564454649", "uuid": "2E59D969-52AB-430B-88AC-F83873519F6F", "name": "BIOS Boot"} 624 ] 625 } 626 }'`) 627 defer cmdSfdisk.Restore() 628 629 cmdBlockdev := testutil.MockCommand(c, "blockdev", ` 630 if [ "$1" == --getss ]; then 631 # sector size 632 echo 512 633 exit 0 634 fi 635 echo "unexpected cmdline opts: $*" 636 exit 1 637 `) 638 defer cmdBlockdev.Restore() 639 640 cmdLsblk := testutil.MockCommand(c, "lsblk", "echo lsblk error; exit 1") 641 defer cmdLsblk.Restore() 642 643 _, err := gadget.OnDiskVolumeFromDevice("/dev/node") 644 c.Assert(err, ErrorMatches, "cannot obtain filesystem information: lsblk error") 645 646 c.Assert(cmdSfdisk.Calls(), DeepEquals, [][]string{ 647 {"sfdisk", "--json", "/dev/node"}, 648 }) 649 650 c.Assert(cmdBlockdev.Calls(), DeepEquals, [][]string{ 651 {"blockdev", "--getss", "/dev/node"}, 652 }) 653 654 c.Assert(cmdLsblk.Calls(), DeepEquals, [][]string{ 655 {"lsblk", "--fs", "--json", "/dev/node1"}, 656 }) 657 } 658 659 func (s *ondiskTestSuite) TestDeviceInfoJsonError(c *C) { 660 cmd := testutil.MockCommand(c, "sfdisk", `echo 'This is not a json'`) 661 defer cmd.Restore() 662 663 dl, err := gadget.OnDiskVolumeFromDevice("/dev/node") 664 c.Assert(err, ErrorMatches, "cannot parse sfdisk output: invalid .*") 665 c.Assert(dl, IsNil) 666 } 667 668 func (s *ondiskTestSuite) TestDeviceInfoError(c *C) { 669 cmd := testutil.MockCommand(c, "sfdisk", "echo 'sfdisk: not found'; exit 127") 670 defer cmd.Restore() 671 672 dl, err := gadget.OnDiskVolumeFromDevice("/dev/node") 673 c.Assert(err, ErrorMatches, "sfdisk: not found") 674 c.Assert(dl, IsNil) 675 } 676 677 func (s *ondiskTestSuite) TestUpdatePartitionList(c *C) { 678 const mockSfdiskScriptBios = ` 679 >&2 echo "Some warning from sfdisk" 680 echo '{ 681 "partitiontable": { 682 "label": "gpt", 683 "id": "9151F25B-CDF0-48F1-9EDE-68CBD616E2CA", 684 "device": "/dev/node", 685 "unit": "sectors", 686 "firstlba": 34, 687 "lastlba": 8388574, 688 "partitions": [ 689 { 690 "node": "/dev/node1", 691 "start": 2048, 692 "size": 2048, 693 "type": "21686148-6449-6E6F-744E-656564454649", 694 "uuid": "2E59D969-52AB-430B-88AC-F83873519F6F", 695 "name": "BIOS Boot" 696 } 697 ] 698 } 699 }'` 700 701 const mockLsblkScriptBios = ` 702 [ "$3" == "/dev/node1" ] && echo '{ 703 "blockdevices": [ {"name": "node1", "fstype": null, "label": null, "uuid": null, "mountpoint": null} ] 704 }' 705 exit 0` 706 707 // sector size is same for all calls 708 cmdBlockdev := testutil.MockCommand(c, "blockdev", ` 709 if [ "$1" == --getss ]; then 710 # sector size 711 echo 512 712 exit 0 713 fi 714 echo "unexpected cmdline opts: $*" 715 exit 1 716 `) 717 defer cmdBlockdev.Restore() 718 719 // start with a single partition 720 cmdSfdisk := testutil.MockCommand(c, "sfdisk", mockSfdiskScriptBios) 721 defer cmdSfdisk.Restore() 722 723 cmdLsblk := testutil.MockCommand(c, "lsblk", mockLsblkScriptBios) 724 defer cmdLsblk.Restore() 725 726 dl, err := gadget.OnDiskVolumeFromDevice("/dev/node") 727 c.Assert(err, IsNil) 728 729 c.Assert(cmdSfdisk.Calls(), DeepEquals, [][]string{ 730 {"sfdisk", "--json", "/dev/node"}, 731 }) 732 733 c.Assert(cmdLsblk.Calls(), DeepEquals, [][]string{ 734 {"lsblk", "--fs", "--json", "/dev/node1"}, 735 }) 736 737 c.Assert(len(dl.Structure), Equals, 1) 738 c.Assert(dl.Structure[0].Node, Equals, "/dev/node1") 739 740 // add a partition 741 cmdSfdisk = testutil.MockCommand(c, "sfdisk", mockSfdiskScriptBiosSeed) 742 defer cmdSfdisk.Restore() 743 744 cmdLsblk = testutil.MockCommand(c, "lsblk", mockLsblkScriptBiosSeed) 745 defer cmdLsblk.Restore() 746 747 // update the partition list 748 err = gadget.UpdatePartitionList(dl) 749 c.Assert(err, IsNil) 750 751 c.Assert(cmdBlockdev.Calls(), DeepEquals, [][]string{ 752 {"blockdev", "--getss", "/dev/node"}, 753 {"blockdev", "--getss", "/dev/node"}, 754 }) 755 756 c.Assert(cmdSfdisk.Calls(), DeepEquals, [][]string{ 757 {"sfdisk", "--json", "/dev/node"}, 758 }) 759 760 c.Assert(cmdLsblk.Calls(), DeepEquals, [][]string{ 761 {"lsblk", "--fs", "--json", "/dev/node1"}, 762 {"lsblk", "--fs", "--json", "/dev/node2"}, 763 }) 764 765 // check if the partition list was updated 766 c.Assert(len(dl.Structure), Equals, 2) 767 c.Assert(dl.Structure[0].Node, Equals, "/dev/node1") 768 c.Assert(dl.Structure[1].Node, Equals, "/dev/node2") 769 } 770 771 func (s *ondiskTestSuite) TestFilesystemInfo(c *C) { 772 cmd := testutil.MockCommand(c, "lsblk", `echo '{ 773 "blockdevices": [ 774 {"name": "loop8p2", "fstype": "vfat", "label": "ubuntu-seed", "uuid": "C1F4-CE43", "mountpoint": null} 775 ] 776 }'`) 777 defer cmd.Restore() 778 779 info, err := gadget.FilesystemInfo("/dev/node") 780 c.Assert(cmd.Calls(), DeepEquals, [][]string{ 781 {"lsblk", "--fs", "--json", "/dev/node"}, 782 }) 783 c.Assert(err, IsNil) 784 c.Assert(len(info.BlockDevices), Equals, 1) 785 bd := info.BlockDevices[0] 786 c.Assert(bd.Name, Equals, "loop8p2") 787 c.Assert(bd.FSType, Equals, "vfat") 788 c.Assert(bd.Label, Equals, "ubuntu-seed") 789 c.Assert(bd.UUID, Equals, "C1F4-CE43") 790 } 791 792 func (s *ondiskTestSuite) TestFilesystemInfoJsonError(c *C) { 793 cmd := testutil.MockCommand(c, "lsblk", `echo 'This is not a json'`) 794 defer cmd.Restore() 795 796 info, err := gadget.FilesystemInfo("/dev/node") 797 c.Assert(err, ErrorMatches, "cannot parse lsblk output: invalid .*") 798 c.Assert(info, IsNil) 799 } 800 801 func (s *ondiskTestSuite) TestFilesystemInfoError(c *C) { 802 cmd := testutil.MockCommand(c, "lsblk", "echo 'lsblk: not found'; exit 127") 803 defer cmd.Restore() 804 805 info, err := gadget.FilesystemInfo("/dev/node") 806 c.Assert(err, ErrorMatches, "lsblk: not found") 807 c.Assert(info, IsNil) 808 }