system/FmtError: new library

Replaces the Format*() functions in system/Error.hxx.
This commit is contained in:
Max Kellermann 2022-11-28 18:49:35 +01:00
parent 124e75c286
commit 96ae659fdf
25 changed files with 305 additions and 186 deletions

View File

@ -21,6 +21,7 @@
#include "LogInit.hxx"
#include "LogBackend.hxx"
#include "Log.hxx"
#include "lib/fmt/PathFormatter.hxx"
#include "config/Param.hxx"
#include "config/Data.hxx"
#include "config/Option.hxx"
@ -29,7 +30,7 @@
#include "util/Domain.hxx"
#include "util/RuntimeError.hxx"
#include "util/StringAPI.hxx"
#include "system/Error.hxx"
#include "system/FmtError.hxx"
#include <cassert>
@ -82,10 +83,8 @@ log_init_file(int line)
throw FormatRuntimeError("failed to open log file \"%s\" (config line %d)",
out_path_utf8.c_str(), line);
#else
int e = errno;
const std::string out_path_utf8 = out_path.ToUTF8();
throw FormatErrno(e, "failed to open log file \"%s\" (config line %d)",
out_path_utf8.c_str(), line);
throw FmtErrno("failed to open log file \"{}\" (config line {})",
out_path, line);
#endif
}
@ -242,10 +241,9 @@ cycle_log_files() noexcept
fd = open_log_file();
if (fd < 0) {
const std::string out_path_utf8 = out_path.ToUTF8();
FmtError(log_domain,
"error re-opening log file: {}",
out_path_utf8);
out_path);
return -1;
}

View File

