2020-04-26 14:47:41 -06:00
|
|
|
#pragma once
|
2023-04-07 09:55:28 -04:00
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
*
|
|
|
|
* @brief This file defines two main structs/classes used in nix error handling.
|
|
|
|
*
|
|
|
|
* ErrorInfo provides a standard payload of error information, with conversion to string
|
|
|
|
* happening in the logger rather than at the call site.
|
|
|
|
*
|
|
|
|
* BaseError is the ancestor of nix specific exceptions (and Interrupted), and contains
|
|
|
|
* an ErrorInfo.
|
|
|
|
*
|
|
|
|
* ErrorInfo structs are sent to the logger as part of an exception, or directly with the
|
|
|
|
* logError or logWarning macros.
|
|
|
|
* See libutil/tests/logging.cc for usage examples.
|
|
|
|
*/
|
2020-03-22 12:25:47 -06:00
|
|
|
|
2022-03-03 10:50:35 +01:00
|
|
|
#include "suggestions.hh"
|
2020-04-26 14:47:41 -06:00
|
|
|
#include "ref.hh"
|
2020-04-03 08:48:20 -06:00
|
|
|
#include "types.hh"
|
2020-07-07 14:37:47 +02:00
|
|
|
#include "fmt.hh"
|
2020-03-27 10:55:09 -06:00
|
|
|
|
2020-06-15 23:35:07 +00:00
|
|
|
#include <cstring>
|
2020-04-26 14:47:41 -06:00
|
|
|
#include <list>
|
|
|
|
#include <memory>
|
|
|
|
#include <map>
|
|
|
|
#include <optional>
|
2023-12-15 11:52:21 -08:00
|
|
|
#include <compare>
|
2020-03-22 12:25:47 -06:00
|
|
|
|
2020-07-07 14:37:47 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2020-03-22 12:25:47 -06:00
|
|
|
|
2020-04-26 14:47:41 -06:00
|
|
|
/* Before 4.7, gcc's std::exception uses empty throw() specifiers for
|
|
|
|
* its (virtual) destructor and what() in c++11 mode, in violation of spec
|
|
|
|
*/
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
|
|
|
|
#define EXCEPTION_NEEDS_THROW_SPEC
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
2020-06-04 11:53:19 -06:00
|
|
|
|
2020-04-28 21:06:08 -06:00
|
|
|
typedef enum {
|
2020-04-26 14:47:41 -06:00
|
|
|
lvlError = 0,
|
|
|
|
lvlWarn,
|
2020-11-27 11:19:36 +01:00
|
|
|
lvlNotice,
|
2020-04-26 14:47:41 -06:00
|
|
|
lvlInfo,
|
|
|
|
lvlTalkative,
|
|
|
|
lvlChatty,
|
|
|
|
lvlDebug,
|
|
|
|
lvlVomit
|
|
|
|
} Verbosity;
|
|
|
|
|
2023-03-26 21:12:25 -04:00
|
|
|
/**
|
|
|
|
* The lines of code surrounding an error.
|
|
|
|
*/
|
2020-06-24 08:33:53 -06:00
|
|
|
struct LinesOfCode {
|
2022-02-25 16:00:00 +01:00
|
|
|
std::optional<std::string> prevLineOfCode;
|
|
|
|
std::optional<std::string> errLineOfCode;
|
|
|
|
std::optional<std::string> nextLineOfCode;
|
2020-06-24 08:33:53 -06:00
|
|
|
};
|
|
|
|
|
2023-12-18 13:14:42 -08:00
|
|
|
struct Pos;
|
2022-04-29 11:27:38 -06:00
|
|
|
|
2021-09-13 11:57:25 -06:00
|
|
|
void printCodeLines(std::ostream & out,
|
2022-04-07 13:42:01 -06:00
|
|
|
const std::string & prefix,
|
2023-12-18 13:14:42 -08:00
|
|
|
const Pos & errPos,
|
2021-09-13 11:57:25 -06:00
|
|
|
const LinesOfCode & loc);
|
|
|
|
|
2020-06-18 15:25:26 -06:00
|
|
|
struct Trace {
|
2023-12-18 13:14:42 -08:00
|
|
|
std::shared_ptr<Pos> pos;
|
2020-06-18 15:25:26 -06:00
|
|
|
hintformat hint;
|
2023-01-19 13:23:04 +01:00
|
|
|
bool frame;
|
2020-03-24 11:21:35 -06:00
|
|
|
};
|
|
|
|
|
2023-12-15 11:52:21 -08:00
|
|
|
inline bool operator<(const Trace& lhs, const Trace& rhs);
|
|
|
|
inline bool operator> (const Trace& lhs, const Trace& rhs);
|
|
|
|
inline bool operator<=(const Trace& lhs, const Trace& rhs);
|
|
|
|
inline bool operator>=(const Trace& lhs, const Trace& rhs);
|
|
|
|
|
2020-04-28 21:06:08 -06:00
|
|
|
struct ErrorInfo {
|
2020-04-26 14:47:41 -06:00
|
|
|
Verbosity level;
|
2021-01-21 00:27:36 +01:00
|
|
|
hintformat msg;
|
2023-12-18 13:14:42 -08:00
|
|
|
std::shared_ptr<Pos> errPos;
|
2020-06-18 15:25:26 -06:00
|
|
|
std::list<Trace> traces;
|
2020-03-24 11:21:35 -06:00
|
|
|
|
2022-03-03 10:50:35 +01:00
|
|
|
Suggestions suggestions;
|
|
|
|
|
2022-02-25 16:00:00 +01:00
|
|
|
static std::optional<std::string> programName;
|
2020-04-06 19:43:22 -06:00
|
|
|
};
|
2020-03-24 11:21:35 -06:00
|
|
|
|
2022-02-25 16:00:00 +01:00
|
|
|
std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace);
|
2020-03-24 11:21:35 -06:00
|
|
|
|
2023-03-26 21:12:25 -04:00
|
|
|
/**
|
|
|
|
* BaseError should generally not be caught, as it has Interrupted as
|
|
|
|
* a subclass. Catch Error instead.
|
|
|
|
*/
|
2020-04-26 14:47:41 -06:00
|
|
|
class BaseError : public std::exception
|
2020-04-06 19:43:22 -06:00
|
|
|
{
|
2020-04-26 14:47:41 -06:00
|
|
|
protected:
|
2020-05-07 16:43:36 -06:00
|
|
|
mutable ErrorInfo err;
|
2020-04-29 18:57:05 -06:00
|
|
|
|
2022-02-25 16:00:00 +01:00
|
|
|
mutable std::optional<std::string> what_;
|
|
|
|
const std::string & calcWhat() const;
|
2020-06-15 14:06:58 +02:00
|
|
|
|
2020-04-06 19:43:22 -06:00
|
|
|
public:
|
2020-04-26 14:47:41 -06:00
|
|
|
unsigned int status = 1; // exit status
|
|
|
|
|
2023-01-19 13:23:04 +01:00
|
|
|
BaseError(const BaseError &) = default;
|
|
|
|
|
2020-04-26 14:47:41 -06:00
|
|
|
template<typename... Args>
|
|
|
|
BaseError(unsigned int status, const Args & ... args)
|
2021-01-21 00:27:36 +01:00
|
|
|
: err { .level = lvlError, .msg = hintfmt(args...) }
|
2020-04-26 14:47:41 -06:00
|
|
|
, status(status)
|
2020-04-29 18:57:05 -06:00
|
|
|
{ }
|
2020-04-26 14:47:41 -06:00
|
|
|
|
|
|
|
template<typename... Args>
|
2022-01-17 19:28:42 +01:00
|
|
|
explicit BaseError(const std::string & fs, const Args & ... args)
|
2021-01-21 00:27:36 +01:00
|
|
|
: err { .level = lvlError, .msg = hintfmt(fs, args...) }
|
2020-04-29 18:57:05 -06:00
|
|
|
{ }
|
2020-04-26 14:47:41 -06:00
|
|
|
|
2022-03-03 10:50:35 +01:00
|
|
|
template<typename... Args>
|
|
|
|
BaseError(const Suggestions & sug, const Args & ... args)
|
|
|
|
: err { .level = lvlError, .msg = hintfmt(args...), .suggestions = sug }
|
|
|
|
{ }
|
|
|
|
|
2020-05-03 08:01:25 -06:00
|
|
|
BaseError(hintformat hint)
|
2021-01-21 00:27:36 +01:00
|
|
|
: err { .level = lvlError, .msg = hint }
|
2020-05-03 08:01:25 -06:00
|
|
|
{ }
|
|
|
|
|
2020-06-15 14:06:58 +02:00
|
|
|
BaseError(ErrorInfo && e)
|
|
|
|
: err(std::move(e))
|
|
|
|
{ }
|
|
|
|
|
|
|
|
BaseError(const ErrorInfo & e)
|
2020-04-26 14:47:41 -06:00
|
|
|
: err(e)
|
2020-04-29 18:57:05 -06:00
|
|
|
{ }
|
2020-04-28 21:06:08 -06:00
|
|
|
|
2020-04-26 14:47:41 -06:00
|
|
|
#ifdef EXCEPTION_NEEDS_THROW_SPEC
|
|
|
|
~BaseError() throw () { };
|
2020-05-07 16:43:36 -06:00
|
|
|
const char * what() const throw () { return calcWhat().c_str(); }
|
2020-04-26 14:47:41 -06:00
|
|
|
#else
|
2020-05-07 16:43:36 -06:00
|
|
|
const char * what() const noexcept override { return calcWhat().c_str(); }
|
2020-04-26 14:47:41 -06:00
|
|
|
#endif
|
2020-03-24 14:24:57 -06:00
|
|
|
|
2022-02-25 16:00:00 +01:00
|
|
|
const std::string & msg() const { return calcWhat(); }
|
2020-10-07 16:33:19 +02:00
|
|
|
const ErrorInfo & info() const { calcWhat(); return err; }
|
2020-06-24 13:10:41 -06:00
|
|
|
|
2023-01-19 13:23:04 +01:00
|
|
|
void pushTrace(Trace trace)
|
|
|
|
{
|
|
|
|
err.traces.push_front(trace);
|
|
|
|
}
|
|
|
|
|
2020-06-24 13:46:25 -06:00
|
|
|
template<typename... Args>
|
2023-12-18 13:14:42 -08:00
|
|
|
void addTrace(std::shared_ptr<Pos> && e, std::string_view fs, const Args & ... args)
|
2020-06-24 13:46:25 -06:00
|
|
|
{
|
2023-01-19 13:23:04 +01:00
|
|
|
addTrace(std::move(e), hintfmt(std::string(fs), args...));
|
2020-06-24 13:46:25 -06:00
|
|
|
}
|
|
|
|
|
2023-12-18 13:14:42 -08:00
|
|
|
void addTrace(std::shared_ptr<Pos> && e, hintformat hint, bool frame = false);
|
2020-06-24 18:31:28 -06:00
|
|
|
|
|
|
|
bool hasTrace() const { return !err.traces.empty(); }
|
2023-01-19 13:23:04 +01:00
|
|
|
|
|
|
|
const ErrorInfo & info() { return err; };
|
2020-04-06 19:43:22 -06:00
|
|
|
};
|
|
|
|
|
2020-04-26 14:47:41 -06:00
|
|
|
#define MakeError(newClass, superClass) \
|
|
|
|
class newClass : public superClass \
|
|
|
|
{ \
|
|
|
|
public: \
|
|
|
|
using superClass::superClass; \
|
|
|
|
}
|
2020-04-08 09:07:58 -06:00
|
|
|
|
2020-04-26 14:47:41 -06:00
|
|
|
MakeError(Error, BaseError);
|
2020-06-17 10:26:52 +02:00
|
|
|
MakeError(UsageError, Error);
|
2020-07-20 14:13:37 -04:00
|
|
|
MakeError(UnimplementedError, Error);
|
2020-03-24 14:24:57 -06:00
|
|
|
|
2023-12-01 17:03:28 -05:00
|
|
|
/**
|
|
|
|
* To use in catch-blocks.
|
|
|
|
*/
|
|
|
|
MakeError(SystemError, Error);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* POSIX system error, created using `errno`, `strerror` friends.
|
|
|
|
*
|
|
|
|
* Throw this, but prefer not to catch this, and catch `SystemError`
|
|
|
|
* instead. This allows implementations to freely switch between this
|
|
|
|
* and `WinError` without breaking catch blocks.
|
|
|
|
*
|
|
|
|
* However, it is permissible to catch this and rethrow so long as
|
|
|
|
* certain conditions are not met (e.g. to catch only if `errNo =
|
|
|
|
* EFooBar`). In that case, try to also catch the equivalent `WinError`
|
|
|
|
* code.
|
|
|
|
*
|
|
|
|
* @todo Rename this to `PosixError` or similar. At this point Windows
|
|
|
|
* support is too WIP to justify the code churn, but if it is finished
|
|
|
|
* then a better identifier becomes moe worth it.
|
|
|
|
*/
|
|
|
|
class SysError : public SystemError
|
2020-04-02 16:02:40 -06:00
|
|
|
{
|
2020-04-26 14:47:41 -06:00
|
|
|
public:
|
|
|
|
int errNo;
|
2020-03-24 09:18:23 -06:00
|
|
|
|
2023-12-01 17:03:28 -05:00
|
|
|
/**
|
|
|
|
* Construct using the explicitly-provided error number. `strerror`
|
|
|
|
* will be used to try to add additional information to the message.
|
|
|
|
*/
|
2020-04-26 14:47:41 -06:00
|
|
|
template<typename... Args>
|
2023-12-01 17:03:28 -05:00
|
|
|
SysError(int errNo, const Args & ... args)
|
|
|
|
: SystemError(""), errNo(errNo)
|
2020-05-06 14:07:20 -06:00
|
|
|
{
|
|
|
|
auto hf = hintfmt(args...);
|
2021-01-21 00:27:36 +01:00
|
|
|
err.msg = hintfmt("%1%: %2%", normaltxt(hf.str()), strerror(errNo));
|
2020-05-06 14:07:20 -06:00
|
|
|
}
|
2022-07-19 03:49:33 -07:00
|
|
|
|
2023-12-01 17:03:28 -05:00
|
|
|
/**
|
|
|
|
* Construct using the ambient `errno`.
|
|
|
|
*
|
|
|
|
* Be sure to not perform another `errno`-modifying operation before
|
|
|
|
* calling this constructor!
|
|
|
|
*/
|
2022-07-19 03:49:33 -07:00
|
|
|
template<typename... Args>
|
|
|
|
SysError(const Args & ... args)
|
|
|
|
: SysError(errno, args ...)
|
|
|
|
{
|
|
|
|
}
|
2020-04-26 14:47:41 -06:00
|
|
|
};
|
2020-03-27 10:03:02 -06:00
|
|
|
|
2023-12-01 17:03:28 -05:00
|
|
|
/**
|
|
|
|
* Throw an exception for the purpose of checking that exception
|
|
|
|
* handling works; see 'initLibUtil()'.
|
2023-08-11 17:22:55 +02:00
|
|
|
*/
|
|
|
|
void throwExceptionSelfCheck();
|
|
|
|
|
2020-03-22 12:25:47 -06:00
|
|
|
}
|