Patch: Elm ME+ 2.5 PLalpha54 -> Elm ME+ 2.5 PLalpha60 [5/13] (4/4)
From
Kari Hurtta@21:1/5 to
All on Thu Nov 24 20:26:44 2022
[continued from previous message]
}
!
! }
!
!
! while (havetodo > 0) {
! DPRINT(Debug,14, (&Debug,
! "write_conf: %d files to do\n",
! havetodo));
!
! havetodo = 0;
!
! if (need_sleep) {
! DPRINT(Debug,14, (&Debug,
! "write_conf: Sleeping for %d seconds\n",
! need_sleep));
! if (POLL_method)
! wait_for_timeout(need_sleep);
! else
! sleep(need_sleep);
!
! }
! need_sleep = 0;
!
! for (i = 0; i < cfiles_num; i++) {
! int close_this = 0;
!
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s proceed=%d",
! cfiles[i].shortname,
! config_handles[i].proceed));
! switch (config_handles[i].proceed) {
! case config_handle_skip: DPRINT(Debug,14, (&Debug," config_handle_skip")); break;
! case config_handle_merge: DPRINT(Debug,14, (&Debug," config_handle_merge")); break;
! case config_handle_dump: DPRINT(Debug,14, (&Debug," config_handle_dump")); break;
! case config_handle_done: DPRINT(Debug,14, (&Debug," config_handle_done")); break;
! }
! DPRINT(Debug,14, (&Debug,"\n"));
!
! switch (config_handles[i].proceed) {
! int err;
! case config_handle_skip:
!
! break;
! case config_handle_merge:
!
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s checking current file %s for merge\n",
! cfiles[i].shortname,
! cfiles[i].fname));
!
! err = can_open(cfiles[i].fname,"r+");
!
! if (err) {
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s - can_open current file %s: %s\n",
! cfiles[i].shortname,
! cfiles[i].fname,
! strerror(err)));
!
! goto have_old_fd_error;
! }
!
! if (-1 == config_handles[i].old_fd) {
!
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s opening current file %s for merge\n",
! cfiles[i].shortname,
! cfiles[i].fname));
!
! /* need open bot reading and writing
! so that file can have exclusive lock
! */
!
! config_handles[i].old_fd = open(cfiles[i].fname,O_RDWR);
! config_handles[i].old_fd_have_stat = 0;
!
! if (-1 == config_handles[i].old_fd) {
! err = errno;
!
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s - open current file %s: %s\n",
! cfiles[i].shortname,
! cfiles[i].fname,
! strerror(err)));
!
! have_old_fd_error:
! if (EINTR == err) {
! havetodo++;
! goto oops;
! }
!
! if (config_handles[i].loop_message_printed) {
! lib_transient(CATGETS(elm_msg_cat, MeSet,
! MeConfigWaitingFail,
! "Waiting config file %s to be updated... Fail: %s"),
! cfiles[i].fname,strerror(err));
! }
!
!
! if (ENOENT == err) {
! config_handles[i].proceed = config_handle_dump;
!
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s - current file %s: %s -- no merge\n",
! cfiles[i].shortname,
! cfiles[i].fname,
! strerror(err)));
!
! goto no_merge;
! }
!
! if (config_handles[i].loop_message_printed && sleepmsg > 0) { /* HACK */
! if (POLL_method)
! wait_for_timeout(sleepmsg);
! else
! sleep(sleepmsg);
! }
!
! if (the_time && ! config_handles[i].bck)
! config_handles[i].bck = elm_message(FRM("%s.%04d-%02d-%02d.old"),
! cfiles[i].fname,
! the_time->tm_year+1900,
! the_time->tm_mon+1,
! the_time->tm_mday);
!
! if (config_handles[i].bck) {
! config_handles[i].require_bck = 1;
!
! lib_error(CATGETS(elm_msg_cat, MeSet,
! MeConfigMergeFailed,
! "Config file %s merge failed: %s (backup: %s)"),
! cfiles[i].fname,strerror(err),
! config_handles[i].bck);
! } else {
! lib_error(CATGETS(elm_msg_cat, MeSet,
! MeConfigMergeFailed1,
! "Config file %s merge failed: %s (no backup)"),
! cfiles[i].fname,strerror(err));
!
! }
!
! config_handles[i].proceed = config_handle_dump;
! goto no_merge;
! }
! }
!
!
! if (-1 != config_handles[i].old_fd) {
! enum syscall_status r3;
! enum FLOCKING_status r4;
!
! struct stat filename_stat;
!
! int have_filename_stat = 0;
!
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s fstat %d (current file %s) for changes\n",
! cfiles[i].shortname,
! config_handles[i].old_fd,
! cfiles[i].fname));
!
! config_handles[i].old_fd_have_stat = 0;
!
! r3 = fstat(config_handles[i].old_fd,
! & (config_handles[i].old_fd_stat));
!
! switch (r3) {
! char *X;
! case syscall_success:
!
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s - fstat %d: %s succeed: dev %ld ino %ld size %ld modified %ld",
! cfiles[i].shortname,
! config_handles[i].old_fd,
! cfiles[i].fname,
! (long)config_handles[i].old_fd_stat.st_dev,
! (long)config_handles[i].old_fd_stat.st_ino,
! (long)(config_handles[i].old_fd_stat.st_size),
! (long)(config_handles[i].old_fd_stat.st_mtime)));
!
! X = ctime(& (config_handles[i].old_fd_stat.st_mtime)); ! if (X) { /* ctime() includes newline */
! DPRINT(Debug,14,(&Debug," -- %s",X));
! } else {
! DPRINT(Debug,14,(&Debug,"\n"));
! }
!
! config_handles[i].old_fd_have_stat = 1;
!
!
! break;
! case syscall_error:
! err = errno;
!
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s - fstat %d: %s %s\n",
! cfiles[i].shortname,
! config_handles[i].old_fd,
! cfiles[i].fname,
! strerror(err)));
!
! if (EINTR == err) {
! havetodo++;
! goto oops;
! }
!
! if (config_handles[i].loop_message_printed) {
! lib_transient(CATGETS(elm_msg_cat, MeSet,
! MeConfigWaitingError,
! "Waiting config file %s to be updated... Error: %s"),
! cfiles[i].fname,strerror(err));
! }
!
! break;
! }
!
! /* When write_conf() am_write_changed()
! merges changes from
! <conf_file> and writes <conf_file>.N,
! it locks <conf_file> with exclusive (write
! lock) althouh new file <conf_file>.N
! is written and then renamed to <conf_file>
! */
!
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s locking %d (current file %s) for changes\n",
! cfiles[i].shortname,
! config_handles[i].old_fd,
! cfiles[i].fname));
!
!
! r4 = filelock_fd(config_handles[i].old_fd,
! FLOCKING_exclusive,
! &conf_merge_locking,
! cfiles[i].fname,
! FLOCKING_non_block,
! &err);
!
! switch (r4) {
! case FLOCKING_UNSUPPORTED:
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s - filelock_fd %d: %s: unsupported\n",
! cfiles[i].shortname,
! config_handles[i].old_fd,
! cfiles[i].fname));
! break;
!
! case FLOCKING_FAIL:
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s - filelock_fd %d: %s: %s\n",
! cfiles[i].shortname,
! config_handles[i].old_fd,
! cfiles[i].fname,
! strerror(err)));
!
! if (the_time && ! config_handles[i].bck)
! config_handles[i].bck = elm_message(FRM("%s.%04d-%02d-%02d.old"),
! cfiles[i].fname,
! the_time->tm_year+1900,
! the_time->tm_mon+1,
! the_time->tm_mday);
! if ( config_handles[i].old_fd_have_stat && ! config_handles[i].bck)
! config_handles[i].bck = elm_message(FRM("%s.%lx_%lx.old"),
! cfiles[i].fname,
! (long)config_handles[i].old_fd_stat.st_dev,
! (long)config_handles[i].old_fd_stat.st_ino);
!
! if (config_handles[i].bck) {
! config_handles[i].require_bck = 1;
!
! lib_error(CATGETS(elm_msg_cat, MeSet,
! MeConfigLockingFail,
! "Failed to lock config file %s for merge changes: %s (backup %s)"),
! cfiles[i].fname,
! strerror(err),
! config_handles[i].require_bck);
!
!
! } else {
! lib_error(CATGETS(elm_msg_cat, MeSet,
! MeConfigLockingFail1,
! "Failed to lock config file %s for merge changes: %s (no backup)"),
! cfiles[i].fname,
! strerror(err));
! }
! break;
! case FLOCKING_OK:
! config_handles[i].old_fd_locked = 1;
!
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s - filelock_fd %d: %s locked\n",
! cfiles[i].shortname,
! config_handles[i].old_fd,
! cfiles[i].fname));
!
! break;
! case FLOCKING_RETRY:
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s - filelock_fd %d: %s locking failed (retry)",
! cfiles[i].shortname,
! config_handles[i].old_fd,
! cfiles[i].fname));
! if (err) {
! DPRINT(Debug,14,(&Debug,": %s",
! strerror(err)));
! }
! DPRINT(Debug,14,(&Debug,"\n"));
!
! if (EINTR == err) {
! havetodo++;
! goto oops;
! }
!
! if (config_handles[i].loop_count++ > 10) {
! DPRINT(Debug,14, (&Debug,
! "write_conf: %s - loop count %d -- quiting loop\n",
! cfiles[i].shortname,
! config_handles[i].loop_count));
!
! goto quit_waiting;
! } else {
! need_sleep = 5;
!
!
! if (! config_handles[i].loop_message_printed) {
! lib_transient(CATGETS(elm_msg_cat, MeSet,
! MeConfigWaiting,
! "Waiting config file %s to be updated... "),
! cfiles[i].fname);
! config_handles[i].loop_message_printed = 1;
! }
!
! goto wait_this;
! }
! break;
! }
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s fstat current file %s for changes\n",
+ cfiles[i].shortname,
+ cfiles[i].fname));
+
+
+ r3 = stat(cfiles[i].fname,&filename_stat);
+ switch (r3) {
+ char *X;
+ case syscall_success:
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s - stat %s succeed: dev %d ino %d size %ld modified %ld",
+ cfiles[i].shortname,
+ cfiles[i].fname,
+ filename_stat.st_dev,filename_stat.st_ino,
+ (long)filename_stat.st_size,
+ (long)filename_stat.st_mtime));
+ X = ctime(& (filename_stat.st_mtime));
+ if (X) { /* ctime() includes newline */
+ DPRINT(Debug,14,(&Debug," -- %s",X));
+ } else {
+ DPRINT(Debug,14,(&Debug,"\n"));
+ }
+
+ have_filename_stat = 1;
+
+ break;
+ case syscall_error:
+ err = errno;
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s - stat %s: %s\n",
+ cfiles[i].shortname,
+ cfiles[i].fname,
+ strerror(err)));
+
+ if (EINTR == err) {
+ havetodo++;
+ goto oops;
+ }
+
+ if (config_handles[i].loop_message_printed) {
+ lib_transient(CATGETS(elm_msg_cat, MeSet,
+ MeConfigWaitingError,
+ "Waiting config file %s to be updated... Error: %s"),
+ cfiles[i].fname,strerror(err));
+
+ }
+
+ /* File lost? -- do merge with currently open file */
+
+ goto quit_waiting1;
+ }
+
+ if (!have_filename_stat || !config_handles[i].old_fd_have_stat) {
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s - file %s - no stat?\n",
+ cfiles[i].shortname,
+ cfiles[i].fname));
+
+ } else if (filename_stat.st_dev == config_handles[i].old_fd_stat.st_dev &&
+ filename_stat.st_ino == config_handles[i].old_fd_stat.st_ino &&
+ filename_stat.st_size == config_handles[i].old_fd_stat.st_size &&
+ filename_stat.st_mtime == config_handles[i].old_fd_stat.st_mtime) {
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s - file %s not changed (since open)\n",
+ cfiles[i].shortname,
+ cfiles[i].fname));
+
+ if (config_handles[i].loop_message_printed) {
+ lib_transient(CATGETS(elm_msg_cat, MeSet,
+ MeConfigWaitingOK,
+ "Waiting config file %s to be updated... OK"),
+ cfiles[i].fname);
+ config_handles[i].loop_message_printed = 1;
+ }
+
+ } else {
+ /* Re-open new file */
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s - file %s changed after open\n",
+ cfiles[i].shortname,
+ cfiles[i].fname));
+
+ if (config_handles[i].loop_count++ > 10) {
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s - loop count %d -- quiting loop\n",
+ cfiles[i].shortname,
+ config_handles[i].loop_count));
+
+ } else {
+ goto wait_this;
+ }
+ }
+
+ quit_waiting:
+
+ if (config_handles[i].loop_message_printed) {
+ lib_transient(CATGETS(elm_msg_cat, MeSet,
+ MeConfigWaitingError1,
+ "Waiting config file %s to be updated... Error"),
+ cfiles[i].fname);
+ }
+
+ quit_waiting1:
+ if (! config_handles[i].old_f) {
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s fdopen %d (current file %s) for merge\n",
+ cfiles[i].shortname,
+ config_handles[i].old_fd,
+ cfiles[i].fname));
+
+
+ config_handles[i].old_f = fdopen(config_handles[i].old_fd,"r");
+
+ if (! config_handles[i].old_f) {
+ int err = errno;
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s fdopen %d (current file %s): %s\n",
+ cfiles[i].shortname,
+ config_handles[i].old_fd,
+ cfiles[i].fname,
+ strerror(err)));
+
+ if (EINTR == err) {
+ havetodo++;
+ goto oops;
+ }
+
+ if (the_time && ! config_handles[i].bck)
+ config_handles[i].bck = elm_message(FRM("%s.%04d-%02d-%02d.old"),
+ cfiles[i].fname,
+ the_time->tm_year+1900,
+ the_time->tm_mon+1,
+ the_time->tm_mday);
+ if ( config_handles[i].old_fd_have_stat && ! config_handles[i].bck)
+ config_handles[i].bck = elm_message(FRM("%s.%lx_%lx.old"),
+ cfiles[i].fname,
+ (long)config_handles[i].old_fd_stat.st_dev,
+ (long)config_handles[i].old_fd_stat.st_ino);
+ if (config_handles[i].bck) {
+ config_handles[i].require_bck = 1;
+
+ lib_error(CATGETS(elm_msg_cat, MeSet,
+ MeConfigMergeFailed,
+ "Config file %s merge failed: %s (backup: %s)"),
+ cfiles[i].fname,strerror(err),
+ config_handles[i].bck);
+ } else {
+ lib_error(CATGETS(elm_msg_cat, MeSet,
+ MeConfigMergeFailed1,
+ "Config file %s merge failed: %s (no backup)"),
+ cfiles[i].fname,strerror(err));
+
+ }
+
+ config_handles[i].proceed = config_handle_dump;
+ goto no_merge;
+ }
+ }
+
+ if (config_handles[i].old_f) {
+ int r;
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s - merging current file %s\n",
+ cfiles[i].shortname,
+ cfiles[i].fname));
+
+
+ r = cfiles[i].merge_map(cfiles[i].fname,
+ config_handles[i].old_f);
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s - current file %s - merge_map=%d %s\n",
+ cfiles[i].shortname,
+ cfiles[i].fname,
+ r,
+ r ? "succeed" : "failed"));
+
+ if (!r) {
+ if (the_time && ! config_handles[i].bck)
+ config_handles[i].bck = elm_message(FRM("%s.%04d-%02d-%02d.old"),
+ cfiles[i].fname,
+ the_time->tm_year+1900,
+ the_time->tm_mon+1,
+ the_time->tm_mday);
+ if ( config_handles[i].old_fd_have_stat && ! config_handles[i].bck)
+ config_handles[i].bck = elm_message(FRM("%s.%lx_%lx.old"),
+ cfiles[i].fname,
+ (long)config_handles[i].old_fd_stat.st_dev,
+ (long)config_handles[i].old_fd_stat.st_ino);
+
+ if (config_handles[i].bck) {
+ config_handles[i].require_bck = 1;
+
+ lib_error(CATGETS(elm_msg_cat, MeSet,
+ MeConfigMergeFailed2,
+ "Config file %s merge failed (backup: %s)"),
+ cfiles[i].fname,
+ config_handles[i].bck);
+ } else {
+ lib_error(CATGETS(elm_msg_cat, MeSet,
+ MeConfigMergeFailed3,
+ "Config file %s merge failed (no backup)"),
+ cfiles[i].fname);
+
+ }
+
+ config_handles[i].proceed = config_handle_dump;
+ }
+ }
+ }
+
+ /* FALLTHRU */
+
+ case config_handle_dump:
+ no_merge:
+
+ /* Assume error */
+ config_handles[i].proceed = config_handle_skip;
+
+ if (config_handles[i].tmp &&
+ ! config_handles[i].tmp_f) {
+ err = 0;
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s opening temp file %s\n", + cfiles[i].shortname,
+ config_handles[i].tmp));
+
+ config_handles[i].tmp_f = safeopen(config_handles[i].tmp,
+ &err);
+
+ if (! config_handles[i].tmp_f) {
+ lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotWriteable,
+ "File %.50s is not writeable: %s"),
+ config_handles[i].tmp, strerror(err));
+ break;
+ }
+ }
+
+ if (config_handles[i].tmp_f) {
+ int r_dump;
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s writing to temp file\n", + cfiles[i].shortname));
+
+ r_dump = cfiles[i].dump_map(config_handles[i].tmp_f,actor,version_buff,
+ &err);
+
+ if (! r_dump) {
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s writing to temp file failed\n",
+ cfiles[i].shortname));
+
+
+ if (config_handles[i].tmp) {
+
+ lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotWriteable,
+ "File %.50s is not writeable: %s"),
+ config_handles[i].tmp, strerror(err));
+
+ unlink(config_handles[i].tmp); /* Ignore error */ + }
+
+ fclose(config_handles[i].tmp_f); /* ignore error */
+ config_handles[i].tmp_f = NULL;
+
+ } else if (EOF == fclose(config_handles[i].tmp_f)) {
+
+ err = errno;
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s closing temp file failed\n",
+ cfiles[i].shortname));
+
+
+ if (config_handles[i].tmp) {
+
+ lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotWriteable,
+ "File %.50s is not writeable: %s"),
+ config_handles[i].tmp, strerror(err));
+
+ unlink(config_handles[i].tmp); /* Ignore error */ + }
+
+ config_handles[i].tmp_f = NULL;
+ } else {
+ config_handles[i].tmp_f = NULL;
+
+ if (config_handles[i].bck) {
+ enum syscall_status r = link(cfiles[i].fname,
+ config_handles[i].bck);
+
+ switch (r) {
+ case syscall_success:
+ DPRINT(Debug,4, (&Debug,
+ "write_conf: Created backup %s => %s\n",
+ cfiles[i].fname,
+ config_handles[i].bck));
+ break;
+ case syscall_error:
+ err = errno;
+ DPRINT(Debug,4, (&Debug,
+ "write_conf: Backup link %s => %s failed: %s\n",
+ cfiles[i].fname,
+ config_handles[i].bck,
+ strerror(err)));
+
+ if (backup_suffix || config_handles[i].require_bck) {
+ lib_error(CATGETS(elm_msg_cat, MeSet, MeBackupFailed,
+ "Backup %s => %s failed: %s"),
+ cfiles[i].fname,
+ config_handles[i].bck,
+ strerror(err));
+
+ if (config_handles[i].tmp) {
+ unlink(config_handles[i].tmp); /* Ignore error */
+ }
+
+ goto skip_this;
+ }
+
+ /* Ignore backup error if automatic backup */
+
+ break;
+ }
+ }
+ }
+
+ if (config_handles[i].tmp) {
+ enum syscall_status r2;
+
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s renaming temp file %s to %s\n",
+ cfiles[i].shortname,
+ config_handles[i].tmp,
+ cfiles[i].fname));
+
+
+ r2 = rename(config_handles[i].tmp,
+ cfiles[i].fname);
+
+ switch (r2) {
+ case syscall_success:
+ cfiles[i].write_message(cfiles[i].fname);
+
+ config_handles[i].proceed = config_handle_done;
+ break;
+
+ case syscall_error:
+ err = errno;
+ lib_error(CATGETS(elm_msg_cat, MeSet, MeFileNotRenamed,
+ "Failed to rename temporary file to %.50s: %30s"),
+ cfiles[i].fname,
+ strerror(err));
+
+ unlink(config_handles[i].tmp); /* Ignore error */ + break;
+ }
+ }
+ }
+
+ /* FALLTHRU */
+
+ case config_handle_done:
+
+ skip_this:
+
+ close_this = 1;
+ break;
+ }
+
+ if (0) {
+ wait_this:
+
+ DPRINT(Debug,14, (&Debug,
+ "write_conf: %s - waiting this -- loop count %d\n",
+ cfiles[i].shortname,
+ config_handles[i].loop_count));
+
+ close_this = 1;
+ havetodo++;
+ }
+
+ oops:
+ if (close_this) {
+ if (config_handles[i].old_fd != -1 &&
+ config_handles[i].old_fd_locked) {
+
+ config_handles[i].old_fd_locked = 0;
+
+ /* Just ignore error --
+ close() should release this anyway
+ */
+ filelock_fd(config_handles[i].old_fd,FLOCKING_release,&conf_merge_locking,
+ cfiles[i].fname,FLOCKING_non_block,NULL);
+ }
+
+ if (config_handles[i].old_f) {
+ fclose(config_handles[i].old_f);
+ config_handles[i].old_f = NULL;
+ } else if (config_handles[i].old_fd != -1) {
+ close(config_handles[i].old_fd);
+ config_handles[i].old_fd = -1;
+ }
+ }
+ }
+ }
+
+
+ for (i = 0; i < cfiles_num; i++) {
+
+ if (config_handles[i].old_fd != -1 &&
+ config_handles[i].old_fd_locked) {
+ /* Just ignore error --
+ close() should release this anyway
+ */
+ filelock_fd(config_handles[i].old_fd,FLOCKING_release,&conf_merge_locking,
+ cfiles[i].fname,FLOCKING_non_block,NULL);
+ }
+
+ if (config_handles[i].old_f) {
+ fclose(config_handles[i].old_f);
+ config_handles[i].old_f = NULL;
+ } else if (config_handles[i].old_fd != -1) {
+ close(config_handles[i].old_fd);
+ config_handles[i].old_fd = -1;
+ }
+
+ if (config_handles[i].tmp_f) {
+ fclose(config_handles[i].tmp_f);
+ config_handles[i].tmp_f = NULL;
+ }
+
+ if (config_handles[i].tmp) {
+ free(config_handles[i].tmp);
+ config_handles[i].tmp = NULL;
+ }
+
+ if (config_handles[i].bck) {
+ free(config_handles[i].bck);
+ config_handles[i].bck = NULL;
+ }
}
+
+ free (config_handles);
+ config_handles = NULL;
}
struct string * conf_taglist(sep)
--
/ Kari Hurtta
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)