dinit-env.cc 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #include <iostream>
  2. #include <fstream>
  3. #include "dinit-log.h"
  4. #include "dinit-env.h"
  5. environment main_env;
  6. // Log a parse error when reading the environment file.
  7. static void log_bad_env(int linenum)
  8. {
  9. log(loglevel_t::ERROR, "Invalid environment variable setting in environment file (line ", linenum, ")");
  10. }
  11. static void log_bad_env_cmd(int linenum)
  12. {
  13. log(loglevel_t::ERROR, "Unknown command in environment file (line ", linenum, ")");
  14. }
  15. // Read and set environment variables from a file. May throw std::bad_alloc, std::system_error.
  16. void read_env_file(const char *env_file_path, bool log_warnings, environment &env)
  17. {
  18. std::ifstream env_file(env_file_path);
  19. if (! env_file) return;
  20. env_file.exceptions(std::ios::badbit);
  21. auto &clocale = std::locale::classic();
  22. std::string line;
  23. int linenum = 0;
  24. while (std::getline(env_file, line)) {
  25. linenum++;
  26. auto lpos = line.begin();
  27. auto lend = line.end();
  28. while (lpos != lend && std::isspace(*lpos, clocale)) {
  29. ++lpos;
  30. }
  31. if (lpos == lend) continue; // empty line
  32. if (*lpos == '#') {
  33. continue;
  34. }
  35. if (*lpos == '=') {
  36. if (log_warnings) {
  37. log_bad_env(linenum);
  38. }
  39. continue;
  40. }
  41. // "!COMMAND" form.
  42. if (*lpos == '!') {
  43. ++lpos; // lpos = first char of command
  44. auto epos = lpos;
  45. do {
  46. ++epos;
  47. } while(epos != lend && !std::isspace(*epos, clocale));
  48. const char *lpos_p = line.data() + (lpos - line.begin());
  49. string_view cmd {lpos_p, (size_t)(epos - lpos)};
  50. std::vector<string_view> cmd_args;
  51. while (epos != lend) {
  52. // skip whitespace
  53. while (std::isspace(*epos, clocale)) {
  54. ++epos;
  55. if (epos == lend) goto process_cmd; // no more args
  56. }
  57. // all non-ws is argument until next ws
  58. const char *arg_begin = line.c_str() + (epos - line.begin());
  59. auto arg_begin_i = epos;
  60. while (epos != lend && !std::isspace(*epos)) {
  61. ++epos;
  62. }
  63. cmd_args.push_back(string_view {arg_begin, (size_t)(epos - arg_begin_i)});
  64. }
  65. process_cmd:
  66. if (cmd == "clear") {
  67. env.clear_no_inherit();
  68. }
  69. else if (cmd == "unset") {
  70. for (string_view arg : cmd_args) {
  71. env.undefine_var(std::string(arg.data(), arg.length()));
  72. }
  73. }
  74. else if (cmd == "import") {
  75. for (string_view arg : cmd_args) {
  76. env.import_parent_var(std::string(arg.data(), arg.length()));
  77. }
  78. }
  79. else if (log_warnings) {
  80. log_bad_env_cmd(linenum);
  81. }
  82. continue;
  83. }
  84. // ENV=VALUE form.
  85. auto name_begin = lpos++;
  86. // skip until '=' or whitespace:
  87. while (lpos != lend && *lpos != '=' && !std::isspace(*lpos, clocale)) ++lpos;
  88. auto name_end = lpos;
  89. // skip whitespace:
  90. while (lpos != lend && std::isspace(*lpos, clocale)) ++lpos;
  91. if (lpos == lend || *lpos != '=') {
  92. if (log_warnings) {
  93. log_bad_env(linenum);
  94. }
  95. continue;
  96. }
  97. ++lpos;
  98. auto val_begin = lpos;
  99. auto val_end = lend;
  100. if (val_begin != (name_end + 1) || name_begin != line.begin()) {
  101. // there are spaces that we need to eliminate
  102. std::string name_and_val;
  103. name_and_val.reserve((name_end - name_begin) + 1 + (val_end - val_begin));
  104. name_and_val = line.substr(name_begin - line.begin(), name_end - name_begin);
  105. name_and_val.append(1, '=');
  106. name_and_val.append(val_begin, val_end);
  107. env.set_var(std::move(name_and_val));
  108. }
  109. else {
  110. line.shrink_to_fit();
  111. env.set_var(std::move(line));
  112. }
  113. }
  114. }