/* Copyright (c) 2026 The Solidite Developers
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. */
#include <bitset>
#include <filesystem>
#include <iostream>
#include <locale>
#include <string>
#include <sstream>
#include <vector>
#include <cstdint>
#include <cstring>
#include <sys/stat.h>
int main(int argc, char* argv[]) {
// locale work
std::locale::global(std::locale(""));
std::cout.imbue(std::locale());
std::wcout.imbue(std::locale());
std::cerr.imbue(std::locale());
std::wcerr.imbue(std::locale());
std::bitset<3> options = 0b001;
/* options[0]=process args? (-- not encountered), set to 0 if --
* options[1]=recursive (if -R then true)
* options[2]=mode found (if not found then error)
* reminder std::bitset initializes RTL so 001 sets [0] to true*/
std::vector<char*> files;
uint_fast16_t mode = 511;
// mode will get converted to octal
for (int i = 1; i < argc; ++i) {
if (options.test(0) == 0)
files.push_back(argv[i]);
else if (std::strcmp(argv[i], "--") == 0)
options.reset(0);
else if (options.test(1) == 0 && std::strcmp(argv[i], "-R") == 0)
options.set(1);
else if (options.test(2) == 0) {
try {
std::istringstream(argv[i]) >> std::oct >> mode;
} catch (...) {
std::cerr << "not an octal integer: " + std::string(argv[i]) + '\n';
return 1;
}
options.set(2);
} else
files.push_back(argv[i]);
}
for (char* file : files) {
try {
if (options.test(1) == 0) {
chmod(file, mode);
} else {
// loop through the files/folders recursively and chmod them
chmod(file, mode); // chmod the original directory
for (const std::filesystem::directory_entry& ENTRY :
std::filesystem::recursive_directory_iterator(file)) {
std::string what;
chmod(ENTRY.path().string().c_str(), mode); // chmod the subdirectories
}
}
} catch (...) {
std::cerr << "failed to change permissions: " + std::string(file) + '\n';
return 1;
}
}
return 0;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>