You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

469 lines
8.8 KiB

  1. /*
  2. ISC License
  3. Copyright (c) 2021, Antonio SJ Musumeci <trapexit@spawn.link>
  4. Permission to use, copy, modify, and/or distribute this software for any
  5. purpose with or without fee is hereby granted, provided that the above
  6. copyright notice and this permission notice appear in all copies.
  7. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. */
  15. #include "branches.hpp"
  16. #include "ef.hpp"
  17. #include "errno.hpp"
  18. #include "from_string.hpp"
  19. #include "fs_glob.hpp"
  20. #include "fs_is_rofs.hpp"
  21. #include "fs_realpathize.hpp"
  22. #include "nonstd/optional.hpp"
  23. #include "num.hpp"
  24. #include "str.hpp"
  25. #include "syslog.hpp"
  26. #include <string>
  27. #include <fnmatch.h>
  28. using std::string;
  29. using std::vector;
  30. using nonstd::optional;
  31. Branches::Impl::Impl(const uint64_t &default_minfreespace_)
  32. : _default_minfreespace(default_minfreespace_)
  33. {
  34. }
  35. Branches::Impl&
  36. Branches::Impl::operator=(Branches::Impl &rval_)
  37. {
  38. auto this_base = dynamic_cast<Branch::Vector*>(this);
  39. auto rval_base = dynamic_cast<Branch::Vector*>(&rval_);
  40. *this_base = *rval_base;
  41. return *this;
  42. }
  43. Branches::Impl&
  44. Branches::Impl::operator=(Branches::Impl &&rval_)
  45. {
  46. auto this_base = dynamic_cast<Branch::Vector*>(this);
  47. auto rval_base = dynamic_cast<Branch::Vector*>(&rval_);
  48. *this_base = std::move(*rval_base);
  49. return *this;
  50. }
  51. const
  52. uint64_t&
  53. Branches::Impl::minfreespace(void) const
  54. {
  55. return _default_minfreespace;
  56. }
  57. namespace l
  58. {
  59. static
  60. void
  61. split(const std::string &s_,
  62. std::string *instr_,
  63. std::string *values_)
  64. {
  65. uint64_t offset;
  66. offset = s_.find_first_not_of("+<>-=");
  67. if (offset == std::string::npos) {
  68. return;
  69. }
  70. if(offset > 1)
  71. offset = 2;
  72. *instr_ = s_.substr(0,offset);
  73. *values_ = s_.substr(offset);
  74. }
  75. static
  76. int
  77. parse_mode(const string &str_,
  78. Branch::Mode *mode_)
  79. {
  80. if(str_ == "RW")
  81. *mode_ = Branch::Mode::RW;
  82. ef(str_ == "RO")
  83. *mode_ = Branch::Mode::RO;
  84. ef(str_ == "NC")
  85. *mode_ = Branch::Mode::NC;
  86. else
  87. return -EINVAL;
  88. return 0;
  89. }
  90. static
  91. int
  92. parse_minfreespace(const string &str_,
  93. optional<uint64_t> *minfreespace_)
  94. {
  95. int rv;
  96. uint64_t uint64;
  97. rv = str::from(str_,&uint64);
  98. if(rv < 0)
  99. return rv;
  100. *minfreespace_ = uint64;
  101. return 0;
  102. }
  103. static
  104. int
  105. parse_branch(const string &str_,
  106. string *glob_,
  107. Branch::Mode *mode_,
  108. optional<uint64_t> *minfreespace_)
  109. {
  110. int rv;
  111. string options;
  112. vector<string> v;
  113. str::rsplit1(str_,'=',&v);
  114. switch(v.size())
  115. {
  116. case 1:
  117. *glob_ = v[0];
  118. *mode_ = Branch::Mode::RW;
  119. break;
  120. case 2:
  121. *glob_ = v[0];
  122. options = v[1];
  123. v.clear();
  124. str::split(options,',',&v);
  125. switch(v.size())
  126. {
  127. case 2:
  128. rv = l::parse_minfreespace(v[1],minfreespace_);
  129. if(rv < 0)
  130. return rv;
  131. case 1:
  132. rv = l::parse_mode(v[0],mode_);
  133. if(rv < 0)
  134. return rv;
  135. break;
  136. case 0:
  137. return -EINVAL;
  138. }
  139. break;
  140. default:
  141. return -EINVAL;
  142. }
  143. return 0;
  144. }
  145. static
  146. int
  147. parse(const string &str_,
  148. Branches::Impl *branches_)
  149. {
  150. int rv;
  151. string glob;
  152. StrVec paths;
  153. optional<uint64_t> minfreespace;
  154. Branch branch(branches_->minfreespace());
  155. rv = l::parse_branch(str_,&glob,&branch.mode,&minfreespace);
  156. if(rv < 0)
  157. return rv;
  158. if(minfreespace.has_value())
  159. branch.set_minfreespace(minfreespace.value());
  160. fs::glob(glob,&paths);
  161. if(paths.empty())
  162. paths.push_back(glob);
  163. fs::realpathize(&paths);
  164. for(auto &path : paths)
  165. {
  166. branch.path = path;
  167. branches_->push_back(branch);
  168. }
  169. return 0;
  170. }
  171. static
  172. int
  173. set(const std::string &str_,
  174. Branches::Impl *branches_)
  175. {
  176. int rv;
  177. StrVec paths;
  178. Branches::Impl tmp_branches(branches_->minfreespace());
  179. str::split(str_,':',&paths);
  180. for(auto &path : paths)
  181. {
  182. rv = l::parse(path,&tmp_branches);
  183. if(rv < 0)
  184. return rv;
  185. }
  186. *branches_ = std::move(tmp_branches);
  187. return 0;
  188. }
  189. static
  190. int
  191. add_begin(const std::string &str_,
  192. Branches::Impl *branches_)
  193. {
  194. int rv;
  195. vector<string> paths;
  196. Branches::Impl tmp_branches(branches_->minfreespace());
  197. str::split(str_,':',&paths);
  198. for(auto &path : paths)
  199. {
  200. rv = l::parse(path,&tmp_branches);
  201. if(rv < 0)
  202. return rv;
  203. }
  204. branches_->insert(branches_->begin(),
  205. tmp_branches.begin(),
  206. tmp_branches.end());
  207. return 0;
  208. }
  209. static
  210. int
  211. add_end(const std::string &str_,
  212. Branches::Impl *branches_)
  213. {
  214. int rv;
  215. StrVec paths;
  216. Branches::Impl tmp_branches(branches_->minfreespace());
  217. str::split(str_,':',&paths);
  218. for(auto &path : paths)
  219. {
  220. rv = l::parse(path,&tmp_branches);
  221. if(rv < 0)
  222. return rv;
  223. }
  224. branches_->insert(branches_->end(),
  225. tmp_branches.begin(),
  226. tmp_branches.end());
  227. return 0;
  228. }
  229. static
  230. int
  231. erase_begin(Branches::Impl *branches_)
  232. {
  233. branches_->erase(branches_->begin());
  234. return 0;
  235. }
  236. static
  237. int
  238. erase_end(Branches::Impl *branches_)
  239. {
  240. branches_->pop_back();
  241. return 0;
  242. }
  243. static
  244. int
  245. erase_fnmatch(const std::string &str_,
  246. Branches::Impl *branches_)
  247. {
  248. StrVec patterns;
  249. str::split(str_,':',&patterns);
  250. for(auto i = branches_->begin(); i != branches_->end();)
  251. {
  252. int match = FNM_NOMATCH;
  253. for(auto pi = patterns.cbegin(); pi != patterns.cend() && match != 0; ++pi)
  254. {
  255. match = ::fnmatch(pi->c_str(),i->path.c_str(),0);
  256. }
  257. i = ((match == 0) ? branches_->erase(i) : (i+1));
  258. }
  259. return 0;
  260. }
  261. }
  262. int
  263. Branches::Impl::from_string(const std::string &s_)
  264. {
  265. std::string instr;
  266. std::string values;
  267. l::split(s_,&instr,&values);
  268. if(instr == "+")
  269. return l::add_end(values,this);
  270. if(instr == "+<")
  271. return l::add_begin(values,this);
  272. if(instr == "+>")
  273. return l::add_end(values,this);
  274. if(instr == "-")
  275. return l::erase_fnmatch(values,this);
  276. if(instr == "-<")
  277. return l::erase_begin(this);
  278. if(instr == "->")
  279. return l::erase_end(this);
  280. if(instr == "=")
  281. return l::set(values,this);
  282. if(instr.empty())
  283. return l::set(values,this);
  284. return -EINVAL;
  285. }
  286. std::string
  287. Branches::Impl::to_string(void) const
  288. {
  289. string tmp;
  290. if(empty())
  291. return tmp;
  292. for(auto &branch : *this)
  293. {
  294. tmp += branch.to_string();
  295. tmp += ':';
  296. }
  297. tmp.pop_back();
  298. return tmp;
  299. }
  300. void
  301. Branches::Impl::to_paths(StrVec &paths_) const
  302. {
  303. for(auto &branch : *this)
  304. {
  305. paths_.push_back(branch.path);
  306. }
  307. }
  308. fs::PathVector
  309. Branches::Impl::to_paths() const
  310. {
  311. fs::PathVector vp;
  312. for(const auto &branch : *this)
  313. vp.emplace_back(branch.path);
  314. return vp;
  315. }
  316. int
  317. Branches::from_string(const std::string &str_)
  318. {
  319. int rv;
  320. Branches::Ptr impl;
  321. Branches::Ptr new_impl;
  322. {
  323. std::lock_guard<std::mutex> lock_guard(_mutex);
  324. impl = _impl;
  325. }
  326. new_impl = std::make_shared<Branches::Impl>(impl->minfreespace());
  327. *new_impl = *impl;
  328. rv = new_impl->from_string(str_);
  329. if(rv < 0)
  330. return rv;
  331. {
  332. std::lock_guard<std::mutex> lock_guard(_mutex);
  333. _impl = new_impl;
  334. }
  335. return 0;
  336. }
  337. string
  338. Branches::to_string(void) const
  339. {
  340. std::lock_guard<std::mutex> lock_guard(_mutex);
  341. return _impl->to_string();
  342. }
  343. void
  344. Branches::find_and_set_mode_ro()
  345. {
  346. for(auto &branch : *_impl)
  347. {
  348. if(branch.mode != Branch::Mode::RW)
  349. continue;
  350. if(!fs::is_rofs_but_not_mounted_ro(branch.path))
  351. continue;
  352. syslog_warning("Branch %s found to be readonly - setting its mode to RO",
  353. branch.path.c_str());
  354. branch.mode = Branch::Mode::RO;
  355. }
  356. }
  357. SrcMounts::SrcMounts(Branches &b_)
  358. : _branches(b_)
  359. {
  360. }
  361. int
  362. SrcMounts::from_string(const std::string &s_)
  363. {
  364. // return _branches.from_string(s_);
  365. return 0;
  366. }
  367. std::string
  368. SrcMounts::to_string(void) const
  369. {
  370. std::string rv;
  371. Branches::CPtr branches = _branches;
  372. if(branches->empty())
  373. return rv;
  374. for(const auto &branch : *branches)
  375. {
  376. rv += branch.path;
  377. rv += ':';
  378. }
  379. rv.pop_back();
  380. return rv;
  381. }