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