@ -136,8 +136,8 @@ ZzipArchiveFile::OpenStream(const char *pathname,
const auto error = (zzip_error_t)zzip_error(dir->dir);
switch (error) {
case ZZIP_ENOENT:
throw FormatFileNotFound("Failed to open '%s' in ZIP file",
pathname);
throw FmtFileNotFound("Failed to open '{}' in ZIP file",
pathname);
default:
throw FormatRuntimeError("Failed to open '%s' in ZIP file: %s",

View File

@ -22,6 +22,7 @@
#include "Param.hxx"
#include "Block.hxx"
#include "Templates.hxx"
#include "lib/fmt/PathFormatter.hxx"
#include "system/Error.hxx"
#include "util/Tokenizer.hxx"
#include "util/StringStrip.hxx"
@ -236,9 +237,8 @@ void
ReadConfigFile(ConfigData &config_data, Path path)
{
assert(!path.IsNull());
const std::string path_utf8 = path.ToUTF8();
FmtDebug(config_file_domain, "loading file {}", path_utf8);
FmtDebug(config_file_domain, "loading file {}", path);
FileReader file(path);
@ -247,6 +247,7 @@ ReadConfigFile(ConfigData &config_data, Path path)
try {
ReadConfigFile(config_data, reader, path.GetDirectoryName());
} catch (...) {
const std::string path_utf8 = path.ToUTF8();
std::throw_with_nested(FormatRuntimeError("Error in %s line %u",
path_utf8.c_str(),
reader.GetLineNumber()));

View File

@ -33,12 +33,14 @@
#include "DatabaseSave.hxx"
#include "db/DatabaseLock.hxx"
#include "db/DatabaseError.hxx"
#include "lib/fmt/PathFormatter.hxx"
#include "fs/io/TextFile.hxx"
#include "io/BufferedOutputStream.hxx"
#include "io/FileOutputStream.hxx"
#include "fs/FileInfo.hxx"
#include "config/Block.hxx"
#include "fs/FileSystem.hxx"
#include "system/FmtError.hxx"
#include "util/CharUtil.hxx"
#include "util/Domain.hxx"
#include "util/RecursiveMap.hxx"
@ -119,12 +121,8 @@ SimpleDatabase::Check() const
#ifndef _WIN32
/* Check if we can write to the directory */
if (!CheckAccess(dirPath, X_OK | W_OK)) {
const int e = errno;
const std::string dirPath_utf8 = dirPath.ToUTF8();
throw FormatErrno(e, "Can't create db file in \"%s\"",
dirPath_utf8.c_str());
}
if (!CheckAccess(dirPath, X_OK | W_OK))
throw FmtErrno("Can't create db file in \"{}\"", dirPath);
#endif
return;
@ -139,8 +137,8 @@ SimpleDatabase::Check() const
#ifndef _WIN32
/* And check that we can write to it */
if (!CheckAccess(path, R_OK | W_OK))
throw FormatErrno("Can't open db file \"%s\" for reading/writing",
path_utf8.c_str());
throw FmtErrno("Can't open db file \"{}\" for reading/writing",
path);
#endif
}

View File

@ -31,7 +31,7 @@
*/
#include "InotifyEvent.hxx"
#include "system/Error.hxx"
#include "system/FmtError.hxx"
#include "io/UniqueFileDescriptor.hxx"
#include <array>
@ -68,7 +68,7 @@ InotifyEvent::AddWatch(const char *pathname, uint32_t mask)
int wd = inotify_add_watch(event.GetFileDescriptor().Get(),
pathname, mask);
if (wd < 0)
throw FormatErrno("inotify_add_watch('%s') failed", pathname);
throw FmtErrno("inotify_add_watch('{}') failed", pathname);
return wd;
}

View File

@ -18,7 +18,8 @@
*/
#include "DirectoryReader.hxx"
#include "system/Error.hxx"
#include "lib/fmt/PathFormatter.hxx"
#include "system/FmtError.hxx"
#ifdef _WIN32
@ -28,7 +29,7 @@ DirectoryReader::DirectoryReader(Path dir)
:handle(FindFirstFile(MakeWildcardPath(dir.c_str()), &data))
{
if (handle == INVALID_HANDLE_VALUE)
throw FormatLastError("Failed to open %s", dir.c_str());
throw FmtLastError("Failed to open {}", dir);
}
#else
@ -37,7 +38,7 @@ DirectoryReader::DirectoryReader(Path dir)
:dirp(opendir(dir.c_str()))
{
if (dirp == nullptr)
throw FormatErrno("Failed to open %s", dir.c_str());
throw FmtErrno("Failed to open {}", dir);
}
#endif

View File

@ -21,7 +21,8 @@
#define MPD_FS_FILE_INFO_HXX
#include "Path.hxx"
#include "system/Error.hxx"
#include "lib/fmt/PathFormatter.hxx"
#include "system/FmtError.hxx"
#ifdef _WIN32
#include "time/FileTime.hxx"
@ -49,11 +50,9 @@ public:
FileInfo(Path path, bool follow_symlinks=true) {
if (!GetFileInfo(path, *this, follow_symlinks)) {
#ifdef _WIN32
throw FormatLastError("Failed to access %s",
path.ToUTF8().c_str());
throw FmtLastError("Failed to access {}", path);
#else
throw FormatErrno("Failed to access %s",
path.ToUTF8().c_str());
throw FmtErrno("Failed to access {}", path);
#endif
}
}

View File

@ -20,7 +20,8 @@
#include "FileSystem.hxx"
#include "AllocatedPath.hxx"
#include "Limits.hxx"
#include "system/Error.hxx"
#include "lib/fmt/PathFormatter.hxx"
#include "system/FmtError.hxx"
#ifdef _WIN32
#include <handleapi.h> // for CloseHandle()
@ -73,13 +74,13 @@ TruncateFile(Path path)
TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr);
if (h == INVALID_HANDLE_VALUE)
throw FormatLastError("Failed to truncate %s", path.c_str());
throw FmtLastError("Failed to truncate {}", path);
CloseHandle(h);
#else
UniqueFileDescriptor fd;
if (!fd.Open(path.c_str(), O_WRONLY|O_TRUNC))
throw FormatErrno("Failed to truncate %s", path.c_str());
throw FmtErrno("Failed to truncate {}", path);
#endif
}
@ -88,9 +89,9 @@ RemoveFile(Path path)
{
#ifdef _WIN32
if (!DeleteFile(path.c_str()))
throw FormatLastError("Failed to delete %s", path.c_str());
throw FmtLastError("Failed to delete {}", path);
#else
if (unlink(path.c_str()) < 0)
throw FormatErrno("Failed to delete %s", path.c_str());
throw FmtErrno("Failed to delete {}", path);
#endif
}

View File

@ -21,7 +21,7 @@
#include "../AsyncInputStream.hxx"
#include "event/Call.hxx"
#include "event/Loop.hxx"
#include "system/Error.hxx"
#include "system/FmtError.hxx"
#include "io/Open.hxx"
#include "io/UniqueFileDescriptor.hxx"
#include "io/uring/ReadOperation.hxx"
@ -188,7 +188,7 @@ OpenUringInputStream(const char *path, Mutex &mutex)
// TODO: use IORING_OP_STATX
struct stat st;
if (fstat(fd.Get(), &st) < 0)
throw FormatErrno("Failed to access %s", path);
throw FmtErrno("Failed to access {}", path);
if (!S_ISREG(st.st_mode))
throw FormatRuntimeError("Not a regular file: %s", path);

View File

@ -28,7 +28,8 @@
*/
#include "FileOutputStream.hxx"
#include "system/Error.hxx"
#include "lib/fmt/PathFormatter.hxx"
#include "system/FmtError.hxx"
#include "util/StringFormat.hxx"
#ifdef _WIN32
@ -106,8 +107,7 @@ FileOutputStream::OpenCreate(bool visible)
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
nullptr);
if (!IsDefined())
throw FormatLastError("Failed to create %s",
path.ToUTF8().c_str());
throw FmtLastError("Failed to create {}", path);
}
inline void
@ -118,14 +118,12 @@ FileOutputStream::OpenAppend(bool create)
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
nullptr);
if (!IsDefined())
throw FormatLastError("Failed to append to %s",
path.ToUTF8().c_str());
throw FmtLastError("Failed to append to {}", path);
if (!SeekEOF()) {
auto code = GetLastError();
Close();
throw FormatLastError(code, "Failed seek end-of-file of %s",
path.ToUTF8().c_str());
throw FmtLastError(code, "Failed seek end-of-file of {}", path);
}
}
@ -148,12 +146,12 @@ FileOutputStream::Write(const void *data, size_t size)
DWORD nbytes;
if (!WriteFile(handle, data, size, &nbytes, nullptr))
throw FormatLastError("Failed to write to %s",
GetPath().c_str());
throw FmtLastError("Failed to write to {}", GetPath());
if (size_t(nbytes) != size)
throw FormatLastError(ERROR_DISK_FULL, "Failed to write to %s",
GetPath().c_str());
throw FmtLastError(DWORD{ERROR_DISK_FULL},
"Failed to write to {}",
GetPath());
}
void
@ -162,7 +160,7 @@ FileOutputStream::Sync()
assert(IsDefined());
if (!FlushFileBuffers(handle))
throw FormatLastError("Failed to sync %s", GetPath().c_str());
throw FmtLastError("Failed to sync {}", GetPath());
}
void
@ -249,8 +247,7 @@ FileOutputStream::OpenCreate([[maybe_unused]] bool visible)
GetPath().c_str(),
O_WRONLY|O_CREAT|O_TRUNC,
0666))
throw FormatErrno("Failed to create %s",
GetPath().c_str());
throw FmtErrno("Failed to create {}", GetPath());
}
inline void
@ -265,8 +262,7 @@ FileOutputStream::OpenAppend(bool create)
directory_fd,
#endif
path.c_str(), flags))
throw FormatErrno("Failed to append to %s",
path.c_str());
throw FmtErrno("Failed to append to {}", path);
}
uint64_t
@ -282,10 +278,9 @@ FileOutputStream::Write(const void *data, size_t size)
ssize_t nbytes = fd.Write(data, size);
if (nbytes < 0)
throw FormatErrno("Failed to write to %s", GetPath().c_str());
throw FmtErrno("Failed to write to {}", GetPath());
else if ((size_t)nbytes < size)
throw FormatErrno(ENOSPC, "Failed to write to %s",
GetPath().c_str());
throw FmtErrno(ENOSPC, "Failed to write to {}", GetPath());
}
void
@ -299,7 +294,7 @@ FileOutputStream::Sync()
const bool success = fsync(fd.Get()) == 0;
#endif
if (!success)
throw FormatErrno("Failed to sync %s", GetPath().c_str());
throw FmtErrno("Failed to sync {}", GetPath());
}
void
@ -316,13 +311,12 @@ try {
StringFormat<64>("/proc/self/fd/%d", fd.Get()),
directory_fd.Get(), path.c_str(),
AT_SYMLINK_FOLLOW) < 0)
throw FormatErrno("Failed to commit %s",
path.c_str());
throw FmtErrno("Failed to commit {}", path);
}
#endif
if (!Close()) {
throw FormatErrno("Failed to commit %s", path.c_str());
throw FmtErrno("Failed to commit {}", path);
}
if (tmp_path != nullptr)

