Log(LogInformation, "ConfigObject")
<< "Dumping program state to file '" << filename << "'";
- String tempFilename = filename + ".tmp";
-
std::fstream fp;
- fp.open(tempFilename.CStr(), std::ios_base::out);
+ String tempFilename = Utility::CreateTempFile(filename + ".XXXXXX", fp);
if (!fp)
BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file"));
Log(LogInformation, "ScriptGlobal")
<< "Dumping variables to file '" << filename << "'";
- String tempFilename = filename + ".tmp";
-
std::fstream fp;
- fp.open(tempFilename.CStr(), std::ios_base::out);
+ String tempFilename = Utility::CreateTempFile(filename + ".XXXXXX", fp);
if (!fp)
BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file"));
#ifdef _WIN32
# include <VersionHelpers.h>
+# include <windows.h>
+# include <io.h>
#endif /*_WIN32*/
using namespace icinga;
void Utility::SaveJsonFile(const String& path, const Value& value)
{
- String tempPath = path + ".tmp";
+ std::fstream fp;
+ String tempFilename = Utility::CreateTempFile(path + ".XXXXXX", fp);
- std::ofstream fp(tempPath.CStr(), std::ofstream::out | std::ostream::trunc);
fp.exceptions(std::ofstream::failbit | std::ofstream::badbit);
fp << JsonEncode(value);
fp.close();
_unlink(path.CStr());
#endif /* _WIN32 */
- if (rename(tempPath.CStr(), path.CStr()) < 0) {
+ if (rename(tempFilename.CStr(), path.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(tempPath));
+ << boost::errinfo_file_name(tempFilename));
}
}
return output;
}
+
+String Utility::CreateTempFile(const String& path, std::fstream& fp)
+{
+ std::vector<char> targetPath(path.Begin(), path.End());
+ targetPath.push_back('\0');
+
+ int fd;
+#ifndef _WIN32
+ fd = mkstemp(&targetPath[0]);
+#else /* _WIN32 */
+ fd = MksTemp(&targetPath[0]);
+#endif /*_WIN32*/
+
+ if (fd < 0) {
+ BOOST_THROW_EXCEPTION(posix_error()
+ << boost::errinfo_api_function("mkstemp")
+ << boost::errinfo_errno(errno)
+ << boost::errinfo_file_name(path));
+ }
+
+ try {
+ fp.open(&targetPath[0], std::ios_base::trunc | std::ios_base::out);
+ } catch (const std::fstream::failure& e) {
+ close(fd);
+ throw;
+ }
+
+ close(fd);
+
+ return String(targetPath.begin(), targetPath.end() - 1);
+}
+
+#ifdef _WIN32
+/* mkstemp extracted from libc/sysdeps/posix/tempname.c. Copyright
+ (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version. */
+
+#define _O_EXCL 0x0400
+#define _O_CREAT 0x0100
+#define _O_RDWR 0x0002
+#define O_EXCL _O_EXCL
+#define O_CREAT _O_CREAT
+#define O_RDWR _O_RDWR
+
+static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+/* Generate a temporary file name based on TMPL. TMPL must match the
+ rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed
+ does not exist at the time of the call to mkstemp. TMPL is
+ overwritten with the result. */
+int Utility::MksTemp(char *tmpl)
+{
+ int len;
+ char *XXXXXX;
+ static unsigned long long value;
+ unsigned long long random_time_bits;
+ unsigned int count;
+ int fd = -1;
+ int save_errno = errno;
+
+ /* A lower bound on the number of temporary files to attempt to
+ generate. The maximum total number of temporary file names that
+ can exist for a given template is 62**6. It should never be
+ necessary to try all these combinations. Instead if a reasonable
+ number of names is tried (we define reasonable as 62**3) fail to
+ give the system administrator the chance to remove the problems. */
+#define ATTEMPTS_MIN (62 * 62 * 62)
+
+ /* The number of times to attempt to generate a temporary file. To
+ conform to POSIX, this must be no smaller than TMP_MAX. */
+#if ATTEMPTS_MIN < TMP_MAX
+ unsigned int attempts = TMP_MAX;
+#else
+ unsigned int attempts = ATTEMPTS_MIN;
+#endif
+
+ len = strlen (tmpl);
+ if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX")) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* This is where the Xs start. */
+ XXXXXX = &tmpl[len - 6];
+
+ /* Get some more or less random data. */
+ {
+ SYSTEMTIME stNow;
+ FILETIME ftNow;
+
+ // get system time
+ GetSystemTime(&stNow);
+ stNow.wMilliseconds = 500;
+ if (!SystemTimeToFileTime(&stNow, &ftNow)) {
+ errno = -1;
+ return -1;
+ }
+
+ random_time_bits = (((unsigned long long)ftNow.dwHighDateTime << 32) | (unsigned long long)ftNow.dwLowDateTime);
+ }
+
+ value += random_time_bits ^ (unsigned long long)GetCurrentThreadId();
+
+ for (count = 0; count < attempts; value += 7777, ++count) {
+ unsigned long long v = value;
+
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
+
+ fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE);
+ if (fd >= 0) {
+ errno = save_errno;
+ return fd;
+ } else if (errno != EEXIST)
+ return -1;
+ }
+
+ /* We got out of the loop because we ran out of combinations to try. */
+ errno = EEXIST;
+ return -1;
+}
+#endif /*_WIN32*/
static String ValidateUTF8(const String& input);
+ static String CreateTempFile(const String& path, std::fstream& fp);
+
private:
Utility(void);
static void CollectPaths(const String& path, std::vector<String>& paths);
+#ifdef _WIN32
+ static int MksTemp (char *tmpl);
+#endif /* _WIN32 */
+
static boost::thread_specific_ptr<String> m_ThreadName;
static boost::thread_specific_ptr<unsigned int> m_RandSeed;
};
{
String api_username = "root"; // TODO make this available as cli parameter?
String api_password = RandomString(8);
- String apiuserspath = GetConfdPath() + "/api-users.conf";
+ String apiUsersPath = GetConfdPath() + "/api-users.conf";
- if (Utility::PathExists(apiuserspath)) {
+ if (Utility::PathExists(apiUsersPath)) {
Log(LogInformation, "cli")
- << "API user config file '" << apiuserspath << "' already exists, not creating config file.";
+ << "API user config file '" << apiUsersPath << "' already exists, not creating config file.";
return true;
}
Log(LogInformation, "cli")
- << "Adding new ApiUser '" << api_username << "' in '" << apiuserspath << "'.";
+ << "Adding new ApiUser '" << api_username << "' in '" << apiUsersPath << "'.";
- NodeUtility::CreateBackupFile(apiuserspath);
+ NodeUtility::CreateBackupFile(apiUsersPath);
- String apiuserspathtmp = apiuserspath + ".tmp";
-
- std::ofstream fp;
- fp.open(apiuserspathtmp.CStr(), std::ofstream::out | std::ofstream::trunc);
+ std::fstream fp;
+ String tempFilename = Utility::CreateTempFile(apiUsersPath + ".XXXXXX", fp);
fp << "/**\n"
<< " * The APIUser objects are used for authentication against the API.\n"
fp.close();
#ifdef _WIN32
- _unlink(apiuserspath.CStr());
+ _unlink(apiUsersPath.CStr());
#endif /* _WIN32 */
- if (rename(apiuserspathtmp.CStr(), apiuserspath.CStr()) < 0) {
+ if (rename(tempFilename.CStr(), apiUsersPath.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(apiuserspathtmp));
+ << boost::errinfo_file_name(tempFilename));
}
return true;
String apipath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf";
NodeUtility::CreateBackupFile(apipath);
- String apipathtmp = apipath + ".tmp";
-
- std::ofstream fp;
- fp.open(apipathtmp.CStr(), std::ofstream::out | std::ofstream::trunc);
+ std::fstream fp;
+ String tempApiPath = Utility::CreateTempFile(apipath + ".XXXXXX", fp);
fp << "/**\n"
<< " * The API listener is used for distributed monitoring setups.\n"
_unlink(apipath.CStr());
#endif /* _WIN32 */
- if (rename(apipathtmp.CStr(), apipath.CStr()) < 0) {
+ if (rename(tempApiPath.CStr(), apipath.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(apipathtmp));
+ << boost::errinfo_file_name(tempApiPath));
}
/* update constants.conf with NodeName = CN + TicketSalt = random value */
String apipath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf";
NodeUtility::CreateBackupFile(apipath);
- String apipathtmp = apipath + ".tmp";
-
- std::ofstream fp;
- fp.open(apipathtmp.CStr(), std::ofstream::out | std::ofstream::trunc);
+ std::fstream fp;
+ String tempApiPath = Utility::CreateTempFile(apipath + ".XXXXXX", fp);
fp << "/**\n"
<< " * The API listener is used for distributed monitoring setups.\n"
_unlink(apipath.CStr());
#endif /* _WIN32 */
- if (rename(apipathtmp.CStr(), apipath.CStr()) < 0) {
+ if (rename(tempApiPath.CStr(), apipath.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(apipathtmp));
+ << boost::errinfo_file_name(tempApiPath));
}
/* generate local zones.conf with zone+endpoint */
<< "Cannot set ownership for user '" << user << "' group '" << group << "' on path '" << path << "'. Verify it yourself!";
}
- String tempPath = filename + ".tmp";
-
- std::ofstream fp(tempPath.CStr(), std::ofstream::out | std::ostream::trunc);
+ std::fstream fp;
+ String tempFilename = Utility::CreateTempFile(filename + ".XXXXXX", fp);
fp << "/*\n";
fp << " * Generated by Icinga 2 node setup commands\n";
_unlink(filename.CStr());
#endif /* _WIN32 */
- if (rename(tempPath.CStr(), filename.CStr()) < 0) {
+ if (rename(tempFilename.CStr(), filename.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(tempPath));
+ << boost::errinfo_file_name(tempFilename));
}
return true;
void NodeUtility::UpdateConstant(const String& name, const String& value)
{
String constantsFile = Application::GetSysconfDir() + "/icinga2/constants.conf";
- String tempFile = constantsFile + ".tmp";
std::ifstream ifp(constantsFile.CStr());
- std::ofstream ofp(tempFile.CStr());
+ std::fstream ofp;
+ String tempFile = Utility::CreateTempFile(constantsFile + ".XXXXXX", ofp);
bool found = false;
String apipath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf";
NodeUtility::CreateBackupFile(apipath);
- String apipathtmp = apipath + ".tmp";
-
- std::ofstream fp;
- fp.open(apipathtmp.CStr(), std::ofstream::out | std::ofstream::trunc);
+ std::fstream fp;
+ String tempApiPath = Utility::CreateTempFile(apipath + ".XXXXXX", fp);
fp << "/**\n"
<< " * The API listener is used for distributed monitoring setups.\n"
_unlink(apipath.CStr());
#endif /* _WIN32 */
- if (rename(apipathtmp.CStr(), apipath.CStr()) < 0) {
+ if (rename(tempApiPath.CStr(), apipath.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(apipathtmp));
+ << boost::errinfo_file_name(tempApiPath));
}
/* apilistener config */
String apipath = FeatureUtility::GetFeaturesAvailablePath() + "/api.conf";
NodeUtility::CreateBackupFile(apipath);
- String apipathtmp = apipath + ".tmp";
- std::ofstream fp;
- fp.open(apipathtmp.CStr(), std::ofstream::out | std::ofstream::trunc);
+ std::fstream fp;
+ String tempApiPath = Utility::CreateTempFile(apipath + ".XXXXXX", fp);
fp << "/**\n"
<< " * The API listener is used for distributed monitoring setups.\n"
_unlink(apipath.CStr());
#endif /* _WIN32 */
- if (rename(apipathtmp.CStr(), apipath.CStr()) < 0) {
+ if (rename(tempApiPath.CStr(), apipath.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(apipathtmp));
+ << boost::errinfo_file_name(tempApiPath));
}
/* update constants.conf with NodeName = CN + TicketSalt = random value */
CreateRepositoryPath(Utility::DirName(path));
- String tempPath = path + ".tmp";
+ std::fstream fp;
+ String tempFilename = Utility::CreateTempFile(path + ".XXXXXX", fp);
- std::ofstream fp(tempPath.CStr(), std::ofstream::out | std::ostream::trunc);
fp << JsonEncode(item);
fp.close();
_unlink(path.CStr());
#endif /* _WIN32 */
- if (rename(tempPath.CStr(), path.CStr()) < 0) {
+ if (rename(tempFilename.CStr(), path.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(tempPath));
+ << boost::errinfo_file_name(tempFilename));
}
return true;
CreateRepositoryPath(Utility::DirName(path));
- String tempPath = path + ".tmp";
+ std::fstream fp;
+ String tempFilename = Utility::CreateTempFile(path + ".XXXXXX", fp);
- std::ofstream fp(tempPath.CStr(), std::ofstream::out | std::ostream::trunc);
SerializeObject(fp, name, type, item);
fp << std::endl;
fp.close();
_unlink(path.CStr());
#endif /* _WIN32 */
- if (rename(tempPath.CStr(), path.CStr()) < 0) {
+ if (rename(tempFilename.CStr(), path.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(tempPath));
+ << boost::errinfo_file_name(tempFilename));
}
return true;
{
CONTEXT("Writing objects.cache file");
- String objectspath = GetObjectsPath();
- String objectspathtmp = objectspath + ".tmp";
+ String objectsPath = GetObjectsPath();
- std::ofstream objectfp;
- objectfp.open(objectspathtmp.CStr(), std::ofstream::out | std::ofstream::trunc);
+ std::fstream objectfp;
+ String tempObjectsPath = Utility::CreateTempFile(objectsPath + ".XXXXXX", objectfp);
objectfp << std::fixed;
objectfp.close();
#ifdef _WIN32
- _unlink(objectspath.CStr());
+ _unlink(objectsPath.CStr());
#endif /* _WIN32 */
- if (rename(objectspathtmp.CStr(), objectspath.CStr()) < 0) {
+ if (rename(tempObjectsPath.CStr(), objectsPath.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(objectspathtmp));
+ << boost::errinfo_file_name(tempObjectsPath));
}
}
double start = Utility::GetTime();
- String statuspath = GetStatusPath();
- String statuspathtmp = statuspath + ".tmp"; /* XXX make this a global definition */
+ String statusPath = GetStatusPath();
- std::ofstream statusfp;
- statusfp.open(statuspathtmp.CStr(), std::ofstream::out | std::ofstream::trunc);
+ std::fstream statusfp;
+ String tempStatusPath = Utility::CreateTempFile(statusPath + ".XXXXXX", statusfp);
statusfp << std::fixed;
statusfp.close();
#ifdef _WIN32
- _unlink(statuspath.CStr());
+ _unlink(statusPath.CStr());
#endif /* _WIN32 */
- if (rename(statuspathtmp.CStr(), statuspath.CStr()) < 0) {
+ if (rename(tempStatusPath.CStr(), statusPath.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(statuspathtmp));
+ << boost::errinfo_file_name(tempStatusPath));
}
Log(LogNotice, "StatusDataWriter")
{
m_ObjectsPath = filename;
- String tempFilename = m_ObjectsPath + ".tmp";
-
std::fstream *fp = new std::fstream();
- fp->open(tempFilename.CStr(), std::ios_base::out);
+ m_ObjectsTempFile = Utility::CreateTempFile(filename + ".XXXXXX", *fp);
if (!*fp)
- BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file"));
+ BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + m_ObjectsTempFile + "' file"));
m_ObjectsFP = new StdioStream(fp, true);
}
m_ObjectsFP->Close();
m_ObjectsFP.reset();
- String tempFilename = m_ObjectsPath + ".tmp";
-
#ifdef _WIN32
_unlink(m_ObjectsPath.CStr());
#endif /* _WIN32 */
- if (rename(tempFilename.CStr(), m_ObjectsPath.CStr()) < 0) {
+ if (rename(m_ObjectsTempFile.CStr(), m_ObjectsPath.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(tempFilename));
+ << boost::errinfo_file_name(m_ObjectsTempFile));
}
}
private:
String m_ObjectsPath;
+ String m_ObjectsTempFile;
StdioStream::Ptr m_ObjectsFP;
mutable boost::mutex m_Mutex;
return Empty;
String repositoryFile = GetRepositoryDir() + SHA256(params->Get("endpoint")) + ".repo";
- String repositoryTempFile = repositoryFile + ".tmp";
- std::ofstream fp(repositoryTempFile.CStr(), std::ofstream::out | std::ostream::trunc);
+ std::fstream fp;
+ String tempRepositoryFile = Utility::CreateTempFile(repositoryFile + ".XXXXXX", fp);
+
fp << JsonEncode(params);
fp.close();
_unlink(repositoryFile.CStr());
#endif /* _WIN32 */
- if (rename(repositoryTempFile.CStr(), repositoryFile.CStr()) < 0) {
+ if (rename(tempRepositoryFile.CStr(), repositoryFile.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(repositoryTempFile));
+ << boost::errinfo_file_name(tempRepositoryFile));
}
ApiListener::Ptr listener = ApiListener::GetInstance();
DumpProgramState();
}
-static void PersistModAttrHelper(std::ofstream& fp, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value)
+static void PersistModAttrHelper(std::fstream& fp, ConfigObject::Ptr& previousObject, const ConfigObject::Ptr& object, const String& attr, const Value& value)
{
if (object != previousObject) {
if (previousObject) {
void IcingaApplication::DumpModifiedAttributes(void)
{
String path = GetModAttrPath();
- String pathtmp = path + ".tmp";
- std::ofstream fp;
- fp.open(pathtmp.CStr(), std::ofstream::out | std::ofstream::trunc);
+ std::fstream fp;
+ String tempFilename = Utility::CreateTempFile(path + ".XXXXXX", fp);
ConfigObject::Ptr previousObject;
ConfigObject::DumpModifiedAttributes(boost::bind(&PersistModAttrHelper, boost::ref(fp), boost::ref(previousObject), _1, _2, _3));
_unlink(path.CStr());
#endif /* _WIN32 */
- if (rename(pathtmp.CStr(), path.CStr()) < 0) {
+ if (rename(tempFilename.CStr(), path.CStr()) < 0) {
BOOST_THROW_EXCEPTION(posix_error()
<< boost::errinfo_api_function("rename")
<< boost::errinfo_errno(errno)
- << boost::errinfo_file_name(pathtmp));
+ << boost::errinfo_file_name(tempFilename));
}
}