blob: fb5119fa4148e2a5b6513240e8d761c178bc3f5b [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#ifndef __NGINX_UTIL_H
2#define __NGINX_UTIL_H
3
4#include <array>
5#include <cerrno>
6#include <cstdio>
7#include <cstdlib>
8#include <cstring>
9#include <fstream>
10#include <string>
11#include <string_view>
12// #include <sys/types.h>
13#include <sys/stat.h>
14#include <unistd.h>
15#include <thread>
16#include <vector>
17
18#ifndef NO_UBUS
19#include "ubus-cxx.hpp"
20#endif
21
22#include "uci-cxx.hpp"
23
24static constexpr auto NGINX_UTIL = std::string_view{"/usr/bin/nginx-util"};
25
26static constexpr auto VAR_UCI_CONF = std::string_view{"/var/lib/nginx/uci.conf"};
27
28static constexpr auto UCI_CONF = std::string_view{"/etc/nginx/uci.conf"};
29
30static constexpr auto NGINX_CONF = std::string_view{"/etc/nginx/nginx.conf"};
31
32static constexpr auto CONF_DIR = std::string_view{"/etc/nginx/conf.d/"};
33
34static constexpr auto LAN_NAME = std::string_view{"_lan"};
35
36static auto constexpr MANAGE_SSL = std::string_view{"uci_manage_ssl"};
37
38static constexpr auto LAN_LISTEN = std::string_view{"/var/lib/nginx/lan.listen"};
39
40static constexpr auto LAN_LISTEN_DEFAULT = // TODO(pst) deprecate
41 std::string_view{"/var/lib/nginx/lan.listen.default"};
42
43// mode: optional ios::binary and/or ios::app (default ios::trunc)
44void write_file(const std::string_view& name,
45 const std::string& str,
46 std::ios_base::openmode flag = std::ios::trunc);
47
48// mode: optional ios::binary (internally ios::ate|ios::in)
49auto read_file(const std::string_view& name, std::ios_base::openmode mode = std::ios::in)
50 -> std::string;
51
52// all S must be convertible to const char[]
53template <typename... S>
54auto call(const std::string& program, S... args) -> pid_t;
55
56void create_lan_listen();
57
58void init_uci(const uci::package& pkg);
59
60auto is_enabled(const uci::package& pkg) -> bool;
61
62void init_lan();
63
64void get_env();
65
66// --------------------- partial implementation: ------------------------------
67
68void write_file(const std::string_view& name,
69 const std::string& str,
70 const std::ios_base::openmode flag)
71{
72 auto tmp = std::string{name};
73
74 if ((flag & std::ios::ate) == 0 && (flag & std::ios::app) == 0) {
75 tmp += ".tmp-XXXXXX";
76 auto fd = mkstemp(&tmp[0]);
77 if (fd == -1 || close(fd) != 0) {
78 throw std::runtime_error("write_file error: cannot access " + tmp);
79 }
80 }
81
82 try {
83 std::ofstream file(tmp.data(), flag);
84 if (!file.good()) {
85 throw std::ofstream::failure("write_file error: cannot open " + std::string{tmp});
86 }
87
88 file << str << std::flush;
89
90 file.close();
91 }
92 catch (...) {
93 if (tmp != name) {
94 remove(tmp.c_str());
95 } // remove can fail.
96 throw;
97 }
98
99 if (rename(tmp.c_str(), name.data()) != 0) {
100 throw std::runtime_error("write_file error: cannot move " + tmp + " to " + name.data());
101 }
102}
103
104auto read_file(const std::string_view& name, const std::ios_base::openmode mode) -> std::string
105{
106 std::ifstream file(name.data(), mode | std::ios::ate);
107 if (!file.good()) {
108 throw std::ifstream::failure("read_file error: cannot open " + std::string{name});
109 }
110
111 std::string ret{};
112 const size_t size = file.tellg();
113 ret.reserve(size);
114
115 file.seekg(0);
116 ret.assign((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
117
118 file.close();
119 return ret;
120}
121
122template <typename... S>
123auto call(const char* program, S... args) -> pid_t
124{
125 pid_t pid = fork();
126
127 if (pid == 0) { // child:
128 std::array<char*, sizeof...(args) + 2> argv = {strdup(program), strdup(args)..., nullptr};
129
130 execv(program, argv.data()); // argv cannot be const char * const[]!
131
132 _exit(EXIT_FAILURE); // exec never returns.
133 }
134 else if (pid > 0) { // parent:
135 return pid;
136 }
137
138 std::string errmsg = "call error: cannot fork (";
139 errmsg += std::to_string(errno) + "): " + std::strerror(errno);
140 throw std::runtime_error(errmsg);
141}
142
143#endif