View File

@ -28,8 +28,9 @@
*/
#include "FileReader.hxx"
#include "lib/fmt/PathFormatter.hxx"
#include "fs/FileInfo.hxx"
#include "system/Error.hxx"
#include "system/FmtError.hxx"
#include "io/Open.hxx"
#include <cassert>
@ -43,7 +44,7 @@ FileReader::FileReader(Path _path)
nullptr))
{
if (handle == INVALID_HANDLE_VALUE)
throw FormatLastError("Failed to open %s", path.ToUTF8().c_str());
throw FmtLastError("Failed to open {}", path);
}
FileInfo
@ -61,8 +62,7 @@ FileReader::Read(void *data, std::size_t size)
DWORD nbytes;
if (!ReadFile(handle, data, size, &nbytes, nullptr))
throw FormatLastError("Failed to read from %s",
path.ToUTF8().c_str());
throw FmtLastError("Failed to read from %s", path);
return nbytes;
}
@ -110,8 +110,7 @@ FileReader::GetFileInfo() const
FileInfo info;
const bool success = fstat(fd.Get(), &info.st) == 0;
if (!success)
throw FormatErrno("Failed to access %s",
path.ToUTF8().c_str());
throw FmtErrno("Failed to access {}", path);
return info;
}
@ -123,7 +122,7 @@ FileReader::Read(void *data, std::size_t size)
ssize_t nbytes = fd.Read(data, size);
if (nbytes < 0)
throw FormatErrno("Failed to read from %s", path.ToUTF8().c_str());
throw FmtErrno("Failed to read from {}", path);
return nbytes;
}

