Some checks failed
CI / markdown-lint (push) Failing after 14s
- Reorganized directory structure following open source best practices - Created src/ directory for all source code components - Moved build artifacts to build/ subdirectories - Organized documentation into phases/, guides/, and api/ subdirectories - Moved third-party code to vendor/ directory - Moved downloads to downloads/ directory - Updated all build scripts to reference new directory structure - Created comprehensive PROJECT_STRUCTURE.md documentation - Added DEVELOPMENT_GUIDE.md as main entry point - Improved separation of concerns and maintainability - Follows standard open source project conventions
27 KiB
27 KiB
Phase 6: Packaging & Updates System
🎯 Objectives
Develop a robust packaging and update system that provides secure, reliable system updates and application management for the BlackBerry Classic (Q20).
📋 Detailed Tasks
6.1 System Packaging Architecture
6.1.1 Root Filesystem Design
System Partition Layout:
# Partition structure
/dev/mmcblk0p1 - Bootloader (2MB)
/dev/mmcblk0p2 - Boot partition (32MB)
/dev/mmcblk0p3 - System A (1GB)
/dev/mmcblk0p4 - System B (1GB)
/dev/mmcblk0p5 - User data (12GB)
/dev/mmcblk0p6 - Recovery (256MB)
/dev/mmcblk0p7 - Cache (512MB)
System Components:
# System directory structure
/
├── bin/ # Essential binaries
├── boot/ # Boot files and kernel
├── dev/ # Device files
├── etc/ # Configuration files
├── home/ # User home directories
├── lib/ # Shared libraries
├── media/ # Mount points
├── mnt/ # Temporary mounts
├── opt/ # Optional applications
├── proc/ # Process information
├── root/ # Root user home
├── run/ # Runtime data
├── sbin/ # System binaries
├── srv/ # Service data
├── sys/ # System information
├── tmp/ # Temporary files
├── usr/ # User programs and data
└── var/ # Variable data
System Package Structure:
# Package format
package-name-version.tar.xz
├── metadata.json # Package metadata
├── filesystem.tar.xz # System files
├── kernel.tar.xz # Kernel and modules
├── device-tree.dtb # Device tree blob
└── scripts/ # Installation scripts
├── pre-install.sh
├── post-install.sh
├── pre-remove.sh
└── post-remove.sh
6.1.2 Package Management System
Package Manager Design:
// Package manager structure
struct q20_package_manager {
struct device *dev;
// Package database
struct q20_package_db *db;
struct q20_package_cache *cache;
// Installation state
struct q20_installation_state *install_state;
struct workqueue_struct *workqueue;
// Package operations
int (*install_package)(struct q20_package_manager *pm, const char *package_path);
int (*remove_package)(struct q20_package_manager *pm, const char *package_name);
int (*update_package)(struct q20_package_manager *pm, const char *package_name);
int (*list_packages)(struct q20_package_manager *pm, struct list_head *packages);
// Update management
int (*check_updates)(struct q20_package_manager *pm);
int (*download_update)(struct q20_package_manager *pm, const char *update_url);
int (*install_update)(struct q20_package_manager *pm, const char *update_path);
};
// Package structure
struct q20_package {
struct list_head list;
char name[64];
char version[32];
char description[256];
char maintainer[64];
char license[32];
// Dependencies
struct list_head dependencies;
struct list_head conflicts;
struct list_head provides;
// Files
struct list_head files;
size_t installed_size;
size_t download_size;
// Metadata
time_t install_time;
time_t build_time;
char build_host[64];
char architecture[16];
// State
enum package_state state;
bool installed;
bool essential;
};
// Package database
struct q20_package_db {
struct device *dev;
sqlite3 *db;
char *db_path;
// Database operations
int (*add_package)(struct q20_package_db *db, struct q20_package *pkg);
int (*remove_package)(struct q20_package_db *db, const char *name);
int (*get_package)(struct q20_package_db *db, const char *name, struct q20_package *pkg);
int (*list_packages)(struct q20_package_db *db, struct list_head *packages);
int (*update_package)(struct q20_package_db *db, struct q20_package *pkg);
};
Package Installation Process:
// Package installation
static int q20_package_install(struct q20_package_manager *pm, const char *package_path)
{
struct q20_package *pkg;
struct q20_package *existing_pkg;
int ret;
// Load package metadata
ret = q20_package_load_metadata(package_path, &pkg);
if (ret)
return ret;
// Check if package is already installed
existing_pkg = q20_package_db_get_package(pm->db, pkg->name);
if (existing_pkg) {
// Check if update is needed
if (q20_package_version_compare(pkg->version, existing_pkg->version) <= 0) {
dev_info(pm->dev, "Package %s is already up to date\n", pkg->name);
q20_package_free(pkg);
return 0;
}
// Remove old package
ret = q20_package_remove_internal(pm, existing_pkg);
if (ret)
goto install_failed;
}
// Check dependencies
ret = q20_package_check_dependencies(pm, pkg);
if (ret)
goto install_failed;
// Run pre-install script
ret = q20_package_run_script(pkg, "pre-install.sh");
if (ret)
goto install_failed;
// Extract filesystem
ret = q20_package_extract_filesystem(pkg, package_path);
if (ret)
goto install_failed;
// Install kernel if needed
if (q20_package_has_kernel(pkg)) {
ret = q20_package_install_kernel(pkg);
if (ret)
goto install_failed;
}
// Install device tree if needed
if (q20_package_has_device_tree(pkg)) {
ret = q20_package_install_device_tree(pkg);
if (ret)
goto install_failed;
}
// Add to package database
ret = q20_package_db_add_package(pm->db, pkg);
if (ret)
goto install_failed;
// Run post-install script
ret = q20_package_run_script(pkg, "post-install.sh");
if (ret)
goto install_failed;
pkg->installed = true;
pkg->install_time = current_kernel_time().tv_sec;
dev_info(pm->dev, "Package %s installed successfully\n", pkg->name);
return 0;
install_failed:
// Cleanup on failure
q20_package_cleanup_failed_install(pkg);
q20_package_free(pkg);
return ret;
}
6.2 Update System
6.2.1 OSTree Integration
OSTree System Design:
// OSTree system structure
struct q20_ostree_system {
struct device *dev;
// OSTree repository
struct ostree_repo *repo;
char *repo_path;
// Boot management
struct ostree_boot_manager *boot_mgr;
char *boot_path;
// Deployment management
struct list_head deployments;
struct q20_ostree_deployment *current_deployment;
struct q20_ostree_deployment *pending_deployment;
// Update operations
int (*pull_updates)(struct q20_ostree_system *ostree, const char *remote_url);
int (*deploy_update)(struct q20_ostree_system *ostree, const char *commit_hash);
int (*rollback)(struct q20_ostree_system *ostree);
int (*cleanup)(struct q20_ostree_system *ostree);
};
// OSTree deployment
struct q20_ostree_deployment {
struct list_head list;
char *commit_hash;
char *version;
char *description;
// Deployment state
enum deployment_state state;
bool booted;
bool pending;
// File system
char *root_path;
char *boot_path;
// Metadata
time_t deploy_time;
time_t boot_time;
int boot_count;
};
// OSTree operations
static int q20_ostree_pull_updates(struct q20_ostree_system *ostree, const char *remote_url)
{
OstreeRepo *repo = ostree->repo;
OstreeAsyncProgress *progress;
GCancellable *cancellable;
char *refspec;
int ret;
// Create progress tracker
progress = ostree_async_progress_new();
cancellable = g_cancellable_new();
// Construct refspec
refspec = g_strdup_printf("q20:q20/%s", ostree->current_deployment->version);
// Pull updates from remote
ret = ostree_repo_pull_with_options(repo, remote_url, refspec, NULL, progress, cancellable, NULL);
if (ret) {
dev_err(ostree->dev, "Failed to pull updates: %s\n", g_strerror(ret));
goto pull_failed;
}
// Check for new commits
ret = q20_ostree_check_new_commits(ostree);
if (ret)
goto pull_failed;
dev_info(ostree->dev, "Updates pulled successfully\n");
pull_failed:
g_free(refspec);
g_object_unref(progress);
g_object_unref(cancellable);
return ret;
}
static int q20_ostree_deploy_update(struct q20_ostree_system *ostree, const char *commit_hash)
{
OstreeRepo *repo = ostree->repo;
OstreeDeployment *deployment;
char *deployment_path;
int ret;
// Create new deployment
ret = ostree_repo_prepare_transaction(repo, NULL, NULL);
if (ret)
return ret;
// Deploy new commit
ret = ostree_repo_write_delta_super(repo, commit_hash, NULL, NULL, NULL);
if (ret)
goto deploy_failed;
// Commit transaction
ret = ostree_repo_commit_transaction(repo, NULL, NULL);
if (ret)
goto deploy_failed;
// Create deployment
deployment = q20_ostree_create_deployment(ostree, commit_hash);
if (!deployment) {
ret = -ENOMEM;
goto deploy_failed;
}
// Set as pending
deployment->state = DEPLOYMENT_STATE_PENDING;
deployment->pending = true;
ostree->pending_deployment = deployment;
// Update bootloader
ret = q20_ostree_update_bootloader(ostree, deployment);
if (ret)
goto deploy_failed;
dev_info(ostree->dev, "Update deployed successfully\n");
return 0;
deploy_failed:
ostree_repo_abort_transaction(repo, NULL);
return ret;
}
6.2.2 Delta Updates
Delta Update System:
// Delta update structure
struct q20_delta_update {
struct device *dev;
// Delta information
char *from_version;
char *to_version;
char *delta_path;
// Delta operations
struct list_head operations;
size_t total_size;
size_t compressed_size;
// Progress tracking
struct q20_delta_progress *progress;
struct work_struct apply_work;
};
// Delta operation types
enum delta_operation_type {
DELTA_OP_COPY, // Copy file from base
DELTA_OP_ADD, // Add new file
DELTA_OP_DELETE, // Delete file
DELTA_OP_PATCH, // Apply binary patch
DELTA_OP_SYMLINK, // Create symlink
DELTA_OP_CHMOD, // Change permissions
};
// Delta operation
struct q20_delta_operation {
struct list_head list;
enum delta_operation_type type;
// File information
char *source_path;
char *target_path;
mode_t permissions;
// Patch data
void *patch_data;
size_t patch_size;
// Progress
size_t bytes_processed;
bool completed;
};
// Delta update application
static int q20_delta_apply_update(struct q20_delta_update *delta)
{
struct q20_delta_operation *op;
int ret;
// Initialize progress tracking
delta->progress = q20_delta_progress_create(delta);
if (!delta->progress)
return -ENOMEM;
// Process each operation
list_for_each_entry(op, &delta->operations, list) {
ret = q20_delta_apply_operation(delta, op);
if (ret) {
dev_err(delta->dev, "Failed to apply operation: %d\n", ret);
goto apply_failed;
}
// Update progress
q20_delta_progress_update(delta->progress, op);
}
// Verify update
ret = q20_delta_verify_update(delta);
if (ret)
goto apply_failed;
dev_info(delta->dev, "Delta update applied successfully\n");
return 0;
apply_failed:
// Rollback on failure
q20_delta_rollback(delta);
return ret;
}
static int q20_delta_apply_operation(struct q20_delta_update *delta,
struct q20_delta_operation *op)
{
int ret;
switch (op->type) {
case DELTA_OP_COPY:
ret = q20_delta_copy_file(op->source_path, op->target_path);
break;
case DELTA_OP_ADD:
ret = q20_delta_add_file(op->target_path, op->patch_data, op->patch_size);
break;
case DELTA_OP_DELETE:
ret = q20_delta_delete_file(op->target_path);
break;
case DELTA_OP_PATCH:
ret = q20_delta_patch_file(op->source_path, op->target_path,
op->patch_data, op->patch_size);
break;
case DELTA_OP_SYMLINK:
ret = q20_delta_create_symlink(op->source_path, op->target_path);
break;
case DELTA_OP_CHMOD:
ret = q20_delta_change_permissions(op->target_path, op->permissions);
break;
default:
ret = -EINVAL;
break;
}
if (ret == 0) {
op->completed = true;
}
return ret;
}
6.3 Application Sandboxing
6.3.1 Flatpak Integration
Flatpak System Design:
// Flatpak system structure
struct q20_flatpak_system {
struct device *dev;
// Flatpak installation
struct flatpak_installation *installation;
char *installation_path;
// Application management
struct list_head applications;
struct q20_flatpak_app *current_app;
// Runtime management
struct list_head runtimes;
struct q20_flatpak_runtime *default_runtime;
// Operations
int (*install_app)(struct q20_flatpak_system *fp, const char *app_id);
int (*remove_app)(struct q20_flatpak_system *fp, const char *app_id);
int (*update_app)(struct q20_flatpak_system *fp, const char *app_id);
int (*launch_app)(struct q20_flatpak_system *fp, const char *app_id);
};
// Flatpak application
struct q20_flatpak_app {
struct list_head list;
char *app_id;
char *name;
char *description;
char *version;
// Application metadata
char *icon_path;
char *desktop_file;
char *executable;
// Sandbox configuration
struct q20_flatpak_sandbox *sandbox;
struct q20_flatpak_permissions *permissions;
// State
bool installed;
bool running;
pid_t process_id;
};
// Flatpak sandbox
struct q20_flatpak_sandbox {
struct q20_flatpak_app *app;
// Namespace isolation
bool network_namespace;
bool pid_namespace;
bool mount_namespace;
bool uts_namespace;
bool ipc_namespace;
bool user_namespace;
// Resource limits
struct rlimit cpu_limit;
struct rlimit memory_limit;
struct rlimit disk_limit;
// Mount points
struct list_head mounts;
char *root_path;
char *data_path;
char *cache_path;
};
// Flatpak operations
static int q20_flatpak_install_app(struct q20_flatpak_system *fp, const char *app_id)
{
FlatpakInstallation *installation = fp->installation;
FlatpakRemote *remote;
GCancellable *cancellable;
int ret;
// Get default remote
remote = flatpak_installation_get_default_remote(installation, cancellable, NULL);
if (!remote) {
ret = -ENOENT;
goto install_failed;
}
// Install application
ret = flatpak_installation_install(installation, remote->name, app_id, NULL,
cancellable, NULL);
if (ret) {
dev_err(fp->dev, "Failed to install app %s: %s\n", app_id, g_strerror(ret));
goto install_failed;
}
// Create application structure
ret = q20_flatpak_create_app(fp, app_id);
if (ret)
goto install_failed;
dev_info(fp->dev, "App %s installed successfully\n", app_id);
return 0;
install_failed:
return ret;
}
static int q20_flatpak_launch_app(struct q20_flatpak_system *fp, const char *app_id)
{
struct q20_flatpak_app *app;
struct q20_flatpak_sandbox *sandbox;
pid_t pid;
int ret;
// Find application
app = q20_flatpak_find_app(fp, app_id);
if (!app) {
ret = -ENOENT;
goto launch_failed;
}
// Create sandbox
sandbox = q20_flatpak_create_sandbox(app);
if (!sandbox) {
ret = -ENOMEM;
goto launch_failed;
}
// Setup sandbox
ret = q20_flatpak_setup_sandbox(sandbox);
if (ret)
goto launch_failed;
// Launch application
pid = q20_flatpak_fork_and_exec(app, sandbox);
if (pid < 0) {
ret = pid;
goto launch_failed;
}
app->running = true;
app->process_id = pid;
dev_info(fp->dev, "App %s launched with PID %d\n", app_id, pid);
return 0;
launch_failed:
return ret;
}
6.3.2 Container Security
Security Implementation:
// Security manager
struct q20_security_manager {
struct device *dev;
// Security policies
struct q20_security_policy *default_policy;
struct list_head app_policies;
// Capability management
struct q20_capability_set *allowed_capabilities;
struct q20_capability_set *denied_capabilities;
// SELinux integration
struct q20_selinux_context *selinux_ctx;
// Operations
int (*apply_policy)(struct q20_security_manager *sm, struct q20_flatpak_app *app);
int (*check_permission)(struct q20_security_manager *sm, const char *permission);
int (*audit_event)(struct q20_security_manager *sm, const char *event);
};
// Security policy
struct q20_security_policy {
struct list_head list;
char *app_id;
// Permissions
struct q20_permission_set *permissions;
struct q20_permission_set *denied_permissions;
// Network access
bool allow_network;
char **allowed_hosts;
int num_allowed_hosts;
// File system access
struct q20_fs_permission *fs_permissions;
int num_fs_permissions;
// Device access
struct q20_device_permission *device_permissions;
int num_device_permissions;
};
// Security operations
static int q20_security_apply_policy(struct q20_security_manager *sm,
struct q20_flatpak_app *app)
{
struct q20_security_policy *policy;
int ret;
// Find app-specific policy
policy = q20_security_find_policy(sm, app->app_id);
if (!policy) {
policy = sm->default_policy;
}
// Apply capability restrictions
ret = q20_security_apply_capabilities(sm, app, policy);
if (ret)
return ret;
// Apply SELinux context
ret = q20_security_apply_selinux(sm, app, policy);
if (ret)
return ret;
// Apply network restrictions
ret = q20_security_apply_network(sm, app, policy);
if (ret)
return ret;
// Apply file system restrictions
ret = q20_security_apply_filesystem(sm, app, policy);
if (ret)
return ret;
// Apply device restrictions
ret = q20_security_apply_devices(sm, app, policy);
if (ret)
return ret;
return 0;
}
static int q20_security_check_permission(struct q20_security_manager *sm,
const char *permission)
{
struct q20_security_policy *policy;
struct q20_flatpak_app *app;
// Get current app context
app = q20_flatpak_get_current_app();
if (!app)
return -EACCES;
// Find app policy
policy = q20_security_find_policy(sm, app->app_id);
if (!policy) {
policy = sm->default_policy;
}
// Check if permission is denied
if (q20_permission_set_contains(policy->denied_permissions, permission)) {
q20_security_audit_event(sm, "permission_denied");
return -EACCES;
}
// Check if permission is allowed
if (q20_permission_set_contains(policy->permissions, permission)) {
return 0;
}
// Check default policy
if (q20_permission_set_contains(sm->default_policy->permissions, permission)) {
return 0;
}
q20_security_audit_event(sm, "permission_denied");
return -EACCES;
}
6.4 Secure Boot
6.4.1 Boot Verification
Secure Boot Implementation:
// Secure boot manager
struct q20_secure_boot {
struct device *dev;
// Key management
struct q20_key_store *key_store;
struct q20_public_key *platform_key;
struct q20_public_key *db_key;
struct q20_public_key *dbx_key;
// Verification state
bool secure_boot_enabled;
bool verification_enabled;
enum boot_verification_level verification_level;
// Operations
int (*verify_kernel)(struct q20_secure_boot *sb, const char *kernel_path);
int (*verify_initramfs)(struct q20_secure_boot *sb, const char *initramfs_path);
int (*verify_module)(struct q20_secure_boot *sb, const char *module_path);
int (*enroll_key)(struct q20_secure_boot *sb, struct q20_public_key *key);
int (*revoke_key)(struct q20_secure_boot *sb, struct q20_public_key *key);
};
// Key store
struct q20_key_store {
struct device *dev;
// Key storage
struct list_head keys;
char *key_store_path;
// Key operations
int (*add_key)(struct q20_key_store *ks, struct q20_public_key *key);
int (*remove_key)(struct q20_key_store *ks, const char *key_id);
int (*find_key)(struct q20_key_store *ks, const char *key_id, struct q20_public_key **key);
int (*list_keys)(struct q20_key_store *ks, struct list_head *keys);
};
// Public key
struct q20_public_key {
struct list_head list;
char *key_id;
char *key_name;
enum key_type type;
// Key data
void *key_data;
size_t key_size;
enum key_algorithm algorithm;
// Metadata
time_t creation_time;
time_t expiration_time;
bool revoked;
};
// Secure boot operations
static int q20_secure_boot_verify_kernel(struct q20_secure_boot *sb, const char *kernel_path)
{
struct q20_signature *signature;
struct q20_public_key *key;
void *kernel_data;
size_t kernel_size;
int ret;
// Load kernel
ret = q20_file_load(kernel_path, &kernel_data, &kernel_size);
if (ret)
return ret;
// Extract signature
ret = q20_signature_extract(kernel_data, kernel_size, &signature);
if (ret)
goto verify_failed;
// Find signing key
ret = q20_key_store_find_key(sb->key_store, signature->key_id, &key);
if (ret)
goto verify_failed;
// Verify signature
ret = q20_signature_verify(kernel_data, kernel_size, signature, key);
if (ret)
goto verify_failed;
// Check key revocation
if (key->revoked) {
ret = -EKEYREVOKED;
goto verify_failed;
}
// Check key expiration
if (key->expiration_time && key->expiration_time < current_kernel_time().tv_sec) {
ret = -EKEYEXPIRED;
goto verify_failed;
}
dev_info(sb->dev, "Kernel verification successful\n");
ret = 0;
verify_failed:
kfree(kernel_data);
q20_signature_free(signature);
return ret;
}
static int q20_secure_boot_enroll_key(struct q20_secure_boot *sb, struct q20_public_key *key)
{
int ret;
// Validate key
ret = q20_public_key_validate(key);
if (ret)
return ret;
// Add to key store
ret = q20_key_store_add_key(sb->key_store, key);
if (ret)
return ret;
// Update secure boot database
ret = q20_secure_boot_update_db(sb, key);
if (ret)
goto enroll_failed;
dev_info(sb->dev, "Key %s enrolled successfully\n", key->key_name);
return 0;
enroll_failed:
q20_key_store_remove_key(sb->key_store, key->key_id);
return ret;
}
6.4.2 Bootloader Integration
Bootloader Security:
// Bootloader security
struct q20_bootloader_security {
struct device *dev;
// Bootloader state
bool secure_boot_enabled;
bool fastboot_unlocked;
bool oem_unlocked;
// Verification
struct q20_verification_chain *verification_chain;
struct q20_boot_policy *boot_policy;
// Operations
int (*verify_boot_image)(struct q20_bootloader_security *bs, const char *image_path);
int (*lock_bootloader)(struct q20_bootloader_security *bs);
int (*unlock_bootloader)(struct q20_bootloader_security *bs);
int (*set_boot_policy)(struct q20_bootloader_security *bs, struct q20_boot_policy *policy);
};
// Boot policy
struct q20_boot_policy {
char *policy_name;
// Verification settings
bool verify_kernel;
bool verify_initramfs;
bool verify_device_tree;
bool verify_modules;
// Boot options
bool allow_unsigned_kernels;
bool allow_custom_kernels;
bool require_secure_boot;
// Recovery options
bool allow_recovery_boot;
bool allow_fastboot;
bool allow_adb;
};
// Bootloader operations
static int q20_bootloader_verify_boot_image(struct q20_bootloader_security *bs,
const char *image_path)
{
struct q20_boot_image *boot_image;
struct q20_signature *signature;
int ret;
// Load boot image
ret = q20_boot_image_load(image_path, &boot_image);
if (ret)
return ret;
// Verify kernel if required
if (bs->boot_policy->verify_kernel) {
ret = q20_secure_boot_verify_kernel(bs->secure_boot, boot_image->kernel_data);
if (ret)
goto verify_failed;
}
// Verify initramfs if required
if (bs->boot_policy->verify_initramfs) {
ret = q20_secure_boot_verify_initramfs(bs->secure_boot, boot_image->initramfs_data);
if (ret)
goto verify_failed;
}
// Verify device tree if required
if (bs->boot_policy->verify_device_tree) {
ret = q20_secure_boot_verify_device_tree(bs->secure_boot, boot_image->dtb_data);
if (ret)
goto verify_failed;
}
dev_info(bs->dev, "Boot image verification successful\n");
ret = 0;
verify_failed:
q20_boot_image_free(boot_image);
return ret;
}
📊 Deliverables
6.5 Complete Packaging System
Requirements:
- Functional package manager
- OSTree update system
- Flatpak application sandboxing
- Secure boot implementation
- Update delivery system
6.6 Update Infrastructure
Components:
- Update server
- Delta update system
- Rollback mechanism
- Update verification
- Distribution system
6.7 Security Framework
Features:
- Application sandboxing
- Permission management
- Secure boot chain
- Key management
- Audit logging
⏱️ Timeline
Week 1-2: System packaging architecture Week 3-4: OSTree update system Week 5-6: Delta updates Week 7-8: Flatpak integration Week 9-10: Security framework Week 11-12: Testing and deployment
Total Duration: 12 weeks (3 months)
🎯 Success Criteria
Phase 6 is successful when:
- Complete packaging system is functional
- Update system is reliable and secure
- Application sandboxing is working
- Secure boot is implemented
- Update delivery is automated
🚨 Risk Mitigation
High-Risk Scenarios:
- Update system failures → Implement robust rollback mechanisms
- Security vulnerabilities → Comprehensive security auditing
- Package conflicts → Dependency resolution and conflict detection
- Boot failures → Multiple boot paths and recovery options
- Storage corruption → Data integrity checks and backup systems