Some checks failed
CI / markdown-lint (push) Failing after 14s
- Updated .gitignore with comprehensive exclusions for build artifacts, IDE files, and OS-specific files - Created BlackBerry-inspired website with Heroicons and Gitea integration - Added complete project structure with all 7 phases implemented - Included kernel drivers, UI components, telephony stack, and packaging tools - Added emulation scripts for testing and development - Comprehensive documentation for all development phases - Security analysis and hardware testing guides - SDK and application framework for third-party development
460 lines
15 KiB
C
460 lines
15 KiB
C
/*
|
|
* BBeOS System Image Builder
|
|
* BlackBerry Classic Q20 System Image Creation
|
|
*
|
|
* This tool creates a complete flashable system image
|
|
* including kernel, rootfs, and all components.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <zlib.h>
|
|
|
|
#define BBEOS_VERSION "1.0.0"
|
|
#define BBEOS_BUILD_DATE __DATE__
|
|
#define BBEOS_BUILD_TIME __TIME__
|
|
|
|
/* Partition layout for Q20 */
|
|
#define PARTITION_BOOT 0
|
|
#define PARTITION_SYSTEM 1
|
|
#define PARTITION_DATA 2
|
|
#define PARTITION_CACHE 3
|
|
#define PARTITION_RECOVERY 4
|
|
|
|
#define BOOT_PARTITION_SIZE (16 * 1024 * 1024) /* 16MB */
|
|
#define SYSTEM_PARTITION_SIZE (512 * 1024 * 1024) /* 512MB */
|
|
#define DATA_PARTITION_SIZE (8 * 1024 * 1024 * 1024) /* 8GB */
|
|
#define CACHE_PARTITION_SIZE (256 * 1024 * 1024) /* 256MB */
|
|
#define RECOVERY_PARTITION_SIZE (32 * 1024 * 1024) /* 32MB */
|
|
|
|
/* Image header structure */
|
|
struct bbeos_image_header {
|
|
char magic[8]; /* "BBEOSIMG" */
|
|
u32 version; /* Version number */
|
|
u32 header_size; /* Size of this header */
|
|
u32 total_size; /* Total image size */
|
|
u32 checksum; /* CRC32 checksum */
|
|
u32 partition_count; /* Number of partitions */
|
|
u64 build_timestamp; /* Build timestamp */
|
|
char build_info[64]; /* Build information */
|
|
char reserved[256]; /* Reserved for future use */
|
|
} __attribute__((packed));
|
|
|
|
/* Partition header structure */
|
|
struct bbeos_partition_header {
|
|
char name[32]; /* Partition name */
|
|
u32 type; /* Partition type */
|
|
u64 offset; /* Offset in image */
|
|
u64 size; /* Partition size */
|
|
u32 flags; /* Partition flags */
|
|
u32 checksum; /* Partition CRC32 */
|
|
char reserved[64]; /* Reserved for future use */
|
|
} __attribute__((packed));
|
|
|
|
/* Partition information */
|
|
struct partition_info {
|
|
const char *name;
|
|
const char *source_path;
|
|
u64 size;
|
|
u32 flags;
|
|
bool required;
|
|
};
|
|
|
|
static struct partition_info partitions[] = {
|
|
{"boot", "boot.img", BOOT_PARTITION_SIZE, 0x01, true},
|
|
{"system", "system.img", SYSTEM_PARTITION_SIZE, 0x02, true},
|
|
{"data", "data.img", DATA_PARTITION_SIZE, 0x04, false},
|
|
{"cache", "cache.img", CACHE_PARTITION_SIZE, 0x08, false},
|
|
{"recovery", "recovery.img", RECOVERY_PARTITION_SIZE, 0x10, false},
|
|
};
|
|
|
|
/* CRC32 calculation */
|
|
static u32 calculate_crc32(const void *data, size_t size) {
|
|
u32 crc = crc32(0L, Z_NULL, 0);
|
|
return crc32(crc, (const Bytef *)data, size);
|
|
}
|
|
|
|
/* File operations */
|
|
static int copy_file(const char *src_path, const char *dst_path) {
|
|
FILE *src, *dst;
|
|
char buffer[4096];
|
|
size_t bytes_read;
|
|
|
|
src = fopen(src_path, "rb");
|
|
if (!src) {
|
|
fprintf(stderr, "Error: Cannot open source file %s: %s\n", src_path, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
dst = fopen(dst_path, "wb");
|
|
if (!dst) {
|
|
fprintf(stderr, "Error: Cannot create destination file %s: %s\n", dst_path, strerror(errno));
|
|
fclose(src);
|
|
return -1;
|
|
}
|
|
|
|
while ((bytes_read = fread(buffer, 1, sizeof(buffer), src)) > 0) {
|
|
if (fwrite(buffer, 1, bytes_read, dst) != bytes_read) {
|
|
fprintf(stderr, "Error: Write failed to %s\n", dst_path);
|
|
fclose(src);
|
|
fclose(dst);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
fclose(src);
|
|
fclose(dst);
|
|
return 0;
|
|
}
|
|
|
|
static u64 get_file_size(const char *path) {
|
|
struct stat st;
|
|
if (stat(path, &st) == 0) {
|
|
return st.st_size;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Create boot image */
|
|
static int create_boot_image(const char *output_path) {
|
|
FILE *boot_img;
|
|
struct bbeos_image_header header;
|
|
u32 crc;
|
|
|
|
printf("Creating boot image...\n");
|
|
|
|
boot_img = fopen(output_path, "wb");
|
|
if (!boot_img) {
|
|
fprintf(stderr, "Error: Cannot create boot image %s\n", output_path);
|
|
return -1;
|
|
}
|
|
|
|
/* Initialize header */
|
|
memset(&header, 0, sizeof(header));
|
|
strcpy(header.magic, "BBEOSIMG");
|
|
header.version = 0x010000; /* Version 1.0.0 */
|
|
header.header_size = sizeof(header);
|
|
header.total_size = BOOT_PARTITION_SIZE;
|
|
header.partition_count = 1;
|
|
header.build_timestamp = time(NULL);
|
|
snprintf(header.build_info, sizeof(header.build_info),
|
|
"BBeOS %s built on %s at %s", BBEOS_VERSION, BBEOS_BUILD_DATE, BBEOS_BUILD_TIME);
|
|
|
|
/* Calculate header checksum */
|
|
header.checksum = calculate_crc32(&header, sizeof(header) - sizeof(header.checksum));
|
|
|
|
/* Write header */
|
|
fwrite(&header, sizeof(header), 1, boot_img);
|
|
|
|
/* Add kernel and initramfs */
|
|
if (access("kernel-source/arch/arm/boot/zImage", F_OK) == 0) {
|
|
printf("Adding kernel (zImage)...\n");
|
|
copy_file("kernel-source/arch/arm/boot/zImage", "temp_kernel");
|
|
copy_file("temp_kernel", output_path);
|
|
unlink("temp_kernel");
|
|
}
|
|
|
|
if (access("initramfs.img", F_OK) == 0) {
|
|
printf("Adding initramfs...\n");
|
|
copy_file("initramfs.img", "temp_initramfs");
|
|
copy_file("temp_initramfs", output_path);
|
|
unlink("temp_initramfs");
|
|
}
|
|
|
|
/* Pad to partition size */
|
|
u64 current_size = get_file_size(output_path);
|
|
if (current_size < BOOT_PARTITION_SIZE) {
|
|
char padding[4096] = {0};
|
|
u64 remaining = BOOT_PARTITION_SIZE - current_size;
|
|
|
|
while (remaining > 0) {
|
|
u64 to_write = (remaining > sizeof(padding)) ? sizeof(padding) : remaining;
|
|
fwrite(padding, 1, to_write, boot_img);
|
|
remaining -= to_write;
|
|
}
|
|
}
|
|
|
|
fclose(boot_img);
|
|
printf("Boot image created: %s\n", output_path);
|
|
return 0;
|
|
}
|
|
|
|
/* Create system image */
|
|
static int create_system_image(const char *output_path) {
|
|
FILE *system_img;
|
|
struct bbeos_image_header header;
|
|
|
|
printf("Creating system image...\n");
|
|
|
|
system_img = fopen(output_path, "wb");
|
|
if (!system_img) {
|
|
fprintf(stderr, "Error: Cannot create system image %s\n", output_path);
|
|
return -1;
|
|
}
|
|
|
|
/* Initialize header */
|
|
memset(&header, 0, sizeof(header));
|
|
strcpy(header.magic, "BBEOSIMG");
|
|
header.version = 0x010000;
|
|
header.header_size = sizeof(header);
|
|
header.total_size = SYSTEM_PARTITION_SIZE;
|
|
header.partition_count = 1;
|
|
header.build_timestamp = time(NULL);
|
|
snprintf(header.build_info, sizeof(header.build_info),
|
|
"BBeOS %s system image", BBEOS_VERSION);
|
|
|
|
/* Calculate header checksum */
|
|
header.checksum = calculate_crc32(&header, sizeof(header) - sizeof(header.checksum));
|
|
|
|
/* Write header */
|
|
fwrite(&header, sizeof(header), 1, system_img);
|
|
|
|
/* Create rootfs structure */
|
|
printf("Creating rootfs structure...\n");
|
|
|
|
/* Add basic directory structure */
|
|
const char *dirs[] = {
|
|
"bin", "sbin", "usr/bin", "usr/sbin", "usr/lib", "usr/share",
|
|
"etc", "var", "tmp", "proc", "sys", "dev", "mnt", "media",
|
|
"lib", "lib64", "home", "root", "data", "cache"
|
|
};
|
|
|
|
for (int i = 0; i < sizeof(dirs) / sizeof(dirs[0]); i++) {
|
|
char cmd[256];
|
|
snprintf(cmd, sizeof(cmd), "mkdir -p rootfs/%s", dirs[i]);
|
|
system(cmd);
|
|
}
|
|
|
|
/* Copy essential files */
|
|
if (access("rootfs", F_OK) == 0) {
|
|
printf("Copying rootfs files...\n");
|
|
system("cp -r rootfs/* temp_rootfs/ 2>/dev/null || true");
|
|
}
|
|
|
|
/* Add BusyBox if available */
|
|
if (access("busybox", F_OK) == 0) {
|
|
printf("Adding BusyBox...\n");
|
|
system("cp busybox temp_rootfs/bin/");
|
|
system("chmod +x temp_rootfs/bin/busybox");
|
|
system("cd temp_rootfs/bin && ln -sf busybox sh");
|
|
system("cd temp_rootfs/bin && ln -sf busybox ls");
|
|
system("cd temp_rootfs/bin && ln -sf busybox cp");
|
|
system("cd temp_rootfs/bin && ln -sf busybox mv");
|
|
system("cd temp_rootfs/bin && ln -sf busybox rm");
|
|
system("cd temp_rootfs/bin && ln -sf busybox mkdir");
|
|
system("cd temp_rootfs/bin && ln -sf busybox mount");
|
|
system("cd temp_rootfs/bin && ln -sf busybox umount");
|
|
}
|
|
|
|
/* Create basic init script */
|
|
FILE *init_script = fopen("temp_rootfs/init", "w");
|
|
if (init_script) {
|
|
fprintf(init_script, "#!/bin/sh\n");
|
|
fprintf(init_script, "# BBeOS Init Script\n");
|
|
fprintf(init_script, "echo 'BBeOS starting...'\n");
|
|
fprintf(init_script, "mount -t proc none /proc\n");
|
|
fprintf(init_script, "mount -t sysfs none /sys\n");
|
|
fprintf(init_script, "mount -t tmpfs none /tmp\n");
|
|
fprintf(init_script, "echo 'BBeOS ready!'\n");
|
|
fprintf(init_script, "exec /bin/sh\n");
|
|
fclose(init_script);
|
|
system("chmod +x temp_rootfs/init");
|
|
}
|
|
|
|
/* Create fstab */
|
|
FILE *fstab = fopen("temp_rootfs/etc/fstab", "w");
|
|
if (fstab) {
|
|
fprintf(fstab, "# BBeOS Filesystem Table\n");
|
|
fprintf(fstab, "proc /proc proc defaults 0 0\n");
|
|
fprintf(fstab, "sysfs /sys sysfs defaults 0 0\n");
|
|
fprintf(fstab, "tmpfs /tmp tmpfs defaults 0 0\n");
|
|
fprintf(fstab, "devpts /dev/pts devpts defaults 0 0\n");
|
|
fclose(fstab);
|
|
}
|
|
|
|
/* Create passwd */
|
|
FILE *passwd = fopen("temp_rootfs/etc/passwd", "w");
|
|
if (passwd) {
|
|
fprintf(passwd, "root:x:0:0:root:/root:/bin/sh\n");
|
|
fprintf(passwd, "user:x:1000:1000:user:/home/user:/bin/sh\n");
|
|
fclose(passwd);
|
|
}
|
|
|
|
/* Create group */
|
|
FILE *group = fopen("temp_rootfs/etc/group", "w");
|
|
if (group) {
|
|
fprintf(group, "root:x:0:\n");
|
|
fprintf(group, "user:x:1000:\n");
|
|
fclose(group);
|
|
}
|
|
|
|
/* Archive rootfs */
|
|
printf("Archiving rootfs...\n");
|
|
system("cd temp_rootfs && tar -czf ../rootfs.tar.gz .");
|
|
|
|
/* Add to system image */
|
|
if (access("rootfs.tar.gz", F_OK) == 0) {
|
|
copy_file("rootfs.tar.gz", "temp_rootfs_archive");
|
|
copy_file("temp_rootfs_archive", output_path);
|
|
unlink("temp_rootfs_archive");
|
|
unlink("rootfs.tar.gz");
|
|
}
|
|
|
|
/* Pad to partition size */
|
|
u64 current_size = get_file_size(output_path);
|
|
if (current_size < SYSTEM_PARTITION_SIZE) {
|
|
char padding[4096] = {0};
|
|
u64 remaining = SYSTEM_PARTITION_SIZE - current_size;
|
|
|
|
while (remaining > 0) {
|
|
u64 to_write = (remaining > sizeof(padding)) ? sizeof(padding) : remaining;
|
|
fwrite(padding, 1, to_write, system_img);
|
|
remaining -= to_write;
|
|
}
|
|
}
|
|
|
|
fclose(system_img);
|
|
printf("System image created: %s\n", output_path);
|
|
return 0;
|
|
}
|
|
|
|
/* Create complete system image */
|
|
static int create_complete_image(const char *output_path) {
|
|
FILE *image_file;
|
|
struct bbeos_image_header header;
|
|
struct bbeos_partition_header part_header;
|
|
u64 current_offset = 0;
|
|
|
|
printf("Creating complete BBeOS system image...\n");
|
|
|
|
image_file = fopen(output_path, "wb");
|
|
if (!image_file) {
|
|
fprintf(stderr, "Error: Cannot create system image %s\n", output_path);
|
|
return -1;
|
|
}
|
|
|
|
/* Initialize main header */
|
|
memset(&header, 0, sizeof(header));
|
|
strcpy(header.magic, "BBEOSIMG");
|
|
header.version = 0x010000;
|
|
header.header_size = sizeof(header);
|
|
header.partition_count = sizeof(partitions) / sizeof(partitions[0]);
|
|
header.build_timestamp = time(NULL);
|
|
snprintf(header.build_info, sizeof(header.build_info),
|
|
"BBeOS %s complete system image", BBEOS_VERSION);
|
|
|
|
/* Calculate total size */
|
|
header.total_size = sizeof(header);
|
|
for (int i = 0; i < header.partition_count; i++) {
|
|
header.total_size += sizeof(part_header) + partitions[i].size;
|
|
}
|
|
|
|
/* Calculate header checksum */
|
|
header.checksum = calculate_crc32(&header, sizeof(header) - sizeof(header.checksum));
|
|
|
|
/* Write main header */
|
|
fwrite(&header, sizeof(header), 1, image_file);
|
|
current_offset += sizeof(header);
|
|
|
|
/* Process each partition */
|
|
for (int i = 0; i < header.partition_count; i++) {
|
|
printf("Processing partition %s...\n", partitions[i].name);
|
|
|
|
/* Initialize partition header */
|
|
memset(&part_header, 0, sizeof(part_header));
|
|
strncpy(part_header.name, partitions[i].name, sizeof(part_header.name) - 1);
|
|
part_header.type = i;
|
|
part_header.offset = current_offset + sizeof(part_header);
|
|
part_header.size = partitions[i].size;
|
|
part_header.flags = partitions[i].flags;
|
|
|
|
/* Write partition header */
|
|
fwrite(&part_header, sizeof(part_header), 1, image_file);
|
|
current_offset += sizeof(part_header);
|
|
|
|
/* Create partition content */
|
|
char part_file[256];
|
|
snprintf(part_file, sizeof(part_file), "%s.img", partitions[i].name);
|
|
|
|
if (strcmp(partitions[i].name, "boot") == 0) {
|
|
create_boot_image(part_file);
|
|
} else if (strcmp(partitions[i].name, "system") == 0) {
|
|
create_system_image(part_file);
|
|
} else {
|
|
/* Create empty partition */
|
|
FILE *empty_part = fopen(part_file, "wb");
|
|
if (empty_part) {
|
|
char padding[4096] = {0};
|
|
u64 remaining = partitions[i].size;
|
|
|
|
while (remaining > 0) {
|
|
u64 to_write = (remaining > sizeof(padding)) ? sizeof(padding) : remaining;
|
|
fwrite(padding, 1, to_write, empty_part);
|
|
remaining -= to_write;
|
|
}
|
|
fclose(empty_part);
|
|
}
|
|
}
|
|
|
|
/* Add partition content to main image */
|
|
if (access(part_file, F_OK) == 0) {
|
|
copy_file(part_file, "temp_partition");
|
|
copy_file("temp_partition", output_path);
|
|
unlink("temp_partition");
|
|
unlink(part_file);
|
|
}
|
|
|
|
current_offset += partitions[i].size;
|
|
}
|
|
|
|
fclose(image_file);
|
|
printf("Complete system image created: %s\n", output_path);
|
|
printf("Image size: %lu bytes\n", (unsigned long)get_file_size(output_path));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Main function */
|
|
int main(int argc, char *argv[]) {
|
|
const char *output_path = "bbeos-system.img";
|
|
|
|
printf("BBeOS System Image Builder\n");
|
|
printf("==========================\n");
|
|
printf("Version: %s\n", BBEOS_VERSION);
|
|
printf("Build Date: %s %s\n", BBEOS_BUILD_DATE, BBEOS_BUILD_TIME);
|
|
printf("\n");
|
|
|
|
/* Parse command line arguments */
|
|
if (argc > 1) {
|
|
output_path = argv[1];
|
|
}
|
|
|
|
/* Create temporary directories */
|
|
system("mkdir -p temp_rootfs");
|
|
|
|
/* Create complete system image */
|
|
int result = create_complete_image(output_path);
|
|
|
|
/* Cleanup */
|
|
system("rm -rf temp_rootfs");
|
|
|
|
if (result == 0) {
|
|
printf("\nBBeOS system image created successfully!\n");
|
|
printf("Output file: %s\n", output_path);
|
|
printf("\nTo flash to Q20 device:\n");
|
|
printf(" fastboot flash system %s\n", output_path);
|
|
printf(" fastboot reboot\n");
|
|
} else {
|
|
fprintf(stderr, "\nError: Failed to create system image\n");
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|