+ if (fd >= 0) {
+ i = 0;
+ fd_close[i++] = fd;
+ while((db_fd = dup(fd)) < MIN_DB_FD) {
+ fd_close[i++] = db_fd;
+ }
+ while(--i >= 0) {
+ close(fd_close[i]);
+ }
+ db_file = fdopen(db_fd, "a");
+ }
+
+ if (annotation) {
+ /*
+ * Make the first debug log file entry.
+ */
+ debug_printf(_("pid %ld ruid %ld euid %ld: %s at %s"),
+ (long)getpid(),
+ (long)getuid(), (long)geteuid(),
+ annotation,
+ ctime(&open_time));
+ }
+}
+
+/* Get current GMT time and return a message timestamp.
+ * Used for g_printf calls to logs and such. The return value
+ * is to a static buffer, so it should be used immediately.
+ *
+ * @returns: timestamp
+ */
+static char *
+msg_timestamp(void)
+{
+ static char timestamp[128];
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ g_snprintf(timestamp, SIZEOF(timestamp), "%lld.%06ld",
+ (long long)tv.tv_sec, (long)tv.tv_usec);
+
+ return timestamp;
+}
+
+/*
+ * ---- public functions
+ */
+
+void
+set_logerror(void (*f)(char *))
+{
+ logerror_fn = f;
+}
+
+void
+debug_open(char *subdir)
+{
+ int fd = -1;
+ int i;
+ char *s = NULL;
+ mode_t mask;
+
+ /* set up logging while we're here */
+ debug_setup_logging();
+
+ /* set 'dbgdir' and clean out old debug files */
+ debug_setup_1(NULL, subdir);
+
+ /*
+ * Create the new file with a unique sequence number.
+ */
+ mask = (mode_t)umask((mode_t)0037); /* Allow the group read bit through */
+
+ /* iteratate through sequence numbers until we find one that
+ * is not already in use */
+ for(i = 0; fd < 0; i++) {
+ amfree(db_name);
+ if ((db_name = get_debug_name(open_time, i)) == NULL) {
+ error(_("Cannot create debug file name in %d tries."), i);
+ /*NOTREACHED*/
+ }
+
+ if ((s = newvstralloc(s, dbgdir, db_name, NULL)) == NULL) {
+ error(_("Cannot allocate debug file name memory"));
+ /*NOTREACHED*/
+ }
+
+ if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
+ if (errno != EEXIST) {
+ error(_("Cannot create debug file \"%s\": %s"),
+ s, strerror(errno));
+ /*NOTREACHED*/
+ }
+ amfree(s);
+ }
+ }
+ (void)umask(mask); /* Restore mask */
+
+ /*
+ * Finish setup.
+ *
+ * Note: we release control of the string 's' points to.
+ */
+ debug_setup_2(s, fd, "start");
+}
+
+void
+debug_reopen(
+ char * dbfilename,
+ char * annotation)
+{
+ char *s = NULL;
+ int fd;
+
+ if (dbfilename == NULL) {
+ return;
+ }
+
+ /* set 'dbgdir' and clean out old debug files */
+ debug_setup_1(NULL, NULL);
+
+ /*
+ * Reopen the file.
+ */
+ if (*dbfilename == '/') {
+ s = stralloc(dbfilename);
+ } else {
+ s = newvstralloc(s, dbgdir, dbfilename, NULL);
+ }
+ if ((fd = open(s, O_RDWR|O_APPEND)) < 0) {
+ error(_("cannot reopen debug file %s"), dbfilename);
+ /*NOTREACHED*/
+ }
+
+ /*
+ * Finish setup.
+ *
+ * Note: we release control of the string 's' points to.
+ */
+ debug_setup_2(s, fd, annotation);
+}
+
+void
+debug_rename(
+ char *config,
+ char *subdir)
+{
+ int fd = -1;
+ int i;
+ char *s = NULL;
+ mode_t mask;
+
+ if (!db_filename)
+ return;
+
+ /* set 'dbgdir' and clean out old debug files */
+ debug_setup_1(config, subdir);
+
+ s = newvstralloc(s, dbgdir, db_name, NULL);
+
+ if (strcmp(db_filename, s) == 0) {
+ amfree(s);
+ return;
+ }
+
+ mask = (mode_t)umask((mode_t)0037);
+
+#if defined(__CYGWIN__)
+ /*
+ * On cygwin, rename will not overwrite an existing file nor
+ * will it rename a file that is open for writing...
+ *
+ * Rename file directly. Expect failure if file already exists
+ * or is open by another user.
+ */
+