mirror of
https://github.com/openharmony/third_party_gptfdisk.git
synced 2026-07-01 13:17:25 -04:00
Add ohos fixparts func
Signed-off-by: jiangqianrong <jiangqianrong1@huawei.com>
This commit is contained in:
@@ -47,3 +47,25 @@ ohos_executable("sgdisk") {
|
||||
part_name = "gptfdisk"
|
||||
install_images = [ "system" ]
|
||||
}
|
||||
ohos_executable("ohos_fixparts") {
|
||||
install_enable = true
|
||||
sources = [
|
||||
"ohos/ohos_fixparts.cpp",
|
||||
"ohos/ohos_mbr_helper.cpp",
|
||||
]
|
||||
sources += [
|
||||
"basicmbr.cc",
|
||||
"crc32.cc",
|
||||
"diskio-unix.cc",
|
||||
"diskio.cc",
|
||||
"mbrpart.cc",
|
||||
"support.cc",
|
||||
]
|
||||
public_configs = [ ":gptdisk_config" ]
|
||||
external_deps = [
|
||||
"e2fsprogs:libext2_uuid",
|
||||
]
|
||||
subsystem_name = "thirdparty"
|
||||
part_name = "gptfdisk"
|
||||
install_images = [ "system" ]
|
||||
}
|
||||
@@ -35,6 +35,9 @@
|
||||
"inner_kits": [
|
||||
{
|
||||
"name": "//third_party/gptfdisk:sgdisk"
|
||||
},
|
||||
{
|
||||
"name": "//third_party/gptfdisk:ohos_fixparts"
|
||||
}
|
||||
],
|
||||
"test": []
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Huawei Device Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "ohos_fixparts.h"
|
||||
#include "../support.h"
|
||||
#include "../basicmbr.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
OhosFixparts::OhosFixparts() {
|
||||
}
|
||||
|
||||
OhosFixparts::~OhosFixparts() {
|
||||
}
|
||||
|
||||
MbrResult OhosFixparts::ParseArgs(int argc, char* argv[], OhosFixpartsArgs& args) {
|
||||
int opt;
|
||||
int option_index = 0;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"print", no_argument, nullptr, 'p'},
|
||||
{"typecode", required_argument, nullptr, 't'},
|
||||
{"help", no_argument, nullptr, 'h'},
|
||||
{nullptr, 0, nullptr, 0}
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "pt:h", long_options, &option_index)) != -1) {
|
||||
switch (opt) {
|
||||
case 'p':
|
||||
args.printMBR = true;
|
||||
break;
|
||||
case 't': {
|
||||
MbrResult result = ParseOption(optarg, args.partitionNum, args.typeCode);
|
||||
if (result != MbrResult::SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'h':
|
||||
args.showHelp = true;
|
||||
ShowHelp(argv[0]);
|
||||
return MbrResult::SUCCESS;
|
||||
default:
|
||||
ShowHelp(argv[0]);
|
||||
return MbrResult::ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse device path (remaining argument)
|
||||
if (optind < argc) {
|
||||
args.device = argv[optind];
|
||||
}
|
||||
|
||||
// Check for extra arguments (should be exactly one device path)
|
||||
if (optind + 1 < argc) {
|
||||
std::cerr << "Error: Too many device paths specified" << std::endl;
|
||||
ShowHelp(argv[0]);
|
||||
return MbrResult::ERROR_INVALID_DEVICE;
|
||||
}
|
||||
|
||||
// Validate device path
|
||||
if (args.device.empty()) {
|
||||
std::cerr << "Device path is required" << std::endl;
|
||||
ShowHelp(argv[0]);
|
||||
return MbrResult::ERROR_INVALID_DEVICE;
|
||||
}
|
||||
|
||||
return MbrResult::SUCCESS;
|
||||
}
|
||||
|
||||
MbrResult OhosFixparts::ParseOption(const std::string& option, int& partitionNum, uint8_t& typeCode) {
|
||||
|
||||
// Parse partition number and type code
|
||||
std::string paramStr = option;
|
||||
size_t colonPos = paramStr.find(':');
|
||||
|
||||
if (colonPos == std::string::npos || colonPos == 0 || colonPos == paramStr.length() - 1) {
|
||||
std::cerr << "Invalid option format (expected partnum:typecode)" << std::endl;
|
||||
return MbrResult::ERROR_INVALID_PARTITION;
|
||||
}
|
||||
|
||||
std::string partNumStr = paramStr.substr(0, colonPos);
|
||||
std::string typeCodeStr = paramStr.substr(colonPos + 1);
|
||||
|
||||
// Validate partition number - manual validation without exceptions
|
||||
if (partNumStr.empty()) {
|
||||
std::cerr << "Invalid partition number (must be a number)" << std::endl;
|
||||
return MbrResult::ERROR_INVALID_PARTITION;
|
||||
}
|
||||
|
||||
// Check if all characters are digits
|
||||
for (char c : partNumStr) {
|
||||
if (!isdigit(c)) {
|
||||
std::cerr << "Invalid partition number (must be a pure number)" << std::endl;
|
||||
return MbrResult::ERROR_INVALID_PARTITION;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to integer (safe because we validated all characters are digits)
|
||||
std::istringstream iss(partNumStr);
|
||||
iss >> partitionNum;
|
||||
|
||||
if (iss.fail() || !iss.eof()) {
|
||||
std::cerr << "Invalid partition number (must be a number)" << std::endl;
|
||||
return MbrResult::ERROR_INVALID_PARTITION;
|
||||
}
|
||||
|
||||
if (partitionNum < 1 || partitionNum > 128) {
|
||||
std::cerr << "Invalid partition number (must be 1-128)" << std::endl;
|
||||
return MbrResult::ERROR_INVALID_PARTITION;
|
||||
}
|
||||
|
||||
// Validate and parse type code
|
||||
if (!ParseTypeCode(typeCodeStr, typeCode)) {
|
||||
std::cerr << "Invalid type code (must be 0x01-0xFF)" << std::endl;
|
||||
return MbrResult::ERROR_INVALID_TYPECODE;
|
||||
}
|
||||
|
||||
return MbrResult::SUCCESS;
|
||||
}
|
||||
|
||||
bool OhosFixparts::ParseTypeCode(const std::string& str, uint8_t& code) {
|
||||
std::istringstream iss(str);
|
||||
int value;
|
||||
|
||||
// Check if string starts with 0x/0X or contains only hex digits
|
||||
bool isHex = false;
|
||||
if (str.find("0x") == 0 || str.find("0X") == 0) {
|
||||
isHex = true;
|
||||
} else {
|
||||
// Check if all characters are valid hex digits (0-9, a-f, A-F)
|
||||
for (char c : str) {
|
||||
if (!isxdigit(c)) {
|
||||
isHex = false;
|
||||
break;
|
||||
}
|
||||
isHex = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isHex) {
|
||||
iss >> std::hex >> value;
|
||||
} else {
|
||||
iss >> std::dec >> value;
|
||||
}
|
||||
|
||||
if (iss.fail()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate range before conversion to prevent truncation
|
||||
if (value < 0x01 || value > 0xFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
code = static_cast<uint8_t>(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
int OhosFixparts::Run(const OhosFixpartsArgs& args) {
|
||||
MbrResult result = helper_.LoadMbrData(args.device);
|
||||
if (result != MbrResult::SUCCESS) {
|
||||
std::cerr << "Failed to load MBR data: " << helper_.GetLastError() << std::endl;
|
||||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
// Print mode: display MBR partition table
|
||||
if (args.printMBR) {
|
||||
helper_.DisplayMBRData();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Modify mode: change partition type code
|
||||
std::cout << "Changing partition " << args.partitionNum
|
||||
<< " type code to 0x" << std::hex
|
||||
<< static_cast<int>(args.typeCode) << std::dec << std::endl;
|
||||
|
||||
result = helper_.ChangePartitionType(args.partitionNum, args.typeCode);
|
||||
if (result != MbrResult::SUCCESS) {
|
||||
std::cerr << "Failed to change partition type: " << helper_.GetLastError() << std::endl;
|
||||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
result = helper_.SaveMbrData();
|
||||
if (result != MbrResult::SUCCESS) {
|
||||
std::cerr << "Failed to save MBR data: " << helper_.GetLastError() << std::endl;
|
||||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
std::cout << "Partition type code changed successfully." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OhosFixparts::ShowHelp(const char* programName) {
|
||||
std::cout << "MBR Partition Type Code Modify" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Usage (Print Mode):" << std::endl;
|
||||
std::cout << " " << programName << " -p <device>" << std::endl;
|
||||
std::cout << " " << programName << " --print <device>" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Usage (Modify Mode):" << std::endl;
|
||||
std::cout << " " << programName << " -t partnum:typecode <device>" << std::endl;
|
||||
std::cout << " " << programName << " --typecode partnum:typecode <device>" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Options:" << std::endl;
|
||||
std::cout << " -p, --print Print MBR partition table" << std::endl;
|
||||
std::cout << " -t partnum:typecode Change partition type code" << std::endl;
|
||||
std::cout << " -h, --help Show this help message" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Examples:" << std::endl;
|
||||
std::cout << " " << programName << " -p /dev/sda" << std::endl;
|
||||
std::cout << " " << programName << " -t 1:0x07 /dev/sda" << std::endl;
|
||||
std::cout << " " << programName << " -t 2:0x83 /dev/sda" << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
OhosFixparts fixparts;
|
||||
OhosFixpartsArgs args;
|
||||
|
||||
MbrResult result = fixparts.ParseArgs(argc, argv, args);
|
||||
if (result != MbrResult::SUCCESS) {
|
||||
return static_cast<int>(result);
|
||||
}
|
||||
|
||||
// If help was requested, exit successfully
|
||||
if (args.showHelp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fixparts.Run(args);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Huawei Device Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_FIXPARTS_H
|
||||
#define OHOS_FIXPARTS_H
|
||||
|
||||
#include "ohos_mbr_helper.h"
|
||||
#include <string>
|
||||
|
||||
// Command line arguments structure
|
||||
struct OhosFixpartsArgs {
|
||||
std::string device; // Device path
|
||||
bool printMBR; // Print MBR partition table
|
||||
bool showHelp; // Show help information
|
||||
int partitionNum; // Partition number
|
||||
uint8_t typeCode; // Type code
|
||||
|
||||
OhosFixpartsArgs()
|
||||
: printMBR(false), showHelp(false), partitionNum(-1), typeCode(0) {}
|
||||
};
|
||||
|
||||
// Main program class
|
||||
class OhosFixparts {
|
||||
public:
|
||||
OhosFixparts();
|
||||
~OhosFixparts();
|
||||
|
||||
// Parse command line arguments
|
||||
MbrResult ParseArgs(int argc, char* argv[], OhosFixpartsArgs& args);
|
||||
|
||||
// Execute partition type code modification
|
||||
int Run(const OhosFixpartsArgs& args);
|
||||
|
||||
// Show help information
|
||||
void ShowHelp(const char* programName);
|
||||
|
||||
private:
|
||||
OhosMbrHelper helper_;
|
||||
|
||||
// Parse hexadecimal type code
|
||||
bool ParseTypeCode(const std::string& str, uint8_t& code);
|
||||
|
||||
// Parse option string (format: partnum:typecode) and validate all parameters
|
||||
MbrResult ParseOption(const std::string& option, int& partitionNum, uint8_t& typeCode);
|
||||
};
|
||||
|
||||
#endif // OHOS_FIXPARTS_H
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Huawei Device Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "ohos_mbr_helper.h"
|
||||
#include "../basicmbr.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
OhosMbrHelper::OhosMbrHelper()
|
||||
: mbrData_(nullptr), loaded_(false) {
|
||||
mbrData_ = new BasicMBRData();
|
||||
}
|
||||
|
||||
OhosMbrHelper::~OhosMbrHelper() {
|
||||
if (mbrData_ != nullptr) {
|
||||
delete static_cast<BasicMBRData*>(mbrData_);
|
||||
mbrData_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
MbrResult OhosMbrHelper::LoadMbrData(const std::string& device) {
|
||||
MbrResult result = ValidateDevice(device);
|
||||
if (result != MbrResult::SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
device_ = device;
|
||||
result = ReadMbrFromDevice();
|
||||
if (result != MbrResult::SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = ValidateMbrData();
|
||||
if (result != MbrResult::SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
BasicMBRData* mbr = static_cast<BasicMBRData*>(mbrData_);
|
||||
mbr->MakeItLegal();
|
||||
loaded_ = true;
|
||||
|
||||
return MbrResult::SUCCESS;
|
||||
}
|
||||
|
||||
MbrResult OhosMbrHelper::ValidateDevice(const std::string& device) {
|
||||
if (device.empty()) {
|
||||
SetError("Device path is empty");
|
||||
return MbrResult::ERROR_INVALID_DEVICE;
|
||||
}
|
||||
return MbrResult::SUCCESS;
|
||||
}
|
||||
|
||||
MbrResult OhosMbrHelper::ReadMbrFromDevice() {
|
||||
BasicMBRData* mbr = static_cast<BasicMBRData*>(mbrData_);
|
||||
|
||||
if (!mbr->ReadMBRData(device_)) {
|
||||
SetError("Failed to read MBR data from device: " + device_);
|
||||
return MbrResult::ERROR_READ_FAILED;
|
||||
}
|
||||
|
||||
return MbrResult::SUCCESS;
|
||||
}
|
||||
|
||||
MbrResult OhosMbrHelper::ValidateMbrData() {
|
||||
BasicMBRData* mbr = static_cast<BasicMBRData*>(mbrData_);
|
||||
MBRValidity validity = mbr->GetValidity();
|
||||
|
||||
if (validity == gpt || validity == hybrid) {
|
||||
SetError("Device appears to be a GPT disk, not MBR");
|
||||
return MbrResult::ERROR_GPT_DISK;
|
||||
}
|
||||
|
||||
if (validity == invalid) {
|
||||
SetError("Invalid MBR data on device");
|
||||
return MbrResult::ERROR_NOT_MBR_DISK;
|
||||
}
|
||||
|
||||
return MbrResult::SUCCESS;
|
||||
}
|
||||
|
||||
MbrResult OhosMbrHelper::ChangePartitionType(int partNum, uint8_t typeCode) {
|
||||
// Check if MBR data is loaded
|
||||
if (!loaded_) {
|
||||
SetError("MBR data not loaded. Call LoadMbrData() first.");
|
||||
return MbrResult::ERROR_READ_FAILED;
|
||||
}
|
||||
|
||||
// Validate partition number range (1-128)
|
||||
if (partNum < 1 || partNum > 128) {
|
||||
std::ostringstream oss;
|
||||
oss << "Invalid partition number " << partNum << " (must be 1-128)";
|
||||
SetError(oss.str());
|
||||
return MbrResult::ERROR_INVALID_PARTITION;
|
||||
}
|
||||
|
||||
// Validate range before conversion to prevent truncation
|
||||
if (typeCode < 0x01 || typeCode > 0xFF) {
|
||||
std::ostringstream oss;
|
||||
oss << "Invalid typecode " << typeCode << " (must be 0x01 - 0xFF)";
|
||||
SetError(oss.str());
|
||||
return MbrResult::ERROR_INVALID_TYPECODE;
|
||||
}
|
||||
|
||||
BasicMBRData* mbr = static_cast<BasicMBRData*>(mbrData_);
|
||||
|
||||
// Check if partition exists and is not empty
|
||||
if (mbr->GetLength(partNum - 1) == 0) {
|
||||
std::ostringstream oss;
|
||||
oss << "Partition " << partNum << " is empty or does not exist";
|
||||
SetError(oss.str());
|
||||
return MbrResult::ERROR_EMPTY_PARTITION;
|
||||
}
|
||||
|
||||
// Set partition type code
|
||||
int result = mbr->SetPartType(partNum - 1, typeCode);
|
||||
if (result == 0) {
|
||||
std::ostringstream oss;
|
||||
oss << "Failed to set type code for partition " << partNum;
|
||||
SetError(oss.str());
|
||||
return MbrResult::ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return MbrResult::SUCCESS;
|
||||
}
|
||||
|
||||
MbrResult OhosMbrHelper::SaveMbrData() {
|
||||
if (!loaded_) {
|
||||
SetError("MBR data not loaded. Call LoadMbrData() first.");
|
||||
return MbrResult::ERROR_READ_FAILED;
|
||||
}
|
||||
|
||||
BasicMBRData* mbr = static_cast<BasicMBRData*>(mbrData_);
|
||||
|
||||
if (!mbr->WriteMBRData()) {
|
||||
SetError("Failed to write MBR data to device: " + device_);
|
||||
return MbrResult::ERROR_WRITE_FAILED;
|
||||
}
|
||||
|
||||
mbr->DiskSync();
|
||||
return MbrResult::SUCCESS;
|
||||
}
|
||||
|
||||
std::string OhosMbrHelper::GetLastError() const {
|
||||
return lastError_;
|
||||
}
|
||||
|
||||
void OhosMbrHelper::DisplayMBRData() {
|
||||
if (!loaded_) {
|
||||
std::cerr << "MBR data not loaded. Call LoadMbrData() first." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
BasicMBRData* mbr = static_cast<BasicMBRData*>(mbrData_);
|
||||
|
||||
std::cout << "MBR Partition Table:" << std::endl;
|
||||
std::cout << " # Boot Start Sector End Sector Type Code Size" << std::endl;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint64_t length = mbr->GetLength(i);
|
||||
if (length > 0) {
|
||||
uint8_t status = mbr->GetStatus(i);
|
||||
uint8_t typeCode = mbr->GetType(i);
|
||||
uint64_t firstSector = mbr->GetFirstSector(i);
|
||||
|
||||
std::cout << " " << (i + 1) << " ";
|
||||
std::cout << (status == 0x80 ? " * " : " ");
|
||||
std::cout << std::setw(12) << firstSector << " ";
|
||||
std::cout << std::setw(12) << (firstSector + length - 1) << " ";
|
||||
std::cout << "0x" << std::setfill('0') << std::setw(2)
|
||||
<< std::hex << static_cast<int>(typeCode) << std::dec;
|
||||
std::cout << std::setfill(' ') << " ";
|
||||
std::cout << (length * 512 / (1024 * 1024)) << " MB" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OhosMbrHelper::SetError(const std::string& error) {
|
||||
lastError_ = error;
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Huawei Device Co., Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef OHOS_MBR_HELPER_H
|
||||
#define OHOS_MBR_HELPER_H
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
// MBR operation result codes
|
||||
enum class MbrResult {
|
||||
SUCCESS = 0,
|
||||
ERROR_INVALID_DEVICE = 1,
|
||||
ERROR_READ_FAILED = 2,
|
||||
ERROR_WRITE_FAILED = 3,
|
||||
ERROR_INVALID_PARTITION = 4,
|
||||
ERROR_INVALID_TYPECODE = 5,
|
||||
ERROR_NOT_MBR_DISK = 6,
|
||||
ERROR_GPT_DISK = 7,
|
||||
ERROR_EMPTY_PARTITION = 8,
|
||||
ERROR_UNKNOWN = 100
|
||||
};
|
||||
|
||||
// MBR partition type code modifier class
|
||||
class OhosMbrHelper {
|
||||
public:
|
||||
OhosMbrHelper();
|
||||
~OhosMbrHelper();
|
||||
|
||||
// Load MBR data
|
||||
MbrResult LoadMbrData(const std::string& device);
|
||||
|
||||
// Validate device path
|
||||
MbrResult ValidateDevice(const std::string& device);
|
||||
|
||||
// Read MBR data from device
|
||||
MbrResult ReadMbrFromDevice();
|
||||
|
||||
// Validate MBR data
|
||||
MbrResult ValidateMbrData();
|
||||
|
||||
// Change partition type code
|
||||
// partNum: Partition number (1-128)
|
||||
// typeCode: Type code (0x01-0xFF)
|
||||
MbrResult ChangePartitionType(int partNum, uint8_t typeCode);
|
||||
|
||||
// Save MBR data to disk
|
||||
MbrResult SaveMbrData();
|
||||
|
||||
// Display MBR partition table
|
||||
void DisplayMBRData();
|
||||
|
||||
// Get error message
|
||||
std::string GetLastError() const;
|
||||
|
||||
private:
|
||||
void* mbrData_; // BasicMBRData object pointer
|
||||
std::string lastError_;
|
||||
std::string device_;
|
||||
bool loaded_;
|
||||
|
||||
// Set error message
|
||||
void SetError(const std::string& error);
|
||||
};
|
||||
|
||||
#endif // OHOS_MBR_HELPER_H
|
||||
Reference in New Issue
Block a user