5 Commits

Author SHA1 Message Date
Cametendo
d54142e71c Update PKGBUILD 2026-05-01 10:18:25 +02:00
Cametendo
ba3932e98f Added .SRCINFO 2026-04-28 12:40:13 +02:00
Cametendo
8a8b559959 Updated PKGBUILD for next version 2026-04-28 12:37:47 +02:00
Cametendo
063cbbd568 Fixed bugs 2026-04-28 11:49:35 +02:00
e15e7f26d5 Update Readme.md
Improved description and about as well as information for updating cflash
2026-04-24 17:09:33 +02:00
8 changed files with 168 additions and 103 deletions

15
.SRCINFO Normal file
View 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

View File

@@ -1,13 +1,13 @@
# Maintainer: Cametendo cameronmathis08@gmail.com # Maintainer: Cametendo cameronmathis08@gmail.com
pkgname=cflash pkgname=cflash
pkgver=1.0.0 pkgver=1.0.1
pkgrel=1 pkgrel=1
pkgdesc="Small and lightweight image and iso flasher build on dd." pkgdesc="A small and lightweight wrapper for dd that strips away the complexity of CLI flashing."
arch=('any') arch=('any')
url="https://github.com/cametendo/cflash-git" url="https://github.com/cametendo/cflash-git"
license=('MIT') license=('MIT')
depends=('java-runtime>=21') depends=('java-runtime>=21')
makedepends=('java-environment>=21' 'maven') makedepends=('java-environment>=21' 'maven' 'git')
source=("cflash::git+https://github.com/cametendo/cflash-git.git") source=("cflash::git+https://github.com/cametendo/cflash-git.git")
sha256sums=('SKIP') sha256sums=('SKIP')
@@ -20,9 +20,8 @@ build() {
package() { package() {
cd "$srcdir/cflash" cd "$srcdir/cflash"
# for some reason MAKEPKD won't accept my version, using the wildcard for literally anything if may find install -Dm644 "target/${pkgname}-${pkgver}-jar-with-dependencies.jar" \
install -Dm644 target/cflash-*-jar-with-dependencies.jar \ "$pkgdir/usr/share/java/${pkgname}/${pkgname}.jar"
"$pkgdir/usr/share/java/cflash/cflash.jar"
# Create the executable # Create the executable
install -d "$pkgdir/usr/bin" install -d "$pkgdir/usr/bin"

View File

@@ -1,15 +1,13 @@
# cflash # cflash
Small and lightweight image and iso flasher build on `dd`. A small and lightweight wrapper for `dd` that strips away the complexity of CLI flashing.
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Java Version](https://img.shields.io/badge/Java-21%2B-orange.svg)](https://www.java.com/en/) [![Java Version](https://img.shields.io/badge/Java-21%2B-orange.svg)](https://www.java.com/en/)
[![Platform](https://img.shields.io/badge/Platform-Linux-brightgreen.svg)](https://www.linux.org/) [![Platform](https://img.shields.io/badge/Platform-Linux-brightgreen.svg)](https://www.linux.org/)
[![Status](https://img.shields.io/badge/Status-Beta-red.svg)](https://en.wikipedia.org/wiki/Software_release_life_cycle#Beta) [![Version](https://img.shields.io/badge/version-1.0.0-blue)](https://github.com/Cametendo/cflash-git/releases/tag/cflash-1.0.0)
# About # About
Java program using `dd` to make flashing iso and image files easier on the terminal. This program allows anyone to flash iso and image files without having to search for extra GUI tools by keeping it simple and resource-friendly. Small and lightweight wrapper written in Java for `dd` designed to simplify CLI flashing while protecting your hardware from accidental command-line errors. cflash replaces the syntax with a clear, safe interface, providing a reliable workflow for both newcomers and power users.
## Getting Started
# Requirements # Requirements
- `Java`: 21 (Download [here](https://www.oracle.com/java/technologies/downloads/#java21)) - `Java`: 21 (Download [here](https://www.oracle.com/java/technologies/downloads/#java21))
@@ -32,12 +30,19 @@ Java program using `dd` to make flashing iso and image files easier on the termi
mvn clean package mvn clean package
``` ```
3. Run the application: 3. Run cflash:
```bash ```bash
java -jar target/cflash-<version>.jar (optionally add arguments here, like with dd) 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 ### System-wide Installation
To install cflash globally so that it can be run from any terminal: To install cflash globally so that it can be run from any terminal:
@@ -55,10 +60,10 @@ To install cflash globally so that it can be run from any terminal:
chmod +x build.sh install.sh chmod +x build.sh install.sh
``` ```
3. Build the project using the provided build script: 3. Build the project using the provided build script (requires root privileges):
```bash ```bash
./build.sh sudo ./build.sh
``` ```
4. Install globally (requires root privileges): 4. Install globally (requires root privileges):
@@ -73,6 +78,12 @@ To install cflash globally so that it can be run from any terminal:
cflash cflash
``` ```
6. Update cflash (reguires root privileges):
```bash
sudo cflash --update
```
**Notes:** **Notes:**
* The `build.sh` script compiles all Java source files and creates an executable `cflash.jar`. * The `build.sh` script compiles all Java source files and creates an executable `cflash.jar`.
@@ -85,6 +96,12 @@ To install cflash globally so that it can be run from any terminal:
cd cflash cd cflash
makepkg -si makepkg -si
``` ```
* You can update cflash using `yay` / `paru` via `yay -S cflash` / `paru -S cflash` or by rebuilding the package:
```bash
git clone https://aur.archlinux.org/cflash.git
cd cflash
makepkg -si
```
# Usage # Usage
- Using the command `cflash` in the terminal, will start the flashing process. You will be asked several question before the flashing begins: - Using the command `cflash` in the terminal, will start the flashing process. You will be asked several question before the flashing begins:

View File

@@ -1,4 +1,5 @@
package org.cametendo; package org.cametendo;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@@ -11,29 +12,31 @@ import org.jline.terminal.TerminalBuilder;
/** /**
* Handles file path input and validation for disk image files. * Handles file path input and validation for disk image files.
* * * <p>This class provides functionality to interactively prompt users for image file paths
* <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
* with tab completion support, validate that files exist and are regular files, and * to the user's home directory and validates that paths point to existing regular files.</p>
* validate file paths from command-line arguments.</p> * * @author Cametendo
* * @version 1.1
* @author Cametendo
* @version 1.0
*/ */
public class FilePathAdd { public class FilePathAdd {
/** /**
* Stores the validated path to the selected image file. * Stores the validated absolute path to the selected image file.
*/ */
public static String ImagePath = ""; 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. * Interactively prompts the user to select an image file path.
* * * <p>Uses JLine for enhanced terminal interaction with {@link FileNameCompleter}.
* <p>Uses JLine for enhanced terminal interaction with tab completion support. * The method expands the tilde (~) character if present at the start of the string
* Validates that the selected path points to an existing regular file.</p> * and validates that the resulting path is a regular file before returning.</p>
* * * @return The validated absolute path to the selected image file
* @return The validated path to the selected image file * @throws IOException If there are I/O errors during terminal setup or file resolution
* @throws IOException If there are I/O errors during terminal setup or file validation
*/ */
protected static String filePath() throws IOException { protected static String filePath() throws IOException {
fileQuestion(); fileQuestion();
@@ -42,37 +45,48 @@ public class FilePathAdd {
LineReader reader = LineReaderBuilder.builder().terminal(terminal).completer(new FileNameCompleter()).build(); LineReader reader = LineReaderBuilder.builder().terminal(terminal).completer(new FileNameCompleter()).build();
while (true) { while (true) {
ImagePath = reader.readLine("Path: ").trim(); String input = reader.readLine("Path: ").trim();
if (ImagePath.isBlank()) { if (input.isBlank()) {
System.out.println("Oops... You didn't specify a file!"); System.out.println("Oops... You didn't specify a file!");
continue; continue;
} }
Path path = Path.of(ImagePath); // 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)) { if (!Files.exists(path) || !Files.isRegularFile(path)) {
System.out.println("Invalid file! Please ensure the path points to an ISO / image file."); System.out.println("Invalid file! Please ensure the path points to an ISO / image file.");
continue; continue;
} }
// Convert to a real, absolute path and return
ImagePath = path.toRealPath().toString();
System.out.println("Using File: " + ImagePath); System.out.println("Using File: " + ImagePath);
return ImagePath; return ImagePath;
} }
} }
/** /**
* Validates and returns the full path to an image file. * 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
* <p>Takes a file path, validates that it exists and is a regular file, * tilde expansion and verifies file existence and type.</p>
* and returns the real path. Used for command-line argument validation.</p> * * @param inputPath Raw path string to validate
* * @return Full validated absolute path, or {@code null} if the path is invalid or inaccessible
* @param ImagePath Path to the image file to validate
* @return Full validated path to the file, or null if invalid
*/ */
public static String validateAndGetFile(String ImagePath) { public static String validateAndGetFile(String inputPath) {
if (inputPath == null) return null;
try { try {
Path path = Path.of(ImagePath); if (inputPath.startsWith("~")) {
inputPath = Home + inputPath.substring(1);
}
Path path = Path.of(inputPath);
if (Files.exists(path) && Files.isRegularFile(path)) { if (Files.exists(path) && Files.isRegularFile(path)) {
return path.toRealPath().toString(); return path.toRealPath().toString();
} else { } else {
@@ -86,10 +100,7 @@ public class FilePathAdd {
} }
/** /**
* Displays the prompt for file path input. * Displays the prompt for file path input to the standard output.
*
* <p>Informs the user that they should enter the full path to their ISO/image file
* and mentions that tab completion is supported for convenience.</p>
*/ */
protected static void fileQuestion() { protected static void fileQuestion() {
System.out.println("Please enter the FULL Path of your ISO / Image. (Tab-completion supported)"); System.out.println("Please enter the FULL Path of your ISO / Image. (Tab-completion supported)");

View File

@@ -0,0 +1 @@

View File

@@ -23,14 +23,5 @@ public class Greeting {
*/ */
public static void greeting(Scanner UserInput) { public static void greeting(Scanner UserInput) {
System.out.println("Welcome to cflash!"); System.out.println("Welcome to cflash!");
System.out.println("Would you like to flash an image (Y/n)");
String input = UserInput.nextLine();
if (YesNo.check(input)) {
System.out.println("Please choose the to be flashed device (f. e. sda)");
} else {
System.out.println("Canceling...");
System.exit(0);
}
} }
} }

View File

@@ -80,7 +80,9 @@ public class OSDetector {
osName = "Haiku OS"; osName = "Haiku OS";
} else if (fileName.contains("reactos")) { } else if (fileName.contains("reactos")) {
osName = "ReactOS"; osName = "ReactOS";
} } else if (fileName.contains("jgh")) {
osName = "JGH OS (Sauerkraut juice)";
}
// Generic Fallbacks // Generic Fallbacks
else if (fileName.contains("linux")) { else if (fileName.contains("linux")) {
osName = "Linux"; osName = "Linux";
@@ -90,6 +92,6 @@ public class OSDetector {
osName = "new OS"; osName = "new OS";
} }
System.out.println("\nFlash complete! Have fun with your " + osName + " installation! 🚀"); System.out.println("\nFlash complete! Have fun with your " + osName + " installation!");
} }
} }

View File

@@ -1,4 +1,5 @@
package org.cametendo; package org.cametendo;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@@ -7,99 +8,127 @@ import java.util.Scanner;
/** /**
* Handles storage device detection, listing, and validation for the flashing process. * 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.
* <p>This class provides functionality to list available storage devices using lsblk, * Keeps the user in the loop with a more personal touch.</p>
* validate device paths, and interactively prompt users to select a target device * * @author Cametendo
* for flashing operations.</p> * @version 1.1
*
* @author Cametendo
* @version 1.0
*/ */
public class StorageDeviceLister { public class StorageDeviceLister {
/**
* Stores the selected device name (without /dev/ prefix).
*/
public static String device = ""; public static String device = "";
/**
* Stores the full validated path to the selected device.
*/
public static String fullPath = ""; public static String fullPath = "";
/** /**
* Interactively prompts the user to select a storage device. * Guides the user through selecting a safe, unmounted storage device.
*
* <p>Displays a list of available storage devices using the lsblk command,
* then prompts the user to enter a device name. Validates the device path
* and continues prompting until a valid device is selected.</p>
*
* @param UserInput Scanner object for reading user input
* @return The full validated path to the selected device
*/ */
protected static String deviceCheck(Scanner UserInput) { protected static String deviceCheck(Scanner UserInput) {
deviceList(); deviceList();
while (true) { while (true) {
device = UserInput.nextLine(); System.out.print("Target device: ");
device = UserInput.nextLine().trim();
if (device.isBlank()) { if (device.isBlank()) {
System.out.println("Oops... Device name is empty. Did you missclick?"); System.out.println("Oops... Device name is empty. Did you missclick?");
continue; continue;
} }
Path path = Path.of("/dev/" + device);
// Standardize path - allows entering 'sda' or '/dev/sda'
String checkPath = device.startsWith("/dev/") ? device : "/dev/" + device;
Path path = Path.of(checkPath);
try { try {
fullPath = path.toRealPath().toString(); fullPath = path.toRealPath().toString();
System.out.println("Using device: " + fullPath); // 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; return fullPath;
} catch (IOException e) { } catch (IOException e) {
System.out.println("Failed to access device! Invalid path or no access. Please try again."); System.out.println("Hmm... I can't seem to find or access that device. Are you sure you have access to it?");
} }
} }
} }
/** /**
* Validates and returns the full path to a storage device. * Asks lsblk if the device or its children have an active mount point.
*
* <p>Takes a device name (without /dev/ prefix), constructs the full path,
* and validates that the device exists and is accessible. Used for command-line
* argument validation.</p>
*
* @param deviceName Device name without /dev/ prefix (e.g., "sda")
* @return Full validated path to the device, or null if invalid
*/ */
public static String validateAndGetPath(String deviceName) { private static boolean isMounted(String devicePath) {
try { try {
Path path = Path.of("/dev/" + deviceName); ProcessBuilder pb = new ProcessBuilder("lsblk", "-no", "MOUNTPOINT", devicePath);
return path.toRealPath().toString(); Process process = pb.start();
} catch (IOException e) {
System.out.println("Device not found. Invalid Path or no access."); try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
return null; 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;
} }
/** /**
* Displays a list of available storage devices using the lsblk command. * Lists devices with enough info for the user to make a smart decision.
*
* <p>Executes the lsblk command to show block devices and their properties,
* then prompts the user to enter a device name for selection.</p>
*/ */
private static void deviceList() { private static void deviceList() {
try { try {
ProcessBuilder pb = new ProcessBuilder("lsblk"); System.out.println("Scanning for block devices...");
ProcessBuilder pb = new ProcessBuilder("lsblk", "-o", "NAME,SIZE,TYPE,RM,MOUNTPOINT");
Process process = pb.start(); Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
System.out.println(line); System.out.println(line);
} }
process.waitFor(); process.waitFor();
System.out.println("Please enter the name of your device (without /dev/):");
System.out.println("Enter the name of your device (e.g., sdb or nvme1n1):");
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
e.printStackTrace(); System.out.println("Failed to run lsblk. Do you have it installed.");
}
}
/**
* Validates a device path (e.g., from a CLI argument).
* * <p>Checks if the device exists, resolves the real path, and ensures
* it isn't currently mounted before giving the green light.</p>
* * @param deviceName Device name (e.g., "sda" or "/dev/sda")
* @return Full validated path, or null if it's a bad idea to use it
*/
public static String validateAndGetPath(String deviceName) {
if (deviceName == null || deviceName.isBlank()) return null;
try {
// Support both "sda" and "/dev/sda"
String checkPath = deviceName.startsWith("/dev/") ? deviceName : "/dev/" + deviceName;
Path path = Path.of(checkPath);
String resolvedPath = path.toRealPath().toString();
// Safety check for CLI arguments too!
if (isMounted(resolvedPath)) {
System.out.println("Hold up! " + resolvedPath + " is mounted. I won't let you flash it like that.");
return null;
}
return resolvedPath;
} catch (IOException e) {
System.out.println("Hmm... I couldn't find a device at '" + deviceName + "'. Is it plugged in?");
return null;
} }
} }
} }