View File

@ -29,7 +29,7 @@
#include "Open.hxx"
#include "UniqueFileDescriptor.hxx"
#include "system/Error.hxx"
#include "system/FmtError.hxx"
#include <fcntl.h>
@ -38,7 +38,7 @@ OpenReadOnly(const char *path, int flags)
{
UniqueFileDescriptor fd;
if (!fd.Open(path, O_RDONLY|flags))
throw FormatErrno("Failed to open '%s'", path);
throw FmtErrno("Failed to open '{}'", path);
return fd;
}
@ -48,7 +48,7 @@ OpenWriteOnly(const char *path, int flags)
{
UniqueFileDescriptor fd;
if (!fd.Open(path, O_WRONLY|flags))
throw FormatErrno("Failed to open '%s'", path);
throw FmtErrno("Failed to open '{}'", path);
return fd;
}
@ -60,7 +60,7 @@ OpenDirectory(const char *path, int flags)
{
UniqueFileDescriptor fd;
if (!fd.Open(path, O_DIRECTORY|O_RDONLY|flags))
throw FormatErrno("Failed to open '%s'", path);
throw FmtErrno("Failed to open '{}'", path);
return fd;
}
@ -74,7 +74,7 @@ OpenPath(const char *path, int flags)
{
UniqueFileDescriptor fd;
if (!fd.Open(path, O_PATH|flags))
throw FormatErrno("Failed to open '%s'", path);
throw FmtErrno("Failed to open '{}'", path);
return fd;
}
@ -84,7 +84,7 @@ OpenPath(FileDescriptor directory, const char *name, int flags)
{
UniqueFileDescriptor fd;
if (!fd.Open(directory, name, O_PATH|flags))
throw FormatErrno("Failed to open '%s'", name);
throw FmtErrno("Failed to open '{}'", name);
return fd;
}
@ -94,7 +94,7 @@ OpenReadOnly(FileDescriptor directory, const char *name, int flags)
{
UniqueFileDescriptor fd;
if (!fd.Open(directory, name, O_RDONLY|flags))
throw FormatErrno("Failed to open '%s'", name);
throw FmtErrno("Failed to open '{}'", name);
return fd;
}
@ -104,7 +104,7 @@ OpenWriteOnly(FileDescriptor directory, const char *name, int flags)
{
UniqueFileDescriptor fd;
if (!fd.Open(directory, name, O_WRONLY|flags))
throw FormatErrno("Failed to open '%s'", name);
throw FmtErrno("Failed to open '{}'", name);
return fd;
}
@ -114,7 +114,7 @@ OpenDirectory(FileDescriptor directory, const char *name, int flags)
{
UniqueFileDescriptor fd;
if (!fd.Open(directory, name, O_DIRECTORY|O_RDONLY|flags))
throw FormatErrno("Failed to open '%s'", name);
throw FmtErrno("Failed to open '{}'", name);
return fd;
}

