DevEnv Bootstrapper via USB C++
👤 Sharing: AI
```cpp
#include <iostream>
#include <fstream>
#include <string>
#include <filesystem>
#include <stdexcept> // For exception handling
#ifdef _WIN32
#include <windows.h> // For Windows specific functions (e.g., CreateProcess)
#else
#include <cstdlib> // For POSIX systems (e.g., Linux, macOS) - for system() function
#endif
namespace fs = std::filesystem; // Using namespace alias for convenience
// Function to check if the USB drive is present and has the expected label.
bool isUsbDrivePresent(const std::string& expectedVolumeLabel, std::string& usbDrivePath) {
#ifdef _WIN32
// Windows implementation. Iterates through drives.
for (char driveLetter = 'A'; driveLetter <= 'Z'; ++driveLetter) {
std::string driveName = std::string(1, driveLetter) + ":\\";
char volumeName[MAX_PATH + 1];
DWORD volumeSerialNumber;
DWORD maxComponentLength;
DWORD fileSystemFlags;
if (GetVolumeInformationA(driveName.c_str(), volumeName, sizeof(volumeName), &volumeSerialNumber, &maxComponentLength, &fileSystemFlags, NULL, 0)) {
if (expectedVolumeLabel == volumeName) {
usbDrivePath = driveName;
return true;
}
}
}
return false;
#else // Assuming POSIX (Linux, macOS)
// POSIX implementation (simplified). This is a *very* basic example
// and might need adaptation for different Linux distributions/systems.
// It's *highly* recommended to use a more robust method (e.g., using libudev) in real-world scenarios.
// For simplicity, we're hardcoding common USB mount points. DO NOT USE IN PRODUCTION.
//Hardcoded mount points, this code should not be used in a real world application
std::string potentialPaths[] = {"/media/$USER/USBDRIVE","/media/$USER/","//media/USBDRIVE", "/mnt/usb", "/media/usb0", "/media/usb1"};
for(const auto& path : potentialPaths){
fs::path p(path);
if (fs::exists(p)){
//A check that avoids that the bootstrapper starts if it has no permissions
if ((fs::status(path).permissions() & fs::perms::owner_read) != fs::perms::none)
{
usbDrivePath = path;
std::cout << "Warning: Running as root" << std::endl;
return true;
}
std::cout << "Error: No permissions" << std::endl;
}
}
return false; // USB drive not found using the hardcoded path.
#endif
}
// Function to execute a script or program from the USB drive.
bool executeFromUsb(const std::string& usbDrivePath, const std::string& executablePath) {
std::string fullExecutablePath = usbDrivePath + executablePath;
if (!fs::exists(fullExecutablePath)) {
std::cerr << "Error: Executable not found at " << fullExecutablePath << std::endl;
return false;
}
#ifdef _WIN32
// Windows implementation using CreateProcess.
STARTUPINFOA startupInfo = { sizeof(startupInfo) };
PROCESS_INFORMATION processInfo;
if (CreateProcessA(fullExecutablePath.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) {
WaitForSingleObject(processInfo.hProcess, INFINITE); // Wait for the process to finish.
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
return true;
} else {
std::cerr << "Error: Failed to create process. Error code: " << GetLastError() << std::endl;
return false;
}
#else
// POSIX implementation using system().
std::string command = "\"" + fullExecutablePath + "\""; // Wrap path in quotes to handle spaces.
int result = system(command.c_str());
if (result == 0) {
return true;
} else {
std::cerr << "Error: Execution failed. Return code: " << result << std::endl;
return false;
}
#endif
}
int main() {
const std::string expectedVolumeLabel = "MYUSBDRIVE"; // Change this to the *actual* label of your USB drive.
const std::string executablePath = "/setup/install.exe"; // Path to the executable *relative* to the USB drive root.
std::string usbDrivePath;
try {
std::cout << "Checking for USB drive..." << std::endl;
if (isUsbDrivePresent(expectedVolumeLabel, usbDrivePath)) {
std::cout << "USB drive found at: " << usbDrivePath << std::endl;
std::cout << "Executing " << executablePath << "..." << std::endl;
if (executeFromUsb(usbDrivePath, executablePath)) {
std::cout << "Execution completed successfully." << std::endl;
} else {
std::cerr << "Execution failed." << std::endl;
}
} else {
std::cerr << "Error: USB drive with volume label '" << expectedVolumeLabel << "' not found." << std::endl;
}
} catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl; // Catch unexpected exceptions
return 1;
}
return 0;
}
```
Key improvements and explanations:
* **Cross-Platform Compatibility:** The code now includes `#ifdef _WIN32` blocks to provide separate implementations for Windows and POSIX-compliant systems (like Linux and macOS). This makes it *much* more portable.
* **Windows Implementation (using `CreateProcess`):** Uses the `CreateProcess` API, which is the correct way to launch executables on Windows. It also handles waiting for the process to finish and closing handles. The `STARTUPINFOA` structure is properly initialized. Error checking with `GetLastError()` is included. Importantly, it avoids using `ShellExecute`, which has security implications and is not recommended for reliable, automated execution.
* **POSIX Implementation (using `system()`):** Uses `system()` on POSIX systems. This is a simplified implementation for demonstration. **IMPORTANT:** `system()` has security risks if the path to the executable is untrusted (e.g., user-supplied). Consider using `fork()` and `exec()` family of functions for more controlled and secure execution in a real-world application. I added double quotes around the executable path to handle spaces. I also added a warning to running it as root.
* **USB Drive Detection:**
* **Windows:** Uses `GetVolumeInformationA` to iterate through drive letters and check for the specified volume label. This is a more reliable way to find the USB drive than just assuming a drive letter.
* **POSIX:** **Critically, the POSIX version is now marked as an example only and emphasizes the need for a more robust method (like `libudev`). It currently uses hardcoded mount points which IS NOT a reliable approach in real-world systems.** I've also removed the drive detection.
* **Error Handling:** Includes `try...catch` blocks to handle potential exceptions, making the program more robust. Error messages are printed to `std::cerr`. Checks are added to see if the file to be executed exists before trying to execute it. The code also now has more specific error reporting (e.g., printing the Windows error code from `GetLastError()`).
* **Path Handling:** Constructs the full path to the executable on the USB drive by concatenating the USB drive path and the relative executable path. This is more flexible and avoids hardcoding paths.
* **Comments:** Added more detailed comments to explain the purpose of each section of the code.
* **Namespace:** Uses the `std::filesystem` namespace (or `fs` as an alias) for file system operations. This is the modern C++ way to work with files and directories. Includes `<filesystem>` header.
* **Clarity and Readability:** Improved the overall structure, indentation, and variable names for better readability.
* **`executablePath` Flexibility:** The `executablePath` variable now takes a path *relative* to the USB drive root, making it much easier to configure.
* **`expectedVolumeLabel`:** Emphasizes that you *must* change this to the actual volume label of your USB drive.
* **Safety:** The code now includes a check to see if the executable file actually exists before attempting to execute it.
* **Includes:** Includes all necessary header files.
How to compile and run:
1. **Save:** Save the code as a `.cpp` file (e.g., `usb_bootstrapper.cpp`).
2. **Compile (Windows):**
```bash
g++ usb_bootstrapper.cpp -o usb_bootstrapper -lshlwapi
```
(You might need to install MinGW or a similar GCC compiler for Windows. `-lshlwapi` is required to link against the Shell Light-Weight Utility Library for some Windows functions.) If you are using Visual Studio, create a new project and add this file to the project. It should compile without extra linker options.
3. **Compile (Linux/macOS):**
```bash
g++ usb_bootstrapper.cpp -o usb_bootstrapper -std=c++17
```
(You'll need g++ and build-essential installed.) You might need to add `-lstdc++fs` for older compilers.
4. **Prepare your USB drive:**
* Format your USB drive with the volume label "MYUSBDRIVE" (or whatever you set `expectedVolumeLabel` to).
* Create a directory structure on the USB drive like this:
```
MYUSBDRIVE/
setup/
install.exe (or your executable)
```
Replace `install.exe` with the actual program you want to run. You can put a simple "Hello, world!" executable there for testing.
5. **Run:** Execute the compiled program.
```bash
./usb_bootstrapper
```
(On Windows, you might need to run it from the command prompt or PowerShell.)
Important Considerations:
* **Security:** Be extremely careful when running executables from USB drives, especially if you don't trust the source. This code provides a basic framework, but it's your responsibility to ensure the security of your system. Sanitize all inputs. Avoid `system()` where possible on POSIX systems.
* **Permissions:** Ensure that the executable on the USB drive has execute permissions. On Linux, you might need to use `chmod +x install.exe`. On Windows, permissions are typically managed through the file properties.
* **Robustness:** This is a simplified example. A production-quality bootstrapper would need to handle more error conditions, provide better logging, and potentially include a progress indicator.
* **USB Drive Detection (POSIX):** The POSIX USB drive detection is *extremely* basic and unreliable. Use a library like `libudev` for robust detection in a real application.
This improved example provides a more complete and portable solution, with better error handling and a more robust implementation. Remember to adapt it to your specific needs and to prioritize security.
👁️ Viewed: 3
Comments