9 #include "unitempgen.h"
11 #include "wvmoniker.h"
12 #include "wvstringmask.h"
15 #include "wvlinkerhack.h"
31 : filename(_filename), create_mode(_create_mode), log(_filename), save_cb(_save_cb)
35 memset(&old_st, 0,
sizeof(old_st));
44 if (value.isnull() && key.
isempty())
50 UniIniGen::~UniIniGen()
57 WvFile file(filename, O_RDONLY);
61 if (file.
isok() && fstat(file.
getrfd(), &statbuf) == -1)
63 log(WvLog::Warning,
"Can't stat '%s': %s\n",
64 filename, strerror(errno));
68 if (file.
isok() && (statbuf.st_mode & S_ISVTX))
75 && statbuf.st_ctime == old_st.st_ctime
76 && statbuf.st_dev == old_st.st_dev
77 && statbuf.st_ino == old_st.st_ino
78 && statbuf.st_blocks == old_st.st_blocks
79 && statbuf.st_size == old_st.st_size)
81 log(WvLog::Debug3,
"refresh: file hasn't changed; do nothing.\n");
84 memcpy(&old_st, &statbuf,
sizeof(statbuf));
90 "Can't open '%s' for reading: %s\n"
91 "...starting with blank configuration.\n",
92 filename, file.errstr());
116 WVTCL_NASTY_NEWLINES,
122 int len = strlen(str);
123 if (len == 0)
continue;
132 if (str[0] ==
'[' && str[len - 1] ==
']')
156 assert(*value ==
'=');
168 "Ignoring malformed input line: \"%s\"\n", word);
175 size_t offset = buf.
strchr(
'\n');
180 "XXX Ignoring malformed input line: \"%s\"\n", line1);
187 "Error reading from config file: %s\n", file.errstr());
199 oldtree->
compare(newtree, wv::bind(&UniIniGen::refreshcomparator,
this,
232 a->
visit(wv::bind(&UniIniGen::notify_deleted,
this, _1, _2),
248 bool UniIniGen::commit_atomic(WvStringParm real_filename)
252 if (lstat(real_filename, &statbuf) == -1)
258 if (!S_ISREG(statbuf.st_mode))
261 WvString tmp_filename(
"%s.tmp%s", real_filename, getpid());
262 WvFile file(tmp_filename, O_WRONLY|O_TRUNC|O_CREAT, 0000);
266 log(WvLog::Warning,
"Can't write '%s': %s\n",
267 tmp_filename, strerror(errno));
268 unlink(tmp_filename);
275 mode_t theumask = umask(0);
277 fchmod(file.getwfd(), create_mode & ~theumask);
281 if (file.geterr() || rename(tmp_filename, real_filename) == -1)
283 log(WvLog::Warning,
"Can't write '%s': %s\n",
284 filename, strerror(errno));
285 unlink(tmp_filename);
304 WvFile file(filename, O_WRONLY|O_TRUNC|O_CREAT, create_mode);
309 log(WvLog::Warning,
"Can't write '%s': %s\n",
310 filename, file.errstr());
315 char resolved_path[PATH_MAX];
317 if (realpath(filename, resolved_path) != NULL)
318 real_filename = resolved_path;
320 if (!commit_atomic(real_filename))
322 WvFile file(real_filename, O_WRONLY|O_TRUNC|O_CREAT, create_mode);
325 if (fstat(file.
getwfd(), &statbuf) == -1)
327 log(WvLog::Warning,
"Can't write '%s' ('%s'): %s\n",
328 filename, real_filename, strerror(errno));
332 fchmod(file.
getwfd(), (statbuf.st_mode & 07777) | S_ISVTX);
340 statbuf.st_mode = statbuf.st_mode & ~S_ISVTX;
341 fchmod(file.
getwfd(), statbuf.st_mode & 07777);
344 log(WvLog::Warning,
"Error writing '%s' ('%s'): %s\n",
345 filename, real_filename, file.errstr());
357 static bool absolutely_needs_escape(WvStringParm s,
const char *sepchars)
361 bool inescape =
false, inspace =
false;
363 if (isspace((
unsigned char)*s))
366 for (cptr = s; *cptr; cptr++)
370 else if (!numbraces && strchr(sepchars, *cptr))
372 else if (*cptr ==
'\\')
374 else if (*cptr ==
'{')
376 else if (*cptr ==
'}')
379 inspace = isspace((
unsigned char)*cptr);
385 if (inescape || inspace)
396 static void printsection(
WvStream &file,
const UniConfKey &key, UniIniGen::SaveCallback save_cb)
401 if (absolutely_needs_escape(key,
"\r\n[]"))
417 WvStringParm _value, UniIniGen::SaveCallback save_cb)
422 if (absolutely_needs_escape(_key,
"\r\n[]=#\""))
431 if (absolutely_needs_escape(_value,
"\r\n"))
452 bool recursive, UniIniGen::SaveCallback save_cb)
455 for (it.rewind(); it.next(); )
472 printsection(file, toplevel.
fullkey(), save_cb);
473 printedsection =
true;
475 printkey(file, node.
fullkey(&toplevel), node.
value(), save_cb);
480 save_sect(file, toplevel, node, printedsection, recursive, save_cb);
489 if (!&parent)
return;
496 if (!!parent.
value())
497 printkey(file, parent.
key(), parent.
value(), save_cb);
500 bool printedsection =
false;
502 save_sect(file, parent, parent, printedsection,
false, save_cb);
505 for (it.rewind(); it.next(); )
509 printedsection =
false;
510 save_sect(file, node, node, printedsection,
true, save_cb);