View File

@ -118,7 +118,7 @@ LoadJackLibrary()
auto libjack = LoadLibraryA(LIBJACK);
if (!libjack)
throw FormatLastError("Failed to load " LIBJACK ".dll");
throw MakeLastError("Failed to load " LIBJACK ".dll");
GetFunction(libjack, "jack_set_error_function", _jack_set_error_function);
GetFunction(libjack, "jack_set_info_function", _jack_set_info_function);

View File

@ -21,7 +21,7 @@
#include "mixer/Mixer.hxx"
#include "config/Block.hxx"
#include "io/FileDescriptor.hxx"
#include "system/Error.hxx"
#include "system/FmtError.hxx"
#include "util/ASCII.hxx"
#include "util/Domain.hxx"
#include "util/RuntimeError.hxx"
@ -119,7 +119,7 @@ OssMixer::Open()
{
device_fd.OpenReadOnly(device);
if (!device_fd.IsDefined())
throw FormatErrno("failed to open %s", device);
throw FmtErrno("failed to open {}", device);
try {
if (control) {
@ -129,8 +129,8 @@ OssMixer::Open()
throw MakeErrno("READ_DEVMASK failed");
if (((1 << volume_control) & devmask) == 0)
throw FormatErrno("mixer control \"%s\" not usable",
control);
throw FmtErrno("mixer control \"{}\" not usable",
control);
}
} catch (...) {
Close();

View File

@ -20,9 +20,11 @@
#include "FifoOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "../Timer.hxx"
#include "lib/fmt/PathFormatter.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/FileSystem.hxx"
#include "fs/FileInfo.hxx"
#include "system/FmtError.hxx"
#include "util/Domain.hxx"
#include "util/RuntimeError.hxx"
#include "Log.hxx"
@ -91,7 +93,7 @@ inline void
FifoOutput::Delete()
{
FmtDebug(fifo_output_domain,
"Removing FIFO \"{}\"", path_utf8);
"Removing FIFO \"{}\"", path);
try {
RemoveFile(path);
@ -125,8 +127,7 @@ inline void
FifoOutput::Create()
{
if (!MakeFifo(path, 0666))
throw FormatErrno("Couldn't create FIFO \"%s\"",
path_utf8.c_str());
throw FmtErrno("Couldn't create FIFO \"{}\"", path);
created = true;
}
@ -142,8 +143,7 @@ FifoOutput::Check()
return;
}
throw FormatErrno("Failed to stat FIFO \"%s\"",
path_utf8.c_str());
throw FmtErrno("Failed to stat FIFO \"{}\"", path);
}
if (!S_ISFIFO(st.st_mode))
@ -158,13 +158,12 @@ try {
input = OpenFile(path, O_RDONLY|O_NONBLOCK|O_BINARY, 0).Steal();
if (input < 0)
throw FormatErrno("Could not open FIFO \"%s\" for reading",
path_utf8.c_str());
throw FmtErrno("Could not open FIFO \"{}\" for reading",
path);
output = OpenFile(path, O_WRONLY|O_NONBLOCK|O_BINARY, 0).Steal();
if (output < 0)
throw FormatErrno("Could not open FIFO \"%s\" for writing",
path_utf8.c_str());
throw FmtErrno("Could not open FIFO \"{}\" for writing");
} catch (...) {
CloseFifo();
throw;
@ -196,7 +195,7 @@ FifoOutput::Cancel() noexcept
if (bytes < 0 && errno != EAGAIN) {
FmtError(fifo_output_domain,
"Flush of FIFO \"{}\" failed: {}",
path_utf8, strerror(errno));
path, strerror(errno));
}
}
@ -230,8 +229,7 @@ FifoOutput::Play(std::span<const std::byte> src)
continue;
}
throw FormatErrno("Failed to write to FIFO %s",
path_utf8.c_str());
throw FmtErrno("Failed to write to FIFO {}", path);
}
}
}

View File

