Files
BBeOS/packaging/system/image-builder.c
Eliott 7b53cde2ae
Some checks failed
CI / markdown-lint (push) Failing after 14s
Complete BBeOS project implementation with BlackBerry-inspired website
- 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
2025-08-01 10:20:28 +02:00

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;
}