Skip to content

Commit

Permalink
minor: allow passing custom assets to start SB protected CM4
Browse files Browse the repository at this point in the history
  • Loading branch information
aethernet committed Jun 6, 2024
1 parent fa41831 commit 8cc4ce1
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 67 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
build
*~
node_modules
yalc.lock
.yalc
34 changes: 18 additions & 16 deletions examples/scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,49 +13,51 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { platform } from 'os';
import { platform } from "os";

import { scanner } from '../lib/';
import { scanner } from "../lib/";

async function main() {
const bootImageFolder = String(process.argv.slice(2));

async function main(usbBootExtraFolder?: string) {
const adapters: scanner.adapters.Adapter[] = [
new scanner.adapters.BlockDeviceAdapter({
includeSystemDrives: () => true,
}),
new scanner.adapters.UsbbootDeviceAdapter(),
new scanner.adapters.UsbbootDeviceAdapter(bootImageFolder),
];
if (platform() === 'win32') {
if (platform() === "win32") {
if (scanner.adapters.DriverlessDeviceAdapter !== undefined) {
adapters.push(new scanner.adapters.DriverlessDeviceAdapter());
}
}
const deviceScanner = new scanner.Scanner(adapters);
deviceScanner.on(
'attach',
"attach",
async (drive: scanner.adapters.AdapterSourceDestination) => {
console.log('attach', drive);
console.log("attach", drive);
if (drive.emitsProgress) {
drive.on('progress', (progress: number) => {
console.log(drive, progress, '%');
drive.on("progress", (progress: number) => {
console.log(drive, progress, "%");
});
}
},
);
deviceScanner.on(
'detach',
"detach",
(drive: scanner.adapters.AdapterSourceDestination) => {
console.log('detach', drive);
console.log("detach", drive);
},
);
deviceScanner.on('error', (error: Error) => {
console.log('error', error);
deviceScanner.on("error", (error: Error) => {
console.log("error", error);
});
await deviceScanner.start();
const d = deviceScanner.getBy(
'devicePath',
'pci-0000:00:14.0-usb-0:2:1.0-scsi-0:0:0:0',
"devicePath",
"pci-0000:00:14.0-usb-0:2:1.0-scsi-0:0:0:0",
);
console.log('ready', d);
console.log("ready", d);
}

void main();
96 changes: 72 additions & 24 deletions examples/usbboot.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright 2019 balena.io
* Copyright 2024 balena.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -13,82 +14,129 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { argv } from 'process';
import ProgressBar = require('progress');

import { scanner, sourceDestination } from '../lib/';
/**
* Unlocking with secureboot
*
* If you need to unlock an cm4 with secureboot, you need to provide a signed boot-image.
* Pass the bootImageFolder flag with the path to the folder containing the signed boot-image.
*/

import ProgressBar = require("progress");

import { scanner, sourceDestination } from "../lib/";

import { pipeSourceToDestinationsWithProgressBar } from "./utils";

// Parse command line arguments
const args = process.argv.slice(2); // removes 'node' and the script name from the args
const flags: any = {};

args.forEach((arg: string, index: number) => {
// Check if the argument is a flag in the format --flag=value
if (arg.startsWith("--")) {
const key: string = arg.substring(2);
const value: string = args[index + 1];
flags[key] = value;
}
});

if (!flags.source) {
console.log("No source has been provided, won't try to flash anything");
}

import { pipeSourceToDestinationsWithProgressBar } from './utils';
if (flags.bootImageFolder !== "") {
console.log(`Using external folder ${flags["bootImageFolder"]}`);
}

if (flags.help) {
console.log(
"Usage: ts-node usbboot.js --bootImageFolder <bootImageFolder> --source <image>",
);
console.log(
"Beware, `source` image will be flashed to all USBboot devices, so make sure you know what you are doing",
);
console.log(
"To unlock a secureboot CM4, set the bootImageFodler to the folder containing a signed boot-image and config.txt",
);
process.exit(0);
}

async function main() {
const bootImageFolder = flags.bootImageFolder;
const adapters: scanner.adapters.Adapter[] = [
new scanner.adapters.BlockDeviceAdapter({
includeSystemDrives: () => false,
}),
new scanner.adapters.UsbbootDeviceAdapter(),
new scanner.adapters.UsbbootDeviceAdapter(bootImageFolder),
];
const deviceScanner = new scanner.Scanner(adapters);
console.log('Waiting for one compute module');
console.log("Waiting for one compute module");
// Wait for one compute module to be plugged
const computeModule: sourceDestination.UsbbootDrive = await new Promise(
(resolve, reject) => {
function onAttach(drive: scanner.adapters.AdapterSourceDestination) {
if (drive instanceof sourceDestination.UsbbootDrive) {
deviceScanner.removeListener('attach', onAttach);
deviceScanner.removeListener("attach", onAttach);
resolve(drive);
}
}
deviceScanner.on('attach', onAttach);
deviceScanner.on('error', reject);
deviceScanner.on("attach", onAttach);
deviceScanner.on("error", reject);
void deviceScanner.start();
},
);
console.log('Compute module attached');
const progressBar = new ProgressBar('converting to block device [:bar]', {
console.log("Compute module attached");
const progressBar = new ProgressBar("converting to block device [:bar]", {
total: 100,
width: 40,
});
function onProgress(progress: number) {
const delta = Math.floor(progress) - progressBar.curr;
progressBar.tick(delta, {});
}
computeModule.on('progress', onProgress);
computeModule.on("progress", onProgress);
// Wait until it is converted to a block device
await new Promise<void>((resolve, reject) => {
function onDetach(drive: scanner.adapters.AdapterSourceDestination) {
if (drive === computeModule) {
deviceScanner.removeListener('detach', onDetach);
deviceScanner.removeListener("detach", onDetach);
resolve();
}
}
deviceScanner.on('detach', onDetach);
deviceScanner.on('error', reject);
deviceScanner.on("detach", onDetach);
deviceScanner.on("error", reject);
});
progressBar.terminate();
computeModule.removeListener('progress', onProgress);
console.log('Waiting for compute module to reattach as a block device');
computeModule.removeListener("progress", onProgress);

console.log("Waiting for compute module to reattach as a block device");

const dest = await new Promise(
(resolve: (drive: sourceDestination.BlockDevice) => void, reject) => {
function onAttach(drive: scanner.adapters.AdapterSourceDestination) {
if (
drive instanceof sourceDestination.BlockDevice &&
drive.description === 'Compute Module'
drive.description === "Compute Module"
) {
drive.oWrite = true;
drive.oDirect = true;
resolve(drive);
deviceScanner.removeListener('attach', onAttach);
deviceScanner.removeListener("attach", onAttach);
}
}
deviceScanner.on('attach', onAttach);
deviceScanner.on('error', reject);
deviceScanner.on("attach", onAttach);
deviceScanner.on("error", reject);
},
);
deviceScanner.stop();

if (argv.length >= 3) {
console.log(`Writing image ${argv[2]}`);
if (flags.source) {
console.log(JSON.stringify(dest));
console.log(`Writing image ${flags.source} to ${dest.path}`);
const source: sourceDestination.SourceDestination =
new sourceDestination.File({
path: argv[2],
path: flags.source,
});
void pipeSourceToDestinationsWithProgressBar({
source,
Expand Down
28 changes: 14 additions & 14 deletions lib/scanner/adapters/usbboot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,28 @@
import {
UsbbootDevice,
UsbbootScanner as UsbbootScannerType,
} from 'node-raspberrypi-usbboot';
} from "node-raspberrypi-usbboot";

import { getRaspberrypiUsbboot } from '../../lazy';
import { UsbbootDrive } from '../../source-destination/usbboot';
import { Adapter } from './adapter';
import { getRaspberrypiUsbboot } from "../../lazy";
import { UsbbootDrive } from "../../source-destination/usbboot";
import { Adapter } from "./adapter";

export class UsbbootDeviceAdapter extends Adapter {
private drives: Map<UsbbootDevice, UsbbootDrive> = new Map();
private scanner?: UsbbootScannerType;

constructor() {
constructor(usbBootExtraFolder?: string | undefined) {
super();
const rpiUsbboot = getRaspberrypiUsbboot();
if (rpiUsbboot !== undefined) {
this.scanner = new rpiUsbboot.UsbbootScanner();
this.scanner.on('attach', this.onAttach.bind(this));
this.scanner.on('detach', this.onDetach.bind(this));
this.scanner.on('ready', this.emit.bind(this, 'ready'));
this.scanner.on('error', this.emit.bind(this, 'error'));
this.scanner = new rpiUsbboot.UsbbootScanner(usbBootExtraFolder);
this.scanner.on("attach", this.onAttach.bind(this));
this.scanner.on("detach", this.onDetach.bind(this));
this.scanner.on("ready", this.emit.bind(this, "ready"));
this.scanner.on("error", this.emit.bind(this, "error"));
} else {
console.warn('node-raspberrypi-usbboot not available');
setImmediate(this.emit.bind(this, 'ready'));
console.warn("node-raspberrypi-usbboot not available");
setImmediate(this.emit.bind(this, "ready"));
}
}

Expand All @@ -56,12 +56,12 @@ export class UsbbootDeviceAdapter extends Adapter {
drive = new UsbbootDrive(device);
this.drives.set(device, drive);
}
this.emit('attach', drive);
this.emit("attach", drive);
}

private onDetach(device: UsbbootDevice): void {
const drive = this.drives.get(device);
this.drives.delete(device);
this.emit('detach', drive);
this.emit("detach", drive);
}
}
27 changes: 15 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"lzma-native": "^8.0.6",
"minimatch": "^9.0.3",
"mountutils": "^1.3.20",
"node-raspberrypi-usbboot": "1.0.7",
"node-raspberrypi-usbboot": "1.1.0-build-aethernet-allow-custom-sb-assets-2605716d9cad91cee838ca28dba6d94103fe2e31-1",
"outdent": "^0.8.0",
"partitioninfo": "^6.0.2",
"rwmutex": "^1.0.0",
Expand Down

0 comments on commit 8cc4ce1

Please sign in to comment.