@ -22,7 +22,7 @@
#include "mixer/plugins/OssMixerPlugin.hxx"
#include "pcm/Export.hxx"
#include "io/UniqueFileDescriptor.hxx"
#include "system/Error.hxx"
#include "system/FmtError.hxx"
#include "util/Domain.hxx"
#include "util/ByteOrder.hxx"
#include "util/Manual.hxx"
@ -643,7 +643,7 @@ try {
assert(!fd.IsDefined());
if (!fd.Open(device, O_WRONLY))
throw FormatErrno("Error opening OSS device \"%s\"", device);
throw FmtErrno("Error opening OSS device \"{}\"", device);
OssIoctlExact(fd, SNDCTL_DSP_CHANNELS, effective_channels,
"Failed to set channel count");
@ -660,7 +660,7 @@ void
OssOutput::Open(AudioFormat &_audio_format)
try {
if (!fd.Open(device, O_WRONLY))
throw FormatErrno("Error opening OSS device \"%s\"", device);
throw FmtErrno("Error opening OSS device \"{}\"", device);
SetupOrDop(_audio_format);
} catch (...) {
@ -698,7 +698,7 @@ OssOutput::Play(std::span<const std::byte> src)
return pcm_export->CalcInputSize(ret);
if (ret < 0 && errno != EINTR)
throw FormatErrno("Write error on %s", device);
throw FmtErrno("Write error on {}", device);
}
}

View File

@ -19,7 +19,7 @@
#include "PipeOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "system/Error.hxx"
#include "system/FmtError.hxx"
#include <string>
#include <stdexcept>
@ -61,7 +61,7 @@ PipeOutput::Open([[maybe_unused]] AudioFormat &audio_format)
{
fh = popen(cmd.c_str(), "w");
if (fh == nullptr)
throw FormatErrno("Error opening pipe \"%s\"", cmd.c_str());
throw FmtErrno("Error opening pipe \"{}\"", cmd);
}
std::size_t

View File

@ -20,7 +20,7 @@
#include "SolarisOutputPlugin.hxx"
#include "../OutputAPI.hxx"
#include "io/FileDescriptor.hxx"
#include "system/Error.hxx"
#include "system/FmtError.hxx"
#include <cerrno>
@ -100,8 +100,7 @@ SolarisOutput::Open(AudioFormat &audio_format)
/* open the device in non-blocking mode */
if (!fd.Open(device, O_WRONLY|O_NONBLOCK))
throw FormatErrno("Failed to open %s",
device);
throw FmtErrno("Failed to open {}", device);
/* restore blocking mode */

View File

