Compare commits
15 Commits
feature/ad
...
fix/bugs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
063cbbd568 | ||
| e15e7f26d5 | |||
|
|
5dc7d88b7f | ||
|
|
cb9b464a99 | ||
| cc3bd2a3a5 | |||
|
|
9f0338740a | ||
|
|
ae8a44fe76 | ||
| 64985fa2d8 | |||
|
|
d8b3795b3e | ||
| 9157b3514a | |||
|
|
4ed8cdc792 | ||
|
|
23f5ff77ec | ||
|
|
ee7c2ba46b | ||
|
|
d0d239e0ca | ||
|
|
5fd53af017 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -36,3 +36,4 @@ hs_err_pid*
|
|||||||
.project
|
.project
|
||||||
.settings/
|
.settings/
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.claude/
|
||||||
|
|||||||
19
CONTRIBUTING.md
Normal file
19
CONTRIBUTING.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions from the community are welcome! To contribute:
|
||||||
|
|
||||||
|
1. Fork the repository.
|
||||||
|
2. Create a new branch for your feature or bug fix.
|
||||||
|
3. Make your changes with proper testing.
|
||||||
|
4. Submit a pull request detailing your modifications.
|
||||||
|
|
||||||
|
### Developer Documentation
|
||||||
|
|
||||||
|
Developer documentation is generated using JavaDoc. To generate and view the documentation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x generate_javadoc.sh
|
||||||
|
./generate_javadoc.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This will create a `docs/` folder with HTML documentation you can view in your browser.
|
||||||
35
PKGBUILD
Normal file
35
PKGBUILD
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Maintainer: Cametendo cameronmathis08@gmail.com
|
||||||
|
pkgname=cflash
|
||||||
|
pkgver=1.0.0
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc="Small and lightweight image and iso flasher build on dd."
|
||||||
|
arch=('any')
|
||||||
|
url="https://github.com/cametendo/cflash-git"
|
||||||
|
license=('MIT')
|
||||||
|
depends=('java-runtime>=21')
|
||||||
|
makedepends=('java-environment>=21' 'maven')
|
||||||
|
source=("cflash::git+https://github.com/cametendo/cflash-git.git")
|
||||||
|
sha256sums=('SKIP')
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cd "$pkgname"
|
||||||
|
# using 'package' because pom.xml triggers the assembly plugin during this phase
|
||||||
|
mvn clean package
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
cd "$srcdir/cflash"
|
||||||
|
|
||||||
|
# for some reason MAKEPKD won't accept my version, using the wildcard for literally anything if may find
|
||||||
|
install -Dm644 target/cflash-*-jar-with-dependencies.jar \
|
||||||
|
"$pkgdir/usr/share/java/cflash/cflash.jar"
|
||||||
|
|
||||||
|
# Create the executable
|
||||||
|
install -d "$pkgdir/usr/bin"
|
||||||
|
cat <<EOF > "$pkgdir/usr/bin/cflash"
|
||||||
|
#!/bin/sh
|
||||||
|
exec /usr/bin/java -jar /usr/share/java/cflash/cflash.jar "\$@"
|
||||||
|
EOF
|
||||||
|
# makes the program executable
|
||||||
|
chmod +x "$pkgdir/usr/bin/cflash"
|
||||||
|
}
|
||||||
103
README.md
103
README.md
@@ -1,18 +1,107 @@
|
|||||||
# cflash
|
# cflash
|
||||||
Small and lightweight image and iso flasher build on `dd`.
|
A small and lightweight wrapper for `dd` that strips away the complexity of CLI flashing.
|
||||||
|
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](https://opensource.org/licenses/MIT)
|
||||||
[](https://www.java.com/en/)
|
[](https://www.java.com/en/)
|
||||||
[](https://www.linux.org/)
|
[](https://www.linux.org/)
|
||||||
[](https://en.wikipedia.org/wiki/Software_release_life_cycle#Beta)
|
[](https://github.com/Cametendo/cflash-git/releases/tag/cflash-1.0.0)
|
||||||
|
|
||||||
# About
|
# About
|
||||||
Java program using `dd` to make flashing iso and image files easier on the terminal. This program allows anyone to flash iso and image files without having to search for extra GUI tools by keeping it simple and resource-friendly.
|
Small and lightweight wrapper written in Java for `dd` designed to simplify CLI flashing while protecting your hardware from accidental command-line errors. cflash replaces the syntax with a clear, safe interface, providing a reliable workflow for both newcomers and power users.
|
||||||
|
|
||||||
# Requirements
|
# Requirements
|
||||||
- `Java`: 21 (Download [here](https://www.oracle.com/java/technologies/downloads/#java21)
|
- `Java`: 21 (Download [here](https://www.oracle.com/java/technologies/downloads/#java21))
|
||||||
- `util-linux`: 2.41
|
- `util-linux`: 2.41
|
||||||
- `coreutils`: 9.10
|
- `coreutils`: 9.10
|
||||||
|
- `maven`: 3.9.15
|
||||||
|
- Operating System: Linux
|
||||||
|
### Building and Running Locally
|
||||||
|
|
||||||
|
1. Clone the repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/cametendo/cflash-git.git
|
||||||
|
cd cflash-git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Compile the code:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mvn clean package
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Run cflash:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
java -jar target/cflash-<version>.jar (optionally add arguments here, like with dd)
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Update cflash:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git pull
|
||||||
|
mvn clean package
|
||||||
|
```
|
||||||
|
|
||||||
|
### System-wide Installation
|
||||||
|
|
||||||
|
To install cflash globally so that it can be run from any terminal:
|
||||||
|
|
||||||
|
1. Clone the repository (if not done already):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/cametendo/cflash-git.git
|
||||||
|
cd cflash-git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Make the build and install scripts executable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x build.sh install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Build the project using the provided build script (requires root privileges):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Install globally (requires root privileges):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Run cflash from anywhere:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cflash
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Update cflash (reguires root privileges):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo cflash --update
|
||||||
|
```
|
||||||
|
|
||||||
|
**Notes:**
|
||||||
|
|
||||||
|
* The `build.sh` script compiles all Java source files and creates an executable `cflash.jar`.
|
||||||
|
* The `install.sh` script copies `cflash.jar` to `/usr/local/lib/cflash` and installs a wrapper script in `/usr/local/bin` for easy execution.
|
||||||
|
* If you use Arch Linux:
|
||||||
|
* You can directly install it with `yay` or `paru` via `yay -S cflash` / `paru -S cflash` or
|
||||||
|
* You can clone the repository from the [AUR](https://aur.archlinux.org/packages/cflash) and manually build it:
|
||||||
|
```bash
|
||||||
|
git clone https://aur.archlinux.org/cflash.git
|
||||||
|
cd cflash
|
||||||
|
makepkg -si
|
||||||
|
```
|
||||||
|
* You can update cflash using `yay` / `paru` via `yay -S cflash` / `paru -S cflash` or by rebuilding the package:
|
||||||
|
```bash
|
||||||
|
git clone https://aur.archlinux.org/cflash.git
|
||||||
|
cd cflash
|
||||||
|
makepkg -si
|
||||||
|
```
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
- Using the command `cflash` in the terminal, will start the flashing process. You will be asked several question before the flashing begins:
|
- Using the command `cflash` in the terminal, will start the flashing process. You will be asked several question before the flashing begins:
|
||||||
@@ -27,13 +116,13 @@ Java program using `dd` to make flashing iso and image files easier on the termi
|
|||||||
- **IMPORTANT**: Since dd needs sudo rights, ensure you have root priviliges.
|
- **IMPORTANT**: Since dd needs sudo rights, ensure you have root priviliges.
|
||||||
|
|
||||||
# Supported OS
|
# Supported OS
|
||||||
- Linux, MacOS, FreeBSD
|
- Linux
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
1. Clone the repository onto your local device.
|
1. Clone the repository onto your device and cd into it.
|
||||||
2. Run the `build.sh` file to build the program.
|
2. Run the `build.sh` file to build the program.
|
||||||
3. Run the `ìnstall.sh`to install the program.
|
3. Run the `ìnstall.sh`to install the program.
|
||||||
4. Open a terminal and use the program with `cflash`.
|
4. Open a terminal and use the program with `cflash`, optionally add all the arguments you need.
|
||||||
|
|
||||||
# License and Credits
|
# License and Credits
|
||||||
**Author**: [Cametendo](https://www.github.com/Cametendo)
|
**Author**: [Cametendo](https://www.github.com/Cametendo)
|
||||||
|
|||||||
86
build.sh
Executable file
86
build.sh
Executable file
@@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# --- Build script for cflash ---
|
||||||
|
# Compiles sources and bundles jline via Maven into a single fat JAR.
|
||||||
|
# If Maven is missing, prompts the user to install it using the detected package manager.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
JAR_FILE="cflash.jar"
|
||||||
|
|
||||||
|
# --- Detect package manager ---
|
||||||
|
detect_package_manager() {
|
||||||
|
if command -v pacman >/dev/null 2>&1; then
|
||||||
|
echo "pacman"
|
||||||
|
elif command -v apt >/dev/null 2>&1; then
|
||||||
|
echo "apt"
|
||||||
|
elif command -v dnf >/dev/null 2>&1; then
|
||||||
|
echo "dnf"
|
||||||
|
elif command -v yum >/dev/null 2>&1; then
|
||||||
|
echo "yum"
|
||||||
|
elif command -v zypper >/dev/null 2>&1; then
|
||||||
|
echo "zypper"
|
||||||
|
elif command -v brew >/dev/null 2>&1; then
|
||||||
|
echo "brew"
|
||||||
|
elif command -v apk >/dev/null 2>&1; then
|
||||||
|
echo "apk"
|
||||||
|
elif command -v emerge >/dev/null 2>&1; then
|
||||||
|
echo "emerge"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Generate Maven install command ---
|
||||||
|
maven_install_command() {
|
||||||
|
local pm="$1"
|
||||||
|
case "$pm" in
|
||||||
|
pacman) echo "pacman -Sy --noconfirm maven" ;;
|
||||||
|
apt) echo "apt update && apt install -y maven" ;;
|
||||||
|
dnf) echo "dnf install -y maven" ;;
|
||||||
|
yum) echo "yum install -y maven" ;;
|
||||||
|
zypper) echo "zypper install -y maven" ;;
|
||||||
|
brew) echo "brew install maven" ;;
|
||||||
|
apk) echo "apk add maven" ;;
|
||||||
|
emerge) echo "emerge dev-java/maven-bin" ;;
|
||||||
|
*) echo "" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Check for mvn ---
|
||||||
|
if ! command -v mvn >/dev/null 2>&1; then
|
||||||
|
echo "Maven (mvn) not found."
|
||||||
|
PM=$(detect_package_manager)
|
||||||
|
|
||||||
|
if [[ -z "$PM" ]]; then
|
||||||
|
echo "Please install Maven manually and rerun this script."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
CMD=$(maven_install_command "$PM")
|
||||||
|
if [[ $EUID -ne 0 && "$PM" != "brew" ]]; then
|
||||||
|
echo "Please run this script as root to install Maven, or install it manually."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -rp "Do you want to run the following command to install Maven? [$CMD] (y/n): " ANSWER
|
||||||
|
case "$ANSWER" in
|
||||||
|
y|Y)
|
||||||
|
echo "Installing Maven..."
|
||||||
|
eval "$CMD"
|
||||||
|
echo "Maven installed successfully."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Maven installation cancelled. Please install manually and rerun."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Build process ---
|
||||||
|
echo "Building cflash with Maven..."
|
||||||
|
mvn package -q
|
||||||
|
|
||||||
|
echo "Copying fat JAR to ${JAR_FILE}..."
|
||||||
|
cp target/cflash-*-jar-with-dependencies.jar "$JAR_FILE"
|
||||||
|
|
||||||
|
echo "Build completed successfully: ${JAR_FILE}"
|
||||||
84
cflash.sh
Executable file
84
cflash.sh
Executable file
@@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# cflash launcher with self-update via git + rebuild (requires sudo for update)
|
||||||
|
|
||||||
|
CFLASH_DIR="/usr/local/lib/cflash"
|
||||||
|
CFLASH_JAR="$CFLASH_DIR/cflash.jar"
|
||||||
|
GIT_REPO="https://gitea.cametendo.org/cametendo/cflash.git"
|
||||||
|
|
||||||
|
update_cflash() {
|
||||||
|
# Check for sudo/root
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
echo "cflash --update requires root privileges. Please run with sudo."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Updating cflash from repository..."
|
||||||
|
|
||||||
|
TMP_DIR=$(mktemp -d)
|
||||||
|
echo "Cloning repository into $TMP_DIR..."
|
||||||
|
|
||||||
|
if ! git clone --depth 1 "$GIT_REPO" "$TMP_DIR"; then
|
||||||
|
echo "Failed to clone repository."
|
||||||
|
rm -rf "$TMP_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
pushd "$TMP_DIR" >/dev/null
|
||||||
|
|
||||||
|
# Logic to handle if the repo contents are nested inside a 'cflash' folder
|
||||||
|
if [[ ! -f "./build.sh" && -d "cflash" ]]; then
|
||||||
|
echo "Detected nested directory, moving into cflash/..."
|
||||||
|
cd cflash
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure build.sh is executable (git usually preserves this, but just in case)
|
||||||
|
if [[ -f "./build.sh" ]]; then
|
||||||
|
chmod +x ./build.sh
|
||||||
|
echo "Building cflash..."
|
||||||
|
if ! ./build.sh; then
|
||||||
|
echo "Build failed."
|
||||||
|
popd >/dev/null
|
||||||
|
rm -rf "$TMP_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Error: build.sh not found in the repository root or cflash/ directory."
|
||||||
|
popd >/dev/null
|
||||||
|
rm -rf "$TMP_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Installing new version..."
|
||||||
|
if [[ -f "./install.sh" ]]; then
|
||||||
|
chmod +x ./install.sh
|
||||||
|
if ! ./install.sh; then
|
||||||
|
echo "Install failed."
|
||||||
|
popd >/dev/null
|
||||||
|
rm -rf "$TMP_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Error: install.sh not found."
|
||||||
|
popd >/dev/null
|
||||||
|
rm -rf "$TMP_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
popd >/dev/null
|
||||||
|
rm -rf "$TMP_DIR"
|
||||||
|
echo "Update completed successfully!"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle --update argument
|
||||||
|
if [[ "$1" == "--update" ]]; then
|
||||||
|
update_cflash
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run cflash normally
|
||||||
|
if [[ -f "$CFLASH_JAR" ]]; then
|
||||||
|
java --enable-native-access=ALL-UNNAMED -jar "$CFLASH_JAR" "$@"
|
||||||
|
else
|
||||||
|
echo "Error: $CFLASH_JAR not found. Please run 'sudo cflash --update' to install."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
139
generate_javadoc.sh
Executable file
139
generate_javadoc.sh
Executable file
@@ -0,0 +1,139 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# --- Generate JavaDoc for cflash ---
|
||||||
|
# This script generates developer documentation using javadoc.
|
||||||
|
# If JDK is missing, it prompts the user to install it using the detected package manager.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SRC_DIR="src/main/java"
|
||||||
|
DOC_DIR="docs"
|
||||||
|
|
||||||
|
# --- Detect package manager ---
|
||||||
|
detect_package_manager() {
|
||||||
|
if command -v pacman >/dev/null 2>&1; then
|
||||||
|
echo "pacman"
|
||||||
|
elif command -v apt >/dev/null 2>&1; then
|
||||||
|
echo "apt"
|
||||||
|
elif command -v dnf >/dev/null 2>&1; then
|
||||||
|
echo "dnf"
|
||||||
|
elif command -v yum >/dev/null 2>&1; then
|
||||||
|
echo "yum"
|
||||||
|
elif command -v zypper >/dev/null 2>&1; then
|
||||||
|
echo "zypper"
|
||||||
|
elif command -v brew >/dev/null 2>&1; then
|
||||||
|
echo "brew"
|
||||||
|
elif command -v apk >/dev/null 2>&1; then
|
||||||
|
echo "apk"
|
||||||
|
elif command -v emerge >/dev/null 2>&1; then
|
||||||
|
echo "emerge"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Generate JDK install command ---
|
||||||
|
jdk_install_command() {
|
||||||
|
local pm="$1"
|
||||||
|
case "$pm" in
|
||||||
|
pacman) echo "pacman -Sy --noconfirm jdk-openjdk" ;;
|
||||||
|
apt) echo "apt update && apt install -y openjdk-21-jdk || apt install -y default-jdk" ;;
|
||||||
|
dnf) echo "dnf install -y java-21-openjdk-devel || dnf install -y java-latest-openjdk-devel" ;;
|
||||||
|
yum) echo "yum install -y java-21-openjdk-devel || yum install -y java-latest-openjdk-devel" ;;
|
||||||
|
zypper) echo "zypper install -y java-21-openjdk-devel || zypper install -y java-latest-openjdk-devel" ;;
|
||||||
|
brew) echo "brew install openjdk" ;;
|
||||||
|
apk) echo "apk add openjdk21" ;;
|
||||||
|
emerge) echo "emerge dev-java/openjdk-bin" ;;
|
||||||
|
*) echo "" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Check for javadoc ---
|
||||||
|
if ! command -v javadoc >/dev/null 2>&1; then
|
||||||
|
echo "Java Development Kit (JDK) with javadoc not found."
|
||||||
|
PM=$(detect_package_manager)
|
||||||
|
|
||||||
|
if [[ -z "$PM" ]]; then
|
||||||
|
echo "Please install the latest JDK manually and rerun this script."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
CMD=$(jdk_install_command "$PM")
|
||||||
|
if [[ $EUID -ne 0 && "$PM" != "brew" ]]; then
|
||||||
|
echo "Please rerun this script with sudo if you want automatic JDK installation."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Prompt user
|
||||||
|
read -rp "Do you want to run the following command to install the JDK? [$CMD] (y/n): " ANSWER
|
||||||
|
case "$ANSWER" in
|
||||||
|
y|Y)
|
||||||
|
echo "Installing JDK..."
|
||||||
|
eval "$CMD"
|
||||||
|
echo "JDK installed successfully."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "JDK installation cancelled. Please install manually and rerun."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Check if source directory exists ---
|
||||||
|
if [[ ! -d "$SRC_DIR" ]]; then
|
||||||
|
echo -e "\033[31mSource directory '$SRC_DIR' not found!"
|
||||||
|
echo "Please ensure you're running this script from the project root directory."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Generate JavaDoc ---
|
||||||
|
echo "Generating JavaDoc for cflash..."
|
||||||
|
rm -rf "$DOC_DIR"
|
||||||
|
mkdir -p "$DOC_DIR"
|
||||||
|
|
||||||
|
# Check if Maven is available
|
||||||
|
if command -v mvn >/dev/null 2>&1; then
|
||||||
|
echo "Using Maven to generate JavaDoc with dependencies..."
|
||||||
|
if mvn javadoc:javadoc -Dquiet=true > /dev/null 2>&1; then
|
||||||
|
# Copy generated docs from Maven location to our docs directory
|
||||||
|
if [[ -d "target/reports/apidocs" ]]; then
|
||||||
|
cp -r target/reports/apidocs/* "$DOC_DIR/"
|
||||||
|
echo -e "\033[32mJavaDoc generated successfully using Maven!"
|
||||||
|
echo -e "\033[0m→ Open file://$PWD/$DOC_DIR/index.html to view it."
|
||||||
|
else
|
||||||
|
echo -e "\033[31mMaven generated docs but couldn't find them in target/reports/apidocs"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "\033[31mMaven JavaDoc generation failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Maven not found. Attempting to generate JavaDoc without dependencies..."
|
||||||
|
# Try to download JLine dependency manually
|
||||||
|
JLINE_JAR="$HOME/.m2/repository/org/jline/jline/3.25.1/jline-3.25.1.jar"
|
||||||
|
if [[ -f "$JLINE_JAR" ]]; then
|
||||||
|
echo "Found JLine dependency in Maven local repository..."
|
||||||
|
CLASSPATH="$SRC_DIR:$JLINE_JAR"
|
||||||
|
else
|
||||||
|
echo "JLine dependency not found. JavaDoc may have missing links."
|
||||||
|
CLASSPATH="$SRC_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if javadoc -quiet -d "$DOC_DIR" \
|
||||||
|
-sourcepath "$SRC_DIR" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
-subpackages org.cametendo \
|
||||||
|
-private \
|
||||||
|
-author \
|
||||||
|
-version \
|
||||||
|
-doctitle "cflash - Disk Image Flashing Utility" \
|
||||||
|
-windowtitle "cflash Documentation" \
|
||||||
|
-bottom "Copyright © 2026 Cametendo. All rights reserved." > /dev/null 2>&1; then
|
||||||
|
echo -e "\033[32mJavaDoc generated successfully!"
|
||||||
|
echo -e "\033[0m→ Open file://$PWD/$DOC_DIR/index.html to view it."
|
||||||
|
else
|
||||||
|
echo -e "\033[31mJavaDoc generation failed. Install Maven for better dependency handling."
|
||||||
|
echo "Run: apt install maven (Ubuntu/Debian) or pacman -S maven (Arch)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
16
install.sh
Executable file
16
install.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Install script for system-wide usage
|
||||||
|
|
||||||
|
# Ensure running as root
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
echo "Please run as root to install globally."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create installation directories
|
||||||
|
mkdir -p /usr/local/lib/cflash
|
||||||
|
cp cflash.jar /usr/local/lib/cflash/
|
||||||
|
cp cflash.sh /usr/local/bin/cflash
|
||||||
|
chmod +x /usr/local/bin/cflash
|
||||||
|
|
||||||
|
echo "cflash installed successfully! You can now run 'cflash' from anywhere."
|
||||||
32
pom.xml
32
pom.xml
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>org.cametendo</groupId>
|
<groupId>org.cametendo</groupId>
|
||||||
<artifactId>cflash</artifactId>
|
<artifactId>cflash</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0.1</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
@@ -22,4 +22,34 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>3.6.0</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>org.cametendo.Main</mainClass>
|
||||||
|
</manifest>
|
||||||
|
<manifestEntries>
|
||||||
|
<Enable-Native-Access>ALL-UNNAMED</Enable-Native-Access>
|
||||||
|
</manifestEntries>
|
||||||
|
</archive>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,38 +1,61 @@
|
|||||||
package org.cametendo;
|
package org.cametendo;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for managing block size configuration for disk flashing operations.
|
||||||
|
*
|
||||||
|
* <p>This class provides methods to both interactively prompt users for block size selection
|
||||||
|
* and to map command-line inputs to valid block size values. The default block size is 4M.</p>
|
||||||
|
*
|
||||||
|
* @author Cametendo
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
public class BlockSize {
|
public class BlockSize {
|
||||||
|
|
||||||
public static String blockSizeString = "";
|
/**
|
||||||
|
* Default block size string value.
|
||||||
|
* Set to "4M" as the default block size for flashing operations.
|
||||||
|
*/
|
||||||
|
public static String blockSizeString = "4M";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps user input to a valid block size value.
|
||||||
|
*
|
||||||
|
* <p>Supports both numeric inputs (1-6) and string inputs (512K,1M,2M,4M,8M,16M).
|
||||||
|
* If the input is not recognized, returns the default block size.</p>
|
||||||
|
*
|
||||||
|
* @param input User input string, either numeric (1-6) or block size string
|
||||||
|
* @return Valid block size string (512K, 1M, 2M, 4M, 8M, 16M, or default)
|
||||||
|
*/
|
||||||
|
public static String mapBlockSize(String input) {
|
||||||
|
return switch (input) {
|
||||||
|
case "1", "512K" -> "512K";
|
||||||
|
case "2", "1M" -> "1M";
|
||||||
|
case "3", "2M" -> "2M";
|
||||||
|
case "4", "4M" -> "4M";
|
||||||
|
case "5", "8M" -> "8M";
|
||||||
|
case "6", "16M" -> "16M";
|
||||||
|
default -> blockSizeString;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interactively prompts the user to select a block size.
|
||||||
|
*
|
||||||
|
* <p>Displays a menu of available block sizes and maps the user's input
|
||||||
|
* to a valid block size value using {@link #mapBlockSize(String)}.</p>
|
||||||
|
*
|
||||||
|
* @param UserInput Scanner object for reading user input
|
||||||
|
* @return The selected block size string
|
||||||
|
*/
|
||||||
static String blockSize(Scanner UserInput) {
|
static String blockSize(Scanner UserInput) {
|
||||||
System.out.println("Choose a block size (Default: 4M)");
|
System.out.println("Choose a block size (Default: 4M)");
|
||||||
System.out.println("512KB (1), 1M (2), 2M (3), 4M (4), 8M (5), 16M (6)");
|
System.out.println("512KB (1), 1M (2), 2M (3), 4M (4), 8M (5), 16M (6)");
|
||||||
String blockSizeInput = UserInput.nextLine();
|
|
||||||
|
|
||||||
switch (blockSizeInput) {
|
String input = UserInput.nextLine();
|
||||||
case "1":
|
|
||||||
blockSizeString = "512KB";
|
blockSizeString = mapBlockSize(input);
|
||||||
break;
|
|
||||||
case "2":
|
|
||||||
blockSizeString = "1M";
|
|
||||||
break;
|
|
||||||
case "3":
|
|
||||||
blockSizeString = "2M";
|
|
||||||
break;
|
|
||||||
case "4":
|
|
||||||
blockSizeString = "4M";
|
|
||||||
break;
|
|
||||||
case "5":
|
|
||||||
blockSizeString = "8M";
|
|
||||||
break;
|
|
||||||
case "6":
|
|
||||||
blockSizeString = "16M";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
blockSizeString = "4M";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
System.out.println("Using blocksize of: " + blockSizeString);
|
System.out.println("Using blocksize of: " + blockSizeString);
|
||||||
return blockSizeString;
|
return blockSizeString;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,26 @@ import java.io.BufferedReader;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the dd command for disk flashing operations.
|
||||||
|
*
|
||||||
|
* <p>This class handles the actual execution of the dd command with the configured
|
||||||
|
* parameters (input file, output device, block size, and output flags). It provides
|
||||||
|
* real-time output streaming and calls the OSDetector for completion messages.</p>
|
||||||
|
*
|
||||||
|
* @author Cametendo
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
public class Dd {
|
public class Dd {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the dd command with the configured parameters.
|
||||||
|
*
|
||||||
|
* <p>Runs the dd command using sudo with the specified image file, target device,
|
||||||
|
* block size, and output flags. Streams the command output in real-time to show
|
||||||
|
* progress. Upon completion, calls {@link OSDetector#wishWell(String)} to display
|
||||||
|
* a completion message based on the image file name.</p>
|
||||||
|
*/
|
||||||
public static void dd() {
|
public static void dd() {
|
||||||
try {
|
try {
|
||||||
ProcessBuilder pb = new ProcessBuilder("sudo", "dd", "if=" + FilePathAdd.ImagePath, "of=" + StorageDeviceLister.fullPath, "bs=" + BlockSize.blockSizeString, "status=progress", "oflag=" + OflagHandler.oflagHandleString);
|
ProcessBuilder pb = new ProcessBuilder("sudo", "dd", "if=" + FilePathAdd.ImagePath, "of=" + StorageDeviceLister.fullPath, "bs=" + BlockSize.blockSizeString, "status=progress", "oflag=" + OflagHandler.oflagHandleString);
|
||||||
@@ -20,6 +39,7 @@ public class Dd {
|
|||||||
System.out.print(c);
|
System.out.print(c);
|
||||||
System.out.flush();
|
System.out.flush();
|
||||||
}
|
}
|
||||||
|
OSDetector.wishWell(FilePathAdd.ImagePath);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,108 @@
|
|||||||
package org.cametendo;
|
package org.cametendo;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
|
import org.jline.reader.LineReader;
|
||||||
|
import org.jline.reader.LineReaderBuilder;
|
||||||
|
import org.jline.reader.impl.completer.FileNameCompleter;
|
||||||
|
import org.jline.terminal.Terminal;
|
||||||
|
import org.jline.terminal.TerminalBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles file path input and validation for disk image files.
|
||||||
|
* * <p>This class provides functionality to interactively prompt users for image file paths
|
||||||
|
* with tab completion support via JLine. It handles Unix-style tilde (~) expansion
|
||||||
|
* to the user's home directory and validates that paths point to existing regular files.</p>
|
||||||
|
* * @author Cametendo
|
||||||
|
* @version 1.1
|
||||||
|
*/
|
||||||
public class FilePathAdd {
|
public class FilePathAdd {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the validated absolute path to the selected image file.
|
||||||
|
*/
|
||||||
public static String ImagePath = "";
|
public static String ImagePath = "";
|
||||||
|
|
||||||
protected static String filePath(Scanner UserInput) {
|
/**
|
||||||
|
* Constant representing the current user's home directory path.
|
||||||
|
*/
|
||||||
|
public static final String Home = System.getProperty("user.home");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interactively prompts the user to select an image file path.
|
||||||
|
* * <p>Uses JLine for enhanced terminal interaction with {@link FileNameCompleter}.
|
||||||
|
* The method expands the tilde (~) character if present at the start of the string
|
||||||
|
* and validates that the resulting path is a regular file before returning.</p>
|
||||||
|
* * @return The validated absolute path to the selected image file
|
||||||
|
* @throws IOException If there are I/O errors during terminal setup or file resolution
|
||||||
|
*/
|
||||||
|
protected static String filePath() throws IOException {
|
||||||
fileQuestion();
|
fileQuestion();
|
||||||
|
|
||||||
|
Terminal terminal = TerminalBuilder.terminal();
|
||||||
|
LineReader reader = LineReaderBuilder.builder().terminal(terminal).completer(new FileNameCompleter()).build();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ImagePath = UserInput.nextLine();
|
String input = reader.readLine("Path: ").trim();
|
||||||
if (ImagePath.isBlank()) {
|
|
||||||
System.out.println("Oops.. You didn't specify a file, did you missclick?");
|
if (input.isBlank()) {
|
||||||
|
System.out.println("Oops... You didn't specify a file!");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Path path = Path.of(ImagePath);
|
|
||||||
try {
|
// Expand tilde to the full home directory path
|
||||||
Files.readAttributes(path, "basic:size");
|
if (input.startsWith("~")) {
|
||||||
System.out.println("Using File: " + ImagePath);
|
input = Home + input.substring(1);
|
||||||
return ImagePath;
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("Failed to access file, invalid path or no access to file! Please try again.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Path path = Path.of(input);
|
||||||
|
|
||||||
|
if (!Files.exists(path) || !Files.isRegularFile(path)) {
|
||||||
|
System.out.println("Invalid file! Please ensure the path points to an ISO / image file.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to a real, absolute path and return
|
||||||
|
ImagePath = path.toRealPath().toString();
|
||||||
|
System.out.println("Using File: " + ImagePath);
|
||||||
|
return ImagePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates and returns the full path to an image file from a provided string.
|
||||||
|
* * <p>This is primarily used for validating command-line arguments. It supports
|
||||||
|
* tilde expansion and verifies file existence and type.</p>
|
||||||
|
* * @param inputPath Raw path string to validate
|
||||||
|
* @return Full validated absolute path, or {@code null} if the path is invalid or inaccessible
|
||||||
|
*/
|
||||||
|
public static String validateAndGetFile(String inputPath) {
|
||||||
|
if (inputPath == null) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (inputPath.startsWith("~")) {
|
||||||
|
inputPath = Home + inputPath.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Path path = Path.of(inputPath);
|
||||||
|
if (Files.exists(path) && Files.isRegularFile(path)) {
|
||||||
|
return path.toRealPath().toString();
|
||||||
|
} else {
|
||||||
|
System.out.println("Invalid file! Please ensure the path points to an ISO / image file.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("File not found! Invalid Path or no access.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the prompt for file path input to the standard output.
|
||||||
|
*/
|
||||||
protected static void fileQuestion() {
|
protected static void fileQuestion() {
|
||||||
System.out.println("Please enter the FULL Path of your ISO / Image. (No tab-complete)");
|
System.out.println("Please enter the FULL Path of your ISO / Image. (Tab-completion supported)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,34 @@
|
|||||||
package org.cametendo;
|
package org.cametendo;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the final confirmation and execution of the disk flashing process.
|
||||||
|
*
|
||||||
|
* <p>This class displays the current configuration to the user for confirmation
|
||||||
|
* before proceeding with the actual flashing operation using the dd command.</p>
|
||||||
|
*
|
||||||
|
* @author Cametendo
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
public class Flasher {
|
public class Flasher {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the current flashing configuration and prompts for user confirmation.
|
||||||
|
*
|
||||||
|
* <p>Shows the device path, image file path, block size, and output flag that will be used
|
||||||
|
* for the flashing operation. If the user confirms, proceeds with the flashing process
|
||||||
|
* by calling {@link Dd#dd()}. If the user cancels, exits the application.</p>
|
||||||
|
*
|
||||||
|
* @param UserInput Scanner object for reading user confirmation
|
||||||
|
*/
|
||||||
public static void flasher(Scanner UserInput) {
|
public static void flasher(Scanner UserInput) {
|
||||||
|
|
||||||
String input = "";
|
String input = "";
|
||||||
|
|
||||||
System.out.println("The programm wil use the following configuration, do you want to flash with this? (Y/n)");
|
System.out.println("The program will use the following configuration, do you want to flash with this? (Y/n)");
|
||||||
System.out.println(" - To be flashed device: " + StorageDeviceLister.fullPath);
|
System.out.println(" - To be flashed device: " + StorageDeviceLister.fullPath);
|
||||||
System.out.println(" - To be used path: " + FilePathAdd.ImagePath);
|
System.out.println(" - To be used path: " + FilePathAdd.ImagePath);
|
||||||
System.out.println(" - To bed used blocksize: " + BlockSize.blockSizeString);
|
System.out.println(" - To be used blocksize: " + BlockSize.blockSizeString);
|
||||||
System.out.println(" - To be used oflag: " + OflagHandler.oflagHandleString);
|
System.out.println(" - To be used oflag: " + OflagHandler.oflagHandleString);
|
||||||
input = UserInput.nextLine();
|
input = UserInput.nextLine();
|
||||||
if (YesNo.check(input)) {
|
if (YesNo.check(input)) {
|
||||||
@@ -19,6 +38,5 @@ public class Flasher {
|
|||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
Dd.dd();
|
Dd.dd();
|
||||||
System.out.println("Flash completed.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1
src/main/java/org/cametendo/GetHome.java
Normal file
1
src/main/java/org/cametendo/GetHome.java
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -1,7 +1,27 @@
|
|||||||
package org.cametendo;
|
package org.cametendo;
|
||||||
|
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the initial greeting and user confirmation for the cflash application.
|
||||||
|
*
|
||||||
|
* <p>This class provides a welcome message and prompts the user to confirm
|
||||||
|
* whether they want to proceed with flashing an image to a storage device.</p>
|
||||||
|
*
|
||||||
|
* @author Cametendo
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
public class Greeting {
|
public class Greeting {
|
||||||
public static void greeting() {
|
|
||||||
|
/**
|
||||||
|
* Displays a welcome message and prompts for user confirmation.
|
||||||
|
*
|
||||||
|
* <p>Shows the cflash welcome message and asks the user if they want to
|
||||||
|
* flash an image. If the user declines, exits the application.</p>
|
||||||
|
*
|
||||||
|
* @param UserInput Scanner object for reading user confirmation
|
||||||
|
*/
|
||||||
|
public static void greeting(Scanner UserInput) {
|
||||||
System.out.println("Welcome to cflash!");
|
System.out.println("Welcome to cflash!");
|
||||||
System.out.println("Would you like to flash an image (Y/n)");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,70 @@
|
|||||||
package org.cametendo;
|
package org.cametendo;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main entry point for the cflash application.
|
||||||
|
*
|
||||||
|
* <p>cflash is a command-line utility for flashing disk images to storage devices.
|
||||||
|
* It supports both interactive mode and command-line argument mode for automation.</p>
|
||||||
|
*
|
||||||
|
* <p>In interactive mode, the user is guided through device selection, file path input,
|
||||||
|
* block size configuration, and output flag selection. In command-line mode, all parameters
|
||||||
|
* can be specified as arguments for automated flashing.</p>
|
||||||
|
*
|
||||||
|
* @author Cametendo
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) throws InterruptedException {
|
|
||||||
|
/**
|
||||||
|
* Main method that serves as the entry point for the cflash application.
|
||||||
|
*
|
||||||
|
* <p>The application can operate in two modes:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>Interactive mode: No arguments provided, user is guided through the process</li>
|
||||||
|
* <li>Command-line mode: Four arguments provided for automated execution</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>Command-line arguments format:</p>
|
||||||
|
* <ol>
|
||||||
|
* <li>Device name (e.g., "sda" without /dev/ prefix)</li>
|
||||||
|
* <li>Image file path (absolute or relative path to ISO/image file)</li>
|
||||||
|
* <li>Block size (1-6 or 512K,1M,2M,4M,8M,16M)</li>
|
||||||
|
* <li>Output flag (1-4 or direct,dsync,sync,nocache)</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* @param args Command-line arguments. If 4 arguments are provided, runs in automated mode.
|
||||||
|
* If no arguments, runs in interactive mode.
|
||||||
|
* @throws InterruptedException If the flashing process is interrupted
|
||||||
|
* @throws IOException If there are I/O errors during device/file validation
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws InterruptedException, IOException {
|
||||||
Scanner UserInput = new Scanner(System.in);
|
Scanner UserInput = new Scanner(System.in);
|
||||||
|
if (args.length == 4) {
|
||||||
Greeting.greeting();
|
String validatedDevice = StorageDeviceLister.validateAndGetPath(args[0]);
|
||||||
String input = UserInput.nextLine();
|
if (validatedDevice == null) {
|
||||||
|
return;
|
||||||
if (YesNo.check(input)) {
|
}
|
||||||
System.out.println("Please choose the to be flashed device (f. e. sda)");
|
|
||||||
} else {
|
String validatedFile = FilePathAdd.validateAndGetFile(args[1]);
|
||||||
System.out.println("Canceling...");
|
if (validatedFile == null) {
|
||||||
System.exit(0);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageDeviceLister.fullPath = validatedDevice;
|
||||||
|
FilePathAdd.ImagePath = validatedFile;
|
||||||
|
BlockSize.blockSizeString = BlockSize.mapBlockSize(args[2]);
|
||||||
|
OflagHandler.oflagHandleString = OflagHandler.mapOflagHandle(args[3]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Greeting.greeting(UserInput);
|
||||||
|
|
||||||
|
StorageDeviceLister.deviceCheck(UserInput);
|
||||||
|
FilePathAdd.filePath();
|
||||||
|
BlockSize.blockSize(UserInput);
|
||||||
|
OflagHandler.Oflag(UserInput);
|
||||||
}
|
}
|
||||||
StorageDeviceLister.deviceCheck(UserInput);
|
|
||||||
FilePathAdd.filePath(UserInput);
|
|
||||||
BlockSize.blockSize(UserInput);
|
|
||||||
OflagHandler.handleOflag(UserInput);
|
|
||||||
Flasher.flasher(UserInput);
|
Flasher.flasher(UserInput);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
97
src/main/java/org/cametendo/OSDetector.java
Normal file
97
src/main/java/org/cametendo/OSDetector.java
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package org.cametendo;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects operating system types from image file names and displays completion messages.
|
||||||
|
*
|
||||||
|
* <p>This class analyzes the filename of disk images to identify the operating system
|
||||||
|
* and displays a personalized completion message with some fun descriptions for various
|
||||||
|
* Linux distributions, BSD variants, and other operating systems.</p>
|
||||||
|
*
|
||||||
|
* @author Cametendo
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
public class OSDetector {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Analyzes an image file path and displays a personalized completion message.
|
||||||
|
*
|
||||||
|
* <p>Extracts the filename from the provided path and attempts to identify the
|
||||||
|
* operating system based on filename patterns. Displays a fun, personalized message
|
||||||
|
* wishing the user well with their new OS installation.</p>
|
||||||
|
*
|
||||||
|
* @param imagePath Path to the image file that was flashed
|
||||||
|
*/
|
||||||
|
public static void wishWell(String imagePath) {
|
||||||
|
String fileName = Path.of(imagePath).getFileName().toString().toLowerCase();
|
||||||
|
|
||||||
|
String osName;
|
||||||
|
|
||||||
|
// Specialized & Advanced Distros
|
||||||
|
if (fileName.contains("nyarch")) {
|
||||||
|
osName = "Nyarch Linux (Nyaa~!)";
|
||||||
|
} else if (fileName.contains("artix")) {
|
||||||
|
osName = "Artix Linux (Systemd-free Arch!)";
|
||||||
|
} else if (fileName.contains("gentoo")) {
|
||||||
|
osName = "Gentoo (Enjoy the compiling...)";
|
||||||
|
} else if (fileName.contains("nixos")) {
|
||||||
|
osName = "NixOS (Immutable & Reproducible!)";
|
||||||
|
} else if (fileName.contains("void")) {
|
||||||
|
osName = "Void Linux";
|
||||||
|
} else if (fileName.contains("arch")) {
|
||||||
|
osName = "Arch Linux (btw)";
|
||||||
|
} else if (fileName.contains("alpine")) {
|
||||||
|
osName = "Alpine Linux (Minimalism at its peak)";
|
||||||
|
} else if (fileName.contains("winux")) {
|
||||||
|
osName = "Winux (Windows without Windows)";
|
||||||
|
}
|
||||||
|
// Mainstream Linux
|
||||||
|
else if (fileName.contains("fedora")) {
|
||||||
|
osName = "Fedora (Freehat Linux)";
|
||||||
|
} else if (fileName.contains("debian")) {
|
||||||
|
osName = "Debian (Universal OS)";
|
||||||
|
} else if (fileName.contains("ubuntu")) {
|
||||||
|
osName = "Ubuntu (Debian but fancy)";
|
||||||
|
} else if (fileName.contains("mint")) {
|
||||||
|
osName = "Linux Mint";
|
||||||
|
} else if (fileName.contains("pop-os") || fileName.contains("pop_os")) {
|
||||||
|
osName = "Pop!_OS";
|
||||||
|
}
|
||||||
|
// The BSD Family
|
||||||
|
else if (fileName.contains("freebsd")) {
|
||||||
|
osName = "FreeBSD";
|
||||||
|
} else if (fileName.contains("openbsd")) {
|
||||||
|
osName = "OpenBSD (Secure by default)";
|
||||||
|
} else if (fileName.contains("netbsd")) {
|
||||||
|
osName = "NetBSD (It runs on everything!)";
|
||||||
|
}
|
||||||
|
// Security & Privacy
|
||||||
|
else if (fileName.contains("kali")) {
|
||||||
|
osName = "Kali Linux (Happy Hacking)";
|
||||||
|
} else if (fileName.contains("tails")) {
|
||||||
|
osName = "Tails (Incognito mode: ON)";
|
||||||
|
} else if (fileName.contains("qubes")) {
|
||||||
|
osName = "Qubes OS (Security by Compartmentalization)";
|
||||||
|
}
|
||||||
|
// Others & Legacy
|
||||||
|
else if (fileName.contains("win") && (fileName.contains("10") || fileName.contains("11"))) {
|
||||||
|
osName = "Windows (Spies... Spies everywhere)";
|
||||||
|
} else if (fileName.contains("haiku")) {
|
||||||
|
osName = "Haiku OS";
|
||||||
|
} else if (fileName.contains("reactos")) {
|
||||||
|
osName = "ReactOS";
|
||||||
|
} else if (fileName.contains("jgh")) {
|
||||||
|
osName = "JGH OS (Sauerkraut juice)";
|
||||||
|
}
|
||||||
|
// Generic Fallbacks
|
||||||
|
else if (fileName.contains("linux")) {
|
||||||
|
osName = "Linux";
|
||||||
|
} else if (fileName.contains("bsd")) {
|
||||||
|
osName = "BSD";
|
||||||
|
} else {
|
||||||
|
osName = "new OS";
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("\nFlash complete! Have fun with your " + osName + " installation!");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +1,60 @@
|
|||||||
package org.cametendo;
|
package org.cametendo;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles output flag (oflag) configuration for the dd command.
|
||||||
|
*
|
||||||
|
* <p>This class provides functionality to both interactively prompt users for output flag selection
|
||||||
|
* and to map command-line inputs to valid oflag values. The default output flag is "direct".</p>
|
||||||
|
*
|
||||||
|
* @author Cametendo
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
public class OflagHandler {
|
public class OflagHandler {
|
||||||
|
|
||||||
public static String oflagHandleString = "";
|
/**
|
||||||
|
* Default output flag string value.
|
||||||
|
* Set to "direct" as the default output flag for dd operations.
|
||||||
|
*/
|
||||||
|
public static String oflagHandleString = "direct";
|
||||||
|
|
||||||
static String handleOflag(Scanner UserInput) {
|
/**
|
||||||
System.out.println("Okay, next up please define your oflag (Default: direct)");
|
* Maps user input to a valid output flag value.
|
||||||
System.out.println("Available flags: direct (1), dsync (2), sync (3), nocache (4)");
|
*
|
||||||
String oflagHandleInput = UserInput.nextLine();
|
* <p>Supports both numeric inputs (1-4) and string inputs (direct,dsync,sync,nocache).
|
||||||
|
* If the input is not recognized, returns the default output flag.</p>
|
||||||
|
*
|
||||||
|
* @param input User input string, either numeric (1-4) or output flag string
|
||||||
|
* @return Valid output flag string (direct, dsync, sync, nocache, or default)
|
||||||
|
*/
|
||||||
|
public static String mapOflagHandle(String input) {
|
||||||
|
return switch (input) {
|
||||||
|
case "1", "direct" -> "direct";
|
||||||
|
case "2", "dsync" -> "dsync";
|
||||||
|
case "3", "sync" -> "sync";
|
||||||
|
case "4", "nocache" -> "nocache";
|
||||||
|
default -> oflagHandleString;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
switch (oflagHandleInput) {
|
/**
|
||||||
case "1":
|
* Interactively prompts the user to select an output flag.
|
||||||
oflagHandleString = "direct";
|
*
|
||||||
break;
|
* <p>Displays a menu of available output flags and maps the user's input
|
||||||
case "2":
|
* to a valid output flag value using {@link #mapOflagHandle(String)}.</p>
|
||||||
oflagHandleString = "dsync";
|
*
|
||||||
break;
|
* @param UserInput Scanner object for reading user input
|
||||||
case "3":
|
* @return The selected output flag string
|
||||||
oflagHandleString = "sync";
|
*/
|
||||||
break;
|
static String Oflag(Scanner UserInput) {
|
||||||
case "4":
|
System.out.println("Choose an Oflag (Default: direct)");
|
||||||
oflagHandleString = "nocache";
|
System.out.println("direct (1), dsync (2), sync (3), nocache (4)");
|
||||||
break;
|
|
||||||
default:
|
String input = UserInput.nextLine();
|
||||||
oflagHandleString = "direct";
|
|
||||||
break;
|
oflagHandleString = mapOflagHandle(input);
|
||||||
}
|
|
||||||
System.out.println("Using oflag: " + oflagHandleString);
|
System.out.println("Using Oflag: " + oflagHandleString);
|
||||||
return oflagHandleString;
|
return oflagHandleString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +1,134 @@
|
|||||||
package org.cametendo;
|
package org.cametendo;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles storage device detection, listing, and validation for the flashing process.
|
||||||
|
* * <p>Includes safety checks to ensure we don't nuke a partition that's currently in use.
|
||||||
|
* Keeps the user in the loop with a more personal touch.</p>
|
||||||
|
* * @author Cametendo
|
||||||
|
* @version 1.1
|
||||||
|
*/
|
||||||
public class StorageDeviceLister {
|
public class StorageDeviceLister {
|
||||||
|
|
||||||
public static String device = "";
|
public static String device = "";
|
||||||
public static String fullPath = "";
|
public static String fullPath = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guides the user through selecting a safe, unmounted storage device.
|
||||||
|
*/
|
||||||
protected static String deviceCheck(Scanner UserInput) {
|
protected static String deviceCheck(Scanner UserInput) {
|
||||||
// 1. lsblk wird genau EINMAL aufgerufen
|
|
||||||
deviceList();
|
deviceList();
|
||||||
|
|
||||||
// 2. Die Abfrage-Schleife
|
|
||||||
while (true) {
|
while (true) {
|
||||||
device = UserInput.nextLine();
|
System.out.print("Target device: ");
|
||||||
|
device = UserInput.nextLine().trim();
|
||||||
|
|
||||||
if (device.isBlank()) {
|
if (device.isBlank()) {
|
||||||
System.out.println("Oops... Device name is empty. Did you missclick?");
|
System.out.println("Oops... Device name is empty. Did you missclick?");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Path path = Path.of("/dev/" + device);
|
|
||||||
|
// Standardize path - allows entering 'sda' or '/dev/sda'
|
||||||
|
String checkPath = device.startsWith("/dev/") ? device : "/dev/" + device;
|
||||||
|
Path path = Path.of(checkPath);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Versuche, den echten Pfad zu finden
|
|
||||||
fullPath = path.toRealPath().toString();
|
fullPath = path.toRealPath().toString();
|
||||||
|
|
||||||
// Wenn wir hier ankommen, war der Pfad gültig
|
// Check if the user is about to break their system
|
||||||
System.out.println("Using device: " + fullPath);
|
if (isMounted(fullPath)) {
|
||||||
|
System.out.println("Wait a second! " + fullPath + " is currently mounted.");
|
||||||
|
System.out.println("I can't flash to a device that's in use. Unmount it and try again!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Solid choice. Using device: " + fullPath);
|
||||||
return fullPath;
|
return fullPath;
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// Fehler-Output, danach springt die Schleife wieder nach oben
|
System.out.println("Hmm... I can't seem to find or access that device. Are you sure you have access to it?");
|
||||||
System.out.println("Failed to access device! Invalid path or no access. Please try again.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks lsblk if the device or its children have an active mount point.
|
||||||
|
*/
|
||||||
|
private static boolean isMounted(String devicePath) {
|
||||||
|
try {
|
||||||
|
ProcessBuilder pb = new ProcessBuilder("lsblk", "-no", "MOUNTPOINT", devicePath);
|
||||||
|
Process process = pb.start();
|
||||||
|
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
if (!line.trim().isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
process.waitFor();
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
System.out.println("Warning: Mountstatus couldn't be verified");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists devices with enough info for the user to make a smart decision.
|
||||||
|
*/
|
||||||
private static void deviceList() {
|
private static void deviceList() {
|
||||||
try {
|
try {
|
||||||
ProcessBuilder pb = new ProcessBuilder("lsblk");
|
System.out.println("Scanning for block devices...");
|
||||||
|
ProcessBuilder pb = new ProcessBuilder("lsblk", "-o", "NAME,SIZE,TYPE,RM,MOUNTPOINT");
|
||||||
Process process = pb.start();
|
Process process = pb.start();
|
||||||
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||||
String line;
|
String line;
|
||||||
while ((line = reader.readLine()) != null) {
|
while ((line = reader.readLine()) != null) {
|
||||||
System.out.println(line);
|
System.out.println(line);
|
||||||
}
|
}
|
||||||
process.waitFor();
|
process.waitFor();
|
||||||
System.out.println("Please enter the name of your device (without /dev/):");
|
|
||||||
|
System.out.println("Enter the name of your device (e.g., sdb or nvme1n1):");
|
||||||
|
|
||||||
} catch (IOException | InterruptedException e) {
|
} catch (IOException | InterruptedException e) {
|
||||||
e.printStackTrace();
|
System.out.println("Failed to run lsblk. Do you have it installed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a device path (e.g., from a CLI argument).
|
||||||
|
* * <p>Checks if the device exists, resolves the real path, and ensures
|
||||||
|
* it isn't currently mounted before giving the green light.</p>
|
||||||
|
* * @param deviceName Device name (e.g., "sda" or "/dev/sda")
|
||||||
|
* @return Full validated path, or null if it's a bad idea to use it
|
||||||
|
*/
|
||||||
|
public static String validateAndGetPath(String deviceName) {
|
||||||
|
if (deviceName == null || deviceName.isBlank()) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Support both "sda" and "/dev/sda"
|
||||||
|
String checkPath = deviceName.startsWith("/dev/") ? deviceName : "/dev/" + deviceName;
|
||||||
|
Path path = Path.of(checkPath);
|
||||||
|
String resolvedPath = path.toRealPath().toString();
|
||||||
|
|
||||||
|
// Safety check for CLI arguments too!
|
||||||
|
if (isMounted(resolvedPath)) {
|
||||||
|
System.out.println("Hold up! " + resolvedPath + " is mounted. I won't let you flash it like that.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvedPath;
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("Hmm... I couldn't find a device at '" + deviceName + "'. Is it plugged in?");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,25 @@
|
|||||||
package org.cametendo;
|
package org.cametendo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for parsing yes/no user responses.
|
||||||
|
*
|
||||||
|
* <p>This class provides a simple method to interpret user input as a boolean
|
||||||
|
* value, accepting various forms of "yes" and treating everything else as "no".</p>
|
||||||
|
*
|
||||||
|
* @author Cametendo
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
public class YesNo {
|
public class YesNo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses user input to determine if it represents a "yes" response.
|
||||||
|
*
|
||||||
|
* <p>Accepts "Y", "y", and empty string (default) as yes responses.
|
||||||
|
* All other inputs are treated as no responses.</p>
|
||||||
|
*
|
||||||
|
* @param input User input string to parse
|
||||||
|
* @return true if the input represents a yes response, false otherwise
|
||||||
|
*/
|
||||||
public static boolean check(String input) {
|
public static boolean check(String input) {
|
||||||
switch (input) {
|
switch (input) {
|
||||||
case "Y":
|
case "Y":
|
||||||
|
|||||||
12
uninstall.sh
Executable file
12
uninstall.sh
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Uninstall script for cflash
|
||||||
|
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
echo "Please run as root to uninstall globally."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f /usr/local/bin/cflash
|
||||||
|
rm -rf /usr/local/lib/cflash
|
||||||
|
|
||||||
|
echo "cflash uninstalled successfully."
|
||||||
Reference in New Issue
Block a user