Inital commit
This commit is contained in:
15
.SRCINFO
Normal file
15
.SRCINFO
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
pkgbase = cflash
|
||||||
|
pkgdesc = A small and lightweight wrapper for dd that strips away the complexity of CLI flashing.
|
||||||
|
pkgver = 1.0.1
|
||||||
|
pkgrel = 1
|
||||||
|
url = https://github.com/cametendo/cflash-git
|
||||||
|
arch = any
|
||||||
|
license = MIT
|
||||||
|
makedepends = java-environment>=21
|
||||||
|
makedepends = maven
|
||||||
|
makedepends = git
|
||||||
|
depends = java-runtime>=21
|
||||||
|
source = cflash::git+https://github.com/cametendo/cflash-git.git
|
||||||
|
sha256sums = SKIP
|
||||||
|
|
||||||
|
pkgname = cflash
|
||||||
39
.gitignore
vendored
Normal file
39
.gitignore
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
.mtj.tmp/
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
replay_pid*
|
||||||
|
|
||||||
|
target/
|
||||||
|
*.class
|
||||||
|
.mtj.tmp/
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.ear
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
# VS Code specific
|
||||||
|
.classpath
|
||||||
|
.project
|
||||||
|
.settings/
|
||||||
|
.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.
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Cametendo
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
34
PKGBUILD
Normal file
34
PKGBUILD
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Maintainer: Cametendo cameronmathis08@gmail.com
|
||||||
|
pkgname=cflash
|
||||||
|
pkgver=1.0.1
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc="A small and lightweight wrapper for dd that strips away the complexity of CLI flashing."
|
||||||
|
arch=('any')
|
||||||
|
url="https://github.com/cametendo/cflash-git"
|
||||||
|
license=('MIT')
|
||||||
|
depends=('java-runtime>=21')
|
||||||
|
makedepends=('java-environment>=21' 'maven' 'git')
|
||||||
|
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"
|
||||||
|
|
||||||
|
install -Dm644 "target/${pkgname}-${pkgver}-jar-with-dependencies.jar" \
|
||||||
|
"$pkgdir/usr/share/java/${pkgname}/${pkgname}.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"
|
||||||
|
}
|
||||||
129
README.md
Normal file
129
README.md
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
# cflash
|
||||||
|
A small and lightweight wrapper for `dd` that strips away the complexity of CLI flashing.
|
||||||
|
|
||||||
|
[](https://opensource.org/licenses/MIT)
|
||||||
|
[](https://www.java.com/en/)
|
||||||
|
[](https://www.linux.org/)
|
||||||
|
[](https://github.com/Cametendo/cflash-git/releases/tag/cflash-1.0.0)
|
||||||
|
|
||||||
|
# About
|
||||||
|
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
|
||||||
|
- `Java`: 21 (Download [here](https://www.oracle.com/java/technologies/downloads/#java21))
|
||||||
|
- `util-linux`: 2.41
|
||||||
|
- `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
|
||||||
|
- Using the command `cflash` in the terminal, will start the flashing process. You will be asked several question before the flashing begins:
|
||||||
|
1. You will see a list of every drive your system see's (excluding system drives) and the be asked to enter the device you want to flash the image onto. (F.e. **/dev/sda**)
|
||||||
|
2. You will be prompted to enter the path of the iso / image you want to flash
|
||||||
|
3. You will be prompted to choose a byte size (default: 4M)
|
||||||
|
4. You will be prompted to enter your oflag (default: direct)
|
||||||
|
5. You will be asked if you are absolutely sure that you want to continue (flashing will wipe all data)
|
||||||
|
- Alternative: using `cflash [device] [iso-path] [block-size] [oflag]` will skip the questions and instantly ask you, if you're absolutely sure you want to continue.
|
||||||
|
- Once confirmed, the flash will start and a small progress bar will appear showing the flashing progress.
|
||||||
|
- After completion, the program will detect the OS from the iso and wish you a great time with your new OS. (Example: "Done! Have fun with your new Linux installation!)
|
||||||
|
- **IMPORTANT**: Since dd needs sudo rights, ensure you have root priviliges.
|
||||||
|
|
||||||
|
# Supported OS
|
||||||
|
- Linux
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
1. Clone the repository onto your device and cd into it.
|
||||||
|
2. Run the `build.sh` file to build the program.
|
||||||
|
3. Run the `ìnstall.sh`to install the program.
|
||||||
|
4. Open a terminal and use the program with `cflash`, optionally add all the arguments you need.
|
||||||
|
|
||||||
|
# License and Credits
|
||||||
|
**Author**: [Cametendo](https://www.github.com/Cametendo)
|
||||||
|
**License**: MIT
|
||||||
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."
|
||||||
55
pom.xml
Normal file
55
pom.xml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>org.cametendo</groupId>
|
||||||
|
<artifactId>cflash</artifactId>
|
||||||
|
<version>1.0.1</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
<maven.compiler.target>21</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jline</groupId>
|
||||||
|
<artifactId>jline</artifactId>
|
||||||
|
<version>3.25.1</version>
|
||||||
|
</dependency>
|
||||||
|
</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>
|
||||||
62
src/main/java/org/cametendo/BlockSize.java
Normal file
62
src/main/java/org/cametendo/BlockSize.java
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package org.cametendo;
|
||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
System.out.println("Choose a block size (Default: 4M)");
|
||||||
|
System.out.println("512KB (1), 1M (2), 2M (3), 4M (4), 8M (5), 16M (6)");
|
||||||
|
|
||||||
|
String input = UserInput.nextLine();
|
||||||
|
|
||||||
|
blockSizeString = mapBlockSize(input);
|
||||||
|
|
||||||
|
System.out.println("Using blocksize of: " + blockSizeString);
|
||||||
|
return blockSizeString;
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/main/java/org/cametendo/Dd.java
Normal file
47
src/main/java/org/cametendo/Dd.java
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package org.cametendo;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() {
|
||||||
|
try {
|
||||||
|
ProcessBuilder pb = new ProcessBuilder("sudo", "dd", "if=" + FilePathAdd.ImagePath, "of=" + StorageDeviceLister.fullPath, "bs=" + BlockSize.blockSizeString, "status=progress", "oflag=" + OflagHandler.oflagHandleString);
|
||||||
|
pb.redirectErrorStream(true);
|
||||||
|
Process process = pb.start();
|
||||||
|
|
||||||
|
BufferedReader reader = new BufferedReader(
|
||||||
|
new InputStreamReader(process.getInputStream())
|
||||||
|
);
|
||||||
|
|
||||||
|
int character;
|
||||||
|
while ((character = reader.read()) != -1) {
|
||||||
|
char c = (char) character;
|
||||||
|
System.out.print(c);
|
||||||
|
System.out.flush();
|
||||||
|
}
|
||||||
|
OSDetector.wishWell(FilePathAdd.ImagePath);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
108
src/main/java/org/cametendo/FilePathAdd.java
Normal file
108
src/main/java/org/cametendo/FilePathAdd.java
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package org.cametendo;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the validated absolute path to the selected image file.
|
||||||
|
*/
|
||||||
|
public static String ImagePath = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
Terminal terminal = TerminalBuilder.terminal();
|
||||||
|
LineReader reader = LineReaderBuilder.builder().terminal(terminal).completer(new FileNameCompleter()).build();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
String input = reader.readLine("Path: ").trim();
|
||||||
|
|
||||||
|
if (input.isBlank()) {
|
||||||
|
System.out.println("Oops... You didn't specify a file!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expand tilde to the full home directory path
|
||||||
|
if (input.startsWith("~")) {
|
||||||
|
input = Home + input.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
System.out.println("Please enter the FULL Path of your ISO / Image. (Tab-completion supported)");
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/main/java/org/cametendo/Flasher.java
Normal file
42
src/main/java/org/cametendo/Flasher.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package org.cametendo;
|
||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
|
||||||
|
String input = "";
|
||||||
|
|
||||||
|
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 used path: " + FilePathAdd.ImagePath);
|
||||||
|
System.out.println(" - To be used blocksize: " + BlockSize.blockSizeString);
|
||||||
|
System.out.println(" - To be used oflag: " + OflagHandler.oflagHandleString);
|
||||||
|
input = UserInput.nextLine();
|
||||||
|
if (YesNo.check(input)) {
|
||||||
|
System.out.println("Starting to flash...");
|
||||||
|
} else {
|
||||||
|
System.out.println("Canceling...");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
Dd.dd();
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/main/java/org/cametendo/GetHome.java
Normal file
1
src/main/java/org/cametendo/GetHome.java
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
27
src/main/java/org/cametendo/Greeting.java
Normal file
27
src/main/java/org/cametendo/Greeting.java
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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!");
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/main/java/org/cametendo/Main.java
Normal file
70
src/main/java/org/cametendo/Main.java
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package org.cametendo;
|
||||||
|
import java.io.IOException;
|
||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
if (args.length == 4) {
|
||||||
|
String validatedDevice = StorageDeviceLister.validateAndGetPath(args[0]);
|
||||||
|
if (validatedDevice == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String validatedFile = FilePathAdd.validateAndGetFile(args[1]);
|
||||||
|
if (validatedFile == null) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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!");
|
||||||
|
}
|
||||||
|
}
|
||||||
60
src/main/java/org/cametendo/OflagHandler.java
Normal file
60
src/main/java/org/cametendo/OflagHandler.java
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package org.cametendo;
|
||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default output flag string value.
|
||||||
|
* Set to "direct" as the default output flag for dd operations.
|
||||||
|
*/
|
||||||
|
public static String oflagHandleString = "direct";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps user input to a valid output flag value.
|
||||||
|
*
|
||||||
|
* <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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interactively prompts the user to select an output flag.
|
||||||
|
*
|
||||||
|
* <p>Displays a menu of available output flags and maps the user's input
|
||||||
|
* to a valid output flag value using {@link #mapOflagHandle(String)}.</p>
|
||||||
|
*
|
||||||
|
* @param UserInput Scanner object for reading user input
|
||||||
|
* @return The selected output flag string
|
||||||
|
*/
|
||||||
|
static String Oflag(Scanner UserInput) {
|
||||||
|
System.out.println("Choose an Oflag (Default: direct)");
|
||||||
|
System.out.println("direct (1), dsync (2), sync (3), nocache (4)");
|
||||||
|
|
||||||
|
String input = UserInput.nextLine();
|
||||||
|
|
||||||
|
oflagHandleString = mapOflagHandle(input);
|
||||||
|
|
||||||
|
System.out.println("Using Oflag: " + oflagHandleString);
|
||||||
|
return oflagHandleString;
|
||||||
|
}
|
||||||
|
}
|
||||||
134
src/main/java/org/cametendo/StorageDeviceLister.java
Normal file
134
src/main/java/org/cametendo/StorageDeviceLister.java
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package org.cametendo;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
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 static String device = "";
|
||||||
|
public static String fullPath = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guides the user through selecting a safe, unmounted storage device.
|
||||||
|
*/
|
||||||
|
protected static String deviceCheck(Scanner UserInput) {
|
||||||
|
deviceList();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
System.out.print("Target device: ");
|
||||||
|
device = UserInput.nextLine().trim();
|
||||||
|
|
||||||
|
if (device.isBlank()) {
|
||||||
|
System.out.println("Oops... Device name is empty. Did you missclick?");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standardize path - allows entering 'sda' or '/dev/sda'
|
||||||
|
String checkPath = device.startsWith("/dev/") ? device : "/dev/" + device;
|
||||||
|
Path path = Path.of(checkPath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
fullPath = path.toRealPath().toString();
|
||||||
|
|
||||||
|
// Check if the user is about to break their system
|
||||||
|
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;
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("Hmm... I can't seem to find or access that device. Are you sure you have access to it?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() {
|
||||||
|
try {
|
||||||
|
System.out.println("Scanning for block devices...");
|
||||||
|
ProcessBuilder pb = new ProcessBuilder("lsblk", "-o", "NAME,SIZE,TYPE,RM,MOUNTPOINT");
|
||||||
|
Process process = pb.start();
|
||||||
|
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
System.out.println(line);
|
||||||
|
}
|
||||||
|
process.waitFor();
|
||||||
|
|
||||||
|
System.out.println("Enter the name of your device (e.g., sdb or nvme1n1):");
|
||||||
|
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/main/java/org/cametendo/YesNo.java
Normal file
37
src/main/java/org/cametendo/YesNo.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
switch (input) {
|
||||||
|
case "Y":
|
||||||
|
return true;
|
||||||
|
case "y":
|
||||||
|
return true;
|
||||||
|
case "":
|
||||||
|
return true;
|
||||||
|
case "n":
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
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