@ -32,8 +32,6 @@
#include <system_error> // IWYU pragma: export
#include <utility>
#include <stdio.h>
template<typename... Args>
static inline std::system_error
FormatSystemError(std::error_code code, const char *fmt,
@ -47,8 +45,7 @@ FormatSystemError(std::error_code code, const char *fmt,
#ifdef _WIN32
#include <errhandlingapi.h> // for GetLastError()
#include <windef.h> // for HWND (needed by winbase.h)
#include <winbase.h> // for FormatMessageA()
#include <winerror.h>
/**
* Returns the error_category to be used to wrap WIN32 GetLastError()
@ -85,41 +82,10 @@ MakeLastError(const char *msg) noexcept
return MakeLastError(GetLastError(), msg);
}
template<typename... Args>
static inline std::system_error
FormatLastError(DWORD code, const char *fmt, Args&&... args) noexcept
{
char buffer[512];
const auto end = buffer + sizeof(buffer);
constexpr std::size_t max_prefix = sizeof(buffer) - 128;
size_t length = snprintf(buffer, max_prefix,
fmt, std::forward<Args>(args)...);
if (length >= max_prefix)
length = max_prefix - 1;
char *p = buffer + length;
*p++ = ':';
*p++ = ' ';
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, code, 0, p, end - p, nullptr);
return MakeLastError(code, buffer);
}
template<typename... Args>
static inline std::system_error
FormatLastError(const char *fmt, Args&&... args) noexcept
{
return FormatLastError(GetLastError(), fmt,
std::forward<Args>(args)...);
}
#endif /* _WIN32 */
#include <cerrno> // IWYU pragma: export
#include <string.h>
/**
* Returns the error_category to be used to wrap errno values. The
* C++ standard does not define this well, so this code is based on
@ -156,35 +122,6 @@ MakeErrno(const char *msg) noexcept
return MakeErrno(errno, msg);
}
template<typename... Args>
static inline std::system_error
FormatErrno(int code, const char *fmt, Args&&... args) noexcept
{
char buffer[512];
snprintf(buffer, sizeof(buffer),
fmt, std::forward<Args>(args)...);
return MakeErrno(code, buffer);
}
template<typename... Args>
static inline std::system_error
FormatErrno(const char *fmt, Args&&... args) noexcept
{
return FormatErrno(errno, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
static inline std::system_error
FormatFileNotFound(const char *fmt, Args&&... args) noexcept
{
#ifdef _WIN32
return FormatLastError(ERROR_FILE_NOT_FOUND, fmt,
std::forward<Args>(args)...);
#else
return FormatErrno(ENOENT, fmt, std::forward<Args>(args)...);
#endif
}
[[gnu::pure]]
inline bool
IsErrno(const std::system_error &e, int code) noexcept

73
src/system/FmtError.cxx Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright 2022 Max Kellermann <max.kellermann@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "FmtError.hxx"
#include <fmt/format.h>
#include <array>
std::system_error
VFmtSystemError(std::error_code code,
fmt::string_view format_str, fmt::format_args args) noexcept
{
std::array<char, 512> buffer;
auto [p, _] = fmt::vformat_to_n(buffer.begin(), buffer.size() - 1,
format_str, args);
*p = 0;
return std::system_error{code, buffer.data()};
}
#ifdef _WIN32
#include <windef.h> // for HWND (needed by winbase.h)
#include <winbase.h> // for FormatMessageA()
std::system_error
VFmtLastError(DWORD code,
fmt::string_view format_str, fmt::format_args args) noexcept
{
std::array<char, 512> buffer;
const auto end = buffer.data() + buffer.size();
constexpr std::size_t max_prefix = sizeof(buffer) - 128;
auto [p, _] = fmt::vformat_to_n(buffer.data(),
buffer.size() - max_prefix,
format_str, args);
*p++ = ':';
*p++ = ' ';
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, code, 0, p, end - p, nullptr);
return MakeLastError(code, buffer.data());
}
#endif // _WIN32

122
src/system/FmtError.hxx Normal file
View File

@ -0,0 +1,122 @@
/*
* Copyright 2022 Max Kellermann <max.kellermann@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "Error.hxx" // IWYU pragma: export
#include <fmt/core.h>
#if FMT_VERSION >= 80000 && FMT_VERSION < 90000
#include <fmt/format.h>
#endif
[[nodiscard]] [[gnu::pure]]
std::system_error
VFmtSystemError(std::error_code code,
fmt::string_view format_str, fmt::format_args args) noexcept;
template<typename S, typename... Args>
[[nodiscard]] [[gnu::pure]]
std::system_error
FmtSystemError(std::error_code code,
const S &format_str, Args&&... args) noexcept
{
#if FMT_VERSION >= 90000
return VFmtSystemError(code, format_str,
fmt::make_format_args(args...));
#else
return VFmtSystemError(code, fmt::to_string_view(format_str),
fmt::make_args_checked<Args...>(format_str,
args...));
#endif
}
#ifdef _WIN32
[[nodiscard]] [[gnu::pure]]
std::system_error
VFmtLastError(DWORD code,
fmt::string_view format_str, fmt::format_args args) noexcept;
template<typename S, typename... Args>
[[nodiscard]] [[gnu::pure]]
std::system_error
FmtLastError(DWORD code,
const S &format_str, Args&&... args) noexcept
{
#if FMT_VERSION >= 90000
return VFmtLastError(code, format_str,
fmt::make_format_args(args...));
#else
return VFmtLastError(code, fmt::to_string_view(format_str),
fmt::make_args_checked<Args...>(format_str,
args...));
#endif
}
template<typename S, typename... Args>
[[nodiscard]] [[gnu::pure]]
std::system_error
FmtLastError(const S &format_str, Args&&... args) noexcept
{
return FmtLastError(GetLastError(),
format_str, std::forward<Args>(args)...);
}
#endif // _WIN32
template<typename S, typename... Args>
[[nodiscard]] [[gnu::pure]]
std::system_error
FmtErrno(int code, const S &format_str, Args&&... args) noexcept
{
return FmtSystemError(std::error_code(code, ErrnoCategory()),
format_str, std::forward<Args>(args)...);
}
template<typename S, typename... Args>
[[nodiscard]] [[gnu::pure]]
std::system_error
FmtErrno(const S &format_str, Args&&... args) noexcept
{
return FmtErrno(errno, format_str, std::forward<Args>(args)...);
}
template<typename S, typename... Args>
[[nodiscard]] [[gnu::pure]]
std::system_error
FmtFileNotFound(const S &format_str, Args&&... args) noexcept
{
#ifdef _WIN32
return FmtLastError(DWORD{ERROR_FILE_NOT_FOUND},
format_str, std::forward<Args>(args)...);
#else
return FmtErrno(ENOENT, format_str, std::forward<Args>(args)...);
#endif
}

View File

@ -1,5 +1,6 @@
system_sources = [
'EventPipe.cxx',
'FmtError.cxx',
]
if host_machine.system() == 'linux'

View File

@ -19,7 +19,8 @@
#include "config.h"
#include "Daemon.hxx"
#include "system/Error.hxx"
#include "lib/fmt/PathFormatter.hxx"
#include "system/FmtError.hxx"
#include "fs/AllocatedPath.hxx"
#include "util/RuntimeError.hxx"
@ -70,14 +71,12 @@ daemonize_kill()
throw std::runtime_error("no pid_file specified in the config file");
const pid_t pid = ReadPidFile(pidfile);
if (pid < 0) {
const std::string utf8 = pidfile.ToUTF8();
throw FormatErrno("unable to read the pid from file \"%s\"",
utf8.c_str());
}
if (pid < 0)
throw FmtErrno("unable to read the pid from file \"{}\"",
pidfile);
if (kill(pid, SIGTERM) < 0)
throw FormatErrno("unable to kill process %i", int(pid));
throw FmtErrno("unable to kill process {}", pid);
std::exit(EXIT_SUCCESS);
}
@ -98,7 +97,7 @@ daemonize_set_user()
/* set gid */
if (user_gid != (gid_t)-1 && user_gid != getgid() &&
setgid(user_gid) == -1) {
throw FormatErrno("Failed to set group %d", (int)user_gid);
throw FmtErrno("Failed to set group {}", user_gid);
}
#ifdef HAVE_INITGROUPS
@ -110,16 +109,16 @@ daemonize_set_user()
we are already this user */
user_uid != getuid() &&
initgroups(user_name, user_gid) == -1) {
throw FormatErrno("Failed to set supplementary groups "
"of user \"%s\"",
user_name);
throw FmtErrno("Failed to set supplementary groups "
"of user \"{}\"",
user_name);
}
#endif
/* set uid */
if (user_uid != (uid_t)-1 && user_uid != getuid() &&
setuid(user_uid) == -1) {
throw FormatErrno("Failed to set user \"%s\"", user_name);
throw FmtErrno("Failed to set user \"{}\"", user_name);
}
}
@ -191,8 +190,8 @@ daemonize_begin(bool detach)
throw MakeErrno("waitpid() failed");
if (WIFSIGNALED(status))
throw FormatErrno("MPD died from signal %d%s", WTERMSIG(status),
WCOREDUMP(status) ? " (core dumped)" : "");
throw FmtErrno("MPD died from signal {}{}", WTERMSIG(status),
WCOREDUMP(status) ? " (core dumped)" : "");
std::exit(WEXITSTATUS(status));
}

View File

@ -20,9 +20,10 @@
#ifndef MPD_PID_FILE_HXX
#define MPD_PID_FILE_HXX
#include "lib/fmt/PathFormatter.hxx"
#include "fs/FileSystem.hxx"
#include "fs/AllocatedPath.hxx"
#include "system/Error.hxx"
#include "system/FmtError.hxx"
#include <cassert>
@ -40,11 +41,9 @@ public:
return;
fd = OpenFile(path, O_WRONLY|O_CREAT|O_TRUNC, 0666).Steal();
if (fd < 0) {
const std::string utf8 = path.ToUTF8();
throw FormatErrno("Failed to create pid file \"%s\"",
utf8.c_str());
}
if (fd < 0)
throw FmtErrno("Failed to create pid file \"{}\"",
path);
}
PidFile(const PidFile &) = delete;

View File

@ -24,5 +24,5 @@ WinEvent::WinEvent()
:event(CreateEventW(nullptr, false, false, nullptr))
{
if (!event)
throw FormatLastError("Error creating events");
throw MakeLastError("Error creating events");
}