diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index e5bba9ed977fe61740e727644c620f492f39c080..f920d1dc3968e3821d39ef089c27ca6f7da0bbf3 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -26790,11 +26790,12 @@ virDomainGraphicsAuthDefFormatAttr(virBufferPtr buf, def->passwd); if (def->expires) { - char strbuf[100]; - struct tm tmbuf, *tm; - tm = gmtime_r(&def->validTo, &tmbuf); - strftime(strbuf, sizeof(strbuf), "%Y-%m-%dT%H:%M:%S", tm); - virBufferAsprintf(buf, " passwdValidTo='%s'", strbuf); + g_autoptr(GDateTime) then = NULL; + g_autofree char *thenstr = NULL; + + then = g_date_time_new_from_unix_utc(def->validTo); + thenstr = g_date_time_format(then, "%Y-%m-%dT%H:%M:%S"); + virBufferAsprintf(buf, " passwdValidTo='%s'", thenstr); } if (def->connected) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index f9be4ad583409c890377668ae691bd073b26e03d..d63eca0bd66c56bddb466f88fdf33206d2fdffcf 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -943,16 +943,14 @@ libxlDomainAutoCoreDump(libxlDriverPrivatePtr driver, virDomainObjPtr vm) { g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver); - time_t curtime = time(NULL); - char timestr[100]; - struct tm time_info; + g_autoptr(GDateTime) now = g_date_time_new_now_local(); + g_autofree char *nowstr = NULL; char *dumpfile = NULL; - localtime_r(&curtime, &time_info); - strftime(timestr, sizeof(timestr), "%Y-%m-%d-%H:%M:%S", &time_info); + nowstr = g_date_time_format(now, "%Y-%m-%d-%H:%M:%S"); dumpfile = g_strdup_printf("%s/%s-%s", cfg->autoDumpDir, vm->def->name, - timestr); + nowstr); /* Unlock virDomainObj while dumping core */ virObjectUnlock(vm); diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index eaed106a6d8f2333530f08dcf9d9e82cb36ca3d5..c66b60fd21b9f811d2962037e101763f75f876a8 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -6070,8 +6070,9 @@ qemuBuildClockArgStr(virDomainClockDefPtr def) break; case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE: { - time_t now = time(NULL); - struct tm nowbits; + g_autoptr(GDateTime) now = g_date_time_new_now_utc(); + g_autoptr(GDateTime) then = NULL; + g_autofree char *thenstr = NULL; if (def->data.variable.basis == VIR_DOMAIN_CLOCK_BASIS_LOCALTIME) { long localOffset; @@ -6094,8 +6095,8 @@ qemuBuildClockArgStr(virDomainClockDefPtr def) def->data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC; } - now += def->data.variable.adjustment; - gmtime_r(&now, &nowbits); + then = g_date_time_add_seconds(now, def->data.variable.adjustment); + thenstr = g_date_time_format(then, "%Y-%m-%dT%H:%M:%S"); /* when an RTC_CHANGE event is received from qemu, we need to * have the adjustment used at domain start time available to @@ -6105,13 +6106,7 @@ qemuBuildClockArgStr(virDomainClockDefPtr def) */ def->data.variable.adjustment0 = def->data.variable.adjustment; - virBufferAsprintf(&buf, "base=%d-%02d-%02dT%02d:%02d:%02d", - nowbits.tm_year + 1900, - nowbits.tm_mon + 1, - nowbits.tm_mday, - nowbits.tm_hour, - nowbits.tm_min, - nowbits.tm_sec); + virBufferAsprintf(&buf, "base=%s", thenstr); } break; default: diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 17104c4921c73279f6ed212ade1013e93730866d..7e379fe83a74401694a41f4909cd5319a86a57f7 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4090,9 +4090,8 @@ getAutoDumpPath(virQEMUDriverPtr driver, virDomainObjPtr vm) { g_autofree char *domname = virDomainDefGetShortName(vm->def); - char timestr[100]; - struct tm time_info; - time_t curtime = time(NULL); + g_autoptr(GDateTime) now = g_date_time_new_now_local(); + g_autofree char *nowstr = NULL; g_autoptr(virQEMUDriverConfig) cfg = NULL; if (!domname) @@ -4100,10 +4099,9 @@ getAutoDumpPath(virQEMUDriverPtr driver, cfg = virQEMUDriverGetConfig(driver); - localtime_r(&curtime, &time_info); - strftime(timestr, sizeof(timestr), "%Y-%m-%d-%H:%M:%S", &time_info); + nowstr = g_date_time_format(now, "%Y-%m-%d-%H:%M:%S"); - return g_strdup_printf("%s/%s-%s", cfg->autoDumpPath, domname, timestr); + return g_strdup_printf("%s/%s-%s", cfg->autoDumpPath, domname, nowstr); } static void diff --git a/src/util/virtime.c b/src/util/virtime.c index 13f899cb91e5be84ae56ea80b53b110b215f1cb0..bc8f06cd48738642a4eaaf0e094765cf192b226d 100644 --- a/src/util/virtime.c +++ b/src/util/virtime.c @@ -302,8 +302,8 @@ char *virTimeStringThen(unsigned long long when) /** * virTimeLocalOffsetFromUTC: * - * This function is threadsafe, but is *not* async signal safe (due to - * gmtime_r() and mktime()). + * This function is threadsafe, but is *not* async signal safe + * due to use of GLib APIs. * * @offset: pointer to time_t that will be set to the difference * between localtime and UTC in seconds (east of UTC is a @@ -314,34 +314,11 @@ char *virTimeStringThen(unsigned long long when) int virTimeLocalOffsetFromUTC(long *offset) { - struct tm gmtimeinfo; - time_t current, utc; + g_autoptr(GDateTime) now = g_date_time_new_now_local(); + GTimeSpan diff = g_date_time_get_utc_offset(now); - /* time() gives seconds since Epoch in current timezone */ - if ((current = time(NULL)) == (time_t)-1) { - virReportSystemError(errno, "%s", - _("failed to get current system time")); - return -1; - } - - /* treat current as if it were in UTC */ - if (!gmtime_r(¤t, &gmtimeinfo)) { - virReportSystemError(errno, "%s", - _("gmtime_r failed")); - return -1; - } - - /* tell mktime to figure out itself whether or not DST is in effect */ - gmtimeinfo.tm_isdst = -1; - - /* mktime() also obeys current timezone rules */ - if ((utc = mktime(&gmtimeinfo)) == (time_t)-1) { - virReportSystemError(errno, "%s", - _("mktime failed")); - return -1; - } - - *offset = current - utc; + /* GTimeSpan measures microseconds, we want seconds */ + *offset = diff / 1000000; return 0; } diff --git a/tests/qemuxml2argvmock.c b/tests/qemuxml2argvmock.c index 8143de16185777cd52dcb800e318394e7900053a..e5841bc8e338378226c6150a0a066a457fe7ecbb 100644 --- a/tests/qemuxml2argvmock.c +++ b/tests/qemuxml2argvmock.c @@ -47,12 +47,14 @@ long virGetSystemPageSize(void) return 4096; } -time_t time(time_t *t) +GDateTime *g_date_time_new_now_utc(void) { - const time_t ret = 1234567890; - if (t) - *t = ret; - return ret; + return g_date_time_new_from_unix_utc(1234567890); +} + +GDateTime *g_date_time_new_now_local(void) +{ + return g_date_time_new_from_unix_local(1234567890); } bool diff --git a/tests/virtimetest.c b/tests/virtimetest.c index f8a81ff09066b7ea3544ba20b4ca29a9f3192afb..f9ac55192d1db18af0e0f92d8baeaeacfbd58cc7 100644 --- a/tests/virtimetest.c +++ b/tests/virtimetest.c @@ -101,20 +101,12 @@ testTimeLocalOffset(const void *args) static bool isNearYearEnd(void) { - time_t current = time(NULL); - struct tm timeinfo; + g_autoptr(GDateTime) now = g_date_time_new_now_local(); - if (current == (time_t)-1) { - VIR_DEBUG("time() failed"); - return false; - } - if (!localtime_r(¤t, &timeinfo)) { - VIR_DEBUG("localtime_r() failed"); - return false; - } - - return (timeinfo.tm_mon == 0 && timeinfo.tm_mday == 1) || - (timeinfo.tm_mon == 11 && timeinfo.tm_mday == 31); + return ((g_date_time_get_month(now) == 1 && + g_date_time_get_day_of_month(now) == 1) || + (g_date_time_get_month(now) == 12 && + g_date_time_get_day_of_month(now) == 31)); } @@ -186,14 +178,21 @@ mymain(void) /* test DST processing with timezones that always * have DST in effect; what's more, cover a zone with * with an unusual DST different than a usual one hour + * + * These tests originally used '0' as the first day, + * but changed to '1' due to GLib GTimeZone parsing bug: + * https://gitlab.gnome.org/GNOME/glib/issues/1999 + * + * Once we depend on a new enough GLib, we can put then + * back to 0 again. */ - TEST_LOCALOFFSET("VIR-00:30VID,0/00:00:00,365/23:59:59", + TEST_LOCALOFFSET("VIR-00:30VID,1/00:00:00,364/23:59:59", ((1 * 60) + 30) * 60); - TEST_LOCALOFFSET("VIR-02:30VID,0/00:00:00,365/23:59:59", + TEST_LOCALOFFSET("VIR-02:30VID,1/00:00:00,364/23:59:59", ((3 * 60) + 30) * 60); - TEST_LOCALOFFSET("VIR-02:30VID-04:30,0/00:00:00,365/23:59:59", + TEST_LOCALOFFSET("VIR-02:30VID-04:30,1/00:00:00,364/23:59:59", ((4 * 60) + 30) * 60); - TEST_LOCALOFFSET("VIR-12:00VID-13:00,0/00:00:00,365/23:59:59", + TEST_LOCALOFFSET("VIR-12:00VID-13:00,1/00:00:00,364/23:59:59", ((13 * 60) + 0) * 60); if (!isNearYearEnd()) { @@ -209,11 +208,11 @@ mymain(void) * tests, except on Dec 31 and Jan 1. */ - TEST_LOCALOFFSET("VIR02:45VID00:45,0/00:00:00,365/23:59:59", + TEST_LOCALOFFSET("VIR02:45VID00:45,1/00:00:00,364/23:59:59", -45 * 60); - TEST_LOCALOFFSET("VIR05:00VID04:00,0/00:00:00,365/23:59:59", + TEST_LOCALOFFSET("VIR05:00VID04:00,1/00:00:00,364/23:59:59", ((-4 * 60) + 0) * 60); - TEST_LOCALOFFSET("VIR11:00VID10:00,0/00:00:00,365/23:59:59", + TEST_LOCALOFFSET("VIR11:00VID10:00,1/00:00:00,364/23:59:59", ((-10 * 60) + 0) * 60); } diff --git a/tools/virsh-checkpoint.c b/tools/virsh-checkpoint.c index f9749b5f6d0e8da8ec776b10f5a47287ce1eef1e..e82a67f075d90942d5b91f39f7fb2059c765e4d9 100644 --- a/tools/virsh-checkpoint.c +++ b/tools/virsh-checkpoint.c @@ -719,9 +719,8 @@ cmdCheckpointList(vshControl *ctl, char *doc = NULL; virDomainCheckpointPtr checkpoint = NULL; long long creation_longlong; - time_t creation_time_t; - char timestr[100]; - struct tm time_info; + g_autoptr(GDateTime) then = NULL; + g_autofree gchar *thenstr = NULL; bool tree = vshCommandOptBool(cmd, "tree"); bool name = vshCommandOptBool(cmd, "name"); bool from = vshCommandOptBool(cmd, "from"); @@ -835,21 +834,16 @@ cmdCheckpointList(vshControl *ctl, if (virXPathLongLong("string(/domaincheckpoint/creationTime)", ctxt, &creation_longlong) < 0) continue; - creation_time_t = creation_longlong; - if (creation_time_t != creation_longlong) { - vshError(ctl, "%s", _("time_t overflow")); - continue; - } - localtime_r(&creation_time_t, &time_info); - strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S %z", - &time_info); + + then = g_date_time_new_from_unix_local(creation_longlong); + thenstr = g_date_time_format(then, "%Y-%m-%d %H:%M:%S %z"); if (parent) { - if (vshTableRowAppend(table, chk_name, timestr, + if (vshTableRowAppend(table, chk_name, thenstr, NULLSTR_EMPTY(parent_chk), NULL) < 0) goto cleanup; } else { - if (vshTableRowAppend(table, chk_name, timestr, NULL) < 0) + if (vshTableRowAppend(table, chk_name, thenstr, NULL) < 0) goto cleanup; } } diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index efcdc613c6f826d1fd7a82269386ac666c3d2832..933e2aa75fd4378286ab5f4a51b79104f1588c81 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -1534,17 +1534,13 @@ cmdDomTime(vshControl *ctl, const vshCmd *cmd) goto cleanup; if (pretty) { - char timestr[100]; - time_t cur_time = seconds; - struct tm time_info; + g_autoptr(GDateTime) then = NULL; + g_autofree char *thenstr = NULL; - if (!gmtime_r(&cur_time, &time_info)) { - vshError(ctl, _("Unable to format time")); - goto cleanup; - } - strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", &time_info); + then = g_date_time_new_from_unix_utc(seconds); + thenstr = g_date_time_format(then, "%Y-%m-%d %H:%M:%S"); - vshPrint(ctl, _("Time: %s"), timestr); + vshPrint(ctl, _("Time: %s"), thenstr); } else { vshPrint(ctl, _("Time: %lld"), seconds); } diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index c48575279cdd4e32b309a283badbdef673025c9a..e64e08e5da73d61067e53c02ee88ae1246a393ec 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -5492,9 +5492,8 @@ static const vshCmdOptDef opts_screenshot[] = { static char * virshGenFileName(vshControl *ctl, virDomainPtr dom, const char *mime) { - char timestr[100]; - time_t cur_time; - struct tm time_info; + g_autoptr(GDateTime) now = g_date_time_new_now_local(); + g_autofree char *nowstr = NULL; const char *ext = NULL; char *ret = NULL; @@ -5509,12 +5508,10 @@ virshGenFileName(vshControl *ctl, virDomainPtr dom, const char *mime) ext = ".png"; /* add mime type here */ - time(&cur_time); - localtime_r(&cur_time, &time_info); - strftime(timestr, sizeof(timestr), "%Y-%m-%d-%H:%M:%S", &time_info); + nowstr = g_date_time_format(now, "%Y-%m-%d-%H:%M:%S"); - ret = g_strdup_printf("%s-%s%s", virDomainGetName(dom), timestr, - NULLSTR_EMPTY(ext)); + ret = g_strdup_printf("%s-%s%s", virDomainGetName(dom), + nowstr, NULLSTR_EMPTY(ext)); return ret; } diff --git a/tools/virsh-network.c b/tools/virsh-network.c index a02c85fcb1181fce86328db3e366265be1a4b9fd..ed90736345e77fea1ec0f74f8a5cb85574e8cf9c 100644 --- a/tools/virsh-network.c +++ b/tools/virsh-network.c @@ -1433,11 +1433,10 @@ cmdNetworkDHCPLeases(vshControl *ctl, const vshCmd *cmd) const char *typestr = NULL; g_autofree char *cidr_format = NULL; virNetworkDHCPLeasePtr lease = leases[i]; - time_t expirytime_tmp = lease->expirytime; - struct tm ts; - char expirytime[32]; - localtime_r(&expirytime_tmp, &ts); - strftime(expirytime, sizeof(expirytime), "%Y-%m-%d %H:%M:%S", &ts); + g_autoptr(GDateTime) then = g_date_time_new_from_unix_local(lease->expirytime); + g_autofree char *thenstr = NULL; + + thenstr = g_date_time_format(then, "%Y-%m-%d %H:%M:%S"); if (lease->type == VIR_IP_ADDR_TYPE_IPV4) typestr = "ipv4"; @@ -1447,7 +1446,7 @@ cmdNetworkDHCPLeases(vshControl *ctl, const vshCmd *cmd) cidr_format = g_strdup_printf("%s/%d", lease->ipaddr, lease->prefix); if (vshTableRowAppend(table, - expirytime, + thenstr, NULLSTR_MINUS(lease->mac), NULLSTR_MINUS(typestr), NULLSTR_MINUS(cidr_format), diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c index a42397b42e999b336f5629c1eca5e9897532e97b..d5e68e4b1888d9f9a87ca27af52c73b03f4e40ee 100644 --- a/tools/virsh-snapshot.c +++ b/tools/virsh-snapshot.c @@ -1492,9 +1492,8 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) virDomainSnapshotPtr snapshot = NULL; char *state = NULL; long long creation_longlong; - time_t creation_time_t; - char timestr[100]; - struct tm time_info; + g_autoptr(GDateTime) then = NULL; + g_autofree gchar *thenstr = NULL; bool tree = vshCommandOptBool(cmd, "tree"); bool name = vshCommandOptBool(cmd, "name"); bool from = vshCommandOptBool(cmd, "from"); @@ -1624,22 +1623,16 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) if (virXPathLongLong("string(/domainsnapshot/creationTime)", ctxt, &creation_longlong) < 0) continue; - creation_time_t = creation_longlong; - if (creation_time_t != creation_longlong) { - vshError(ctl, "%s", _("time_t overflow")); - continue; - } - localtime_r(&creation_time_t, &time_info); - strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S %z", - &time_info); + then = g_date_time_new_from_unix_local(creation_longlong); + thenstr = g_date_time_format(then, "%Y-%m-%d %H:%M:%S %z"); if (parent) { - if (vshTableRowAppend(table, snap_name, timestr, state, + if (vshTableRowAppend(table, snap_name, thenstr, state, NULLSTR_EMPTY(parent_snap), NULL) < 0) goto cleanup; } else { - if (vshTableRowAppend(table, snap_name, timestr, state, + if (vshTableRowAppend(table, snap_name, thenstr, state, NULL) < 0) goto cleanup; } diff --git a/tools/virt-admin.c b/tools/virt-admin.c index 30106d1971f7800a224f1fa4de34e133391e5011..c71ebb10122bc63adca656f7d5faa55458be365c 100644 --- a/tools/virt-admin.c +++ b/tools/virt-admin.c @@ -69,40 +69,6 @@ vshAdmClientTransportToString(int transport) return str ? _(str) : _("unknown"); } -/* - * vshAdmGetTimeStr: - * - * Produces string representation (local time) of @then - * (seconds since epoch UTC) using format 'YYYY-MM-DD HH:MM:SS+ZZZZ'. - * - * Returns 0 if conversion finished successfully, -1 in case of an error. - * Caller is responsible for freeing the string returned. - */ -static int -vshAdmGetTimeStr(vshControl *ctl, time_t then, char **result) -{ - char *tmp = NULL; - struct tm timeinfo; - - if (!localtime_r(&then, &timeinfo)) - goto error; - - if (VIR_ALLOC_N(tmp, VIRT_ADMIN_TIME_BUFLEN) < 0) - goto error; - - if (strftime(tmp, VIRT_ADMIN_TIME_BUFLEN, "%Y-%m-%d %H:%M:%S%z", - &timeinfo) == 0) { - VIR_FREE(tmp); - goto error; - } - - *result = tmp; - return 0; - - error: - vshError(ctl, "%s", _("Timestamp string conversion failed")); - return -1; -} /* * vshAdmCatchDisconnect: @@ -646,19 +612,19 @@ cmdSrvClientsList(vshControl *ctl, const vshCmd *cmd) goto cleanup; for (i = 0; i < nclts; i++) { - g_autofree char *timestr = NULL; + g_autoptr(GDateTime) then = NULL; + g_autofree gchar *thenstr = NULL; g_autofree char *idStr = NULL; virAdmClientPtr client = clts[i]; id = virAdmClientGetID(client); + then = g_date_time_new_from_unix_local(virAdmClientGetTimestamp(client)); transport = virAdmClientGetTransport(client); - if (vshAdmGetTimeStr(ctl, virAdmClientGetTimestamp(client), - ×tr) < 0) - goto cleanup; + thenstr = g_date_time_format(then, "%Y-%m-%d %H:%M:%S%z"); idStr = g_strdup_printf("%llu", id); if (vshTableRowAppend(table, idStr, vshAdmClientTransportToString(transport), - timestr, NULL) < 0) + thenstr, NULL) < 0) goto cleanup; } @@ -714,7 +680,8 @@ cmdClientInfo(vshControl *ctl, const vshCmd *cmd) size_t i; unsigned long long id; const char *srvname = NULL; - char *timestr = NULL; + g_autoptr(GDateTime) then = NULL; + g_autofree gchar *thenstr = NULL; virAdmServerPtr srv = NULL; virAdmClientPtr clnt = NULL; virTypedParameterPtr params = NULL; @@ -739,12 +706,13 @@ cmdClientInfo(vshControl *ctl, const vshCmd *cmd) goto cleanup; } - if (vshAdmGetTimeStr(ctl, virAdmClientGetTimestamp(clnt), ×tr) < 0) - goto cleanup; + + then = g_date_time_new_from_unix_local(virAdmClientGetTimestamp(clnt)); + thenstr = g_date_time_format(then, "%Y-%m-%d %H:%M:%S%z"); /* this info is provided by the client object itself */ vshPrint(ctl, "%-15s: %llu\n", "id", virAdmClientGetID(clnt)); - vshPrint(ctl, "%-15s: %s\n", "connection_time", timestr); + vshPrint(ctl, "%-15s: %s\n", "connection_time", thenstr); vshPrint(ctl, "%-15s: %s\n", "transport", vshAdmClientTransportToString(virAdmClientGetTransport(clnt))); @@ -760,7 +728,6 @@ cmdClientInfo(vshControl *ctl, const vshCmd *cmd) virTypedParamsFree(params, nparams); virAdmServerFree(srv); virAdmClientFree(clnt); - VIR_FREE(timestr); return ret; } diff --git a/tools/vsh.c b/tools/vsh.c index 5c8908f2409114ae036ce8d47d2ed82f3ce5f361..949c8dad7b331f1b98873180b5a5c496a0f08773 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -2182,8 +2182,8 @@ vshOutputLogFile(vshControl *ctl, int log_level, const char *msg_format, char *str = NULL; size_t len; const char *lvl = ""; - time_t stTime; - struct tm stTm; + g_autoptr(GDateTime) now = g_date_time_new_now_local(); + g_autofree gchar *nowstr = NULL; if (ctl->log_fd == -1) return; @@ -2193,15 +2193,9 @@ vshOutputLogFile(vshControl *ctl, int log_level, const char *msg_format, * * [YYYY.MM.DD HH:MM:SS SIGNATURE PID] LOG_LEVEL message */ - time(&stTime); - localtime_r(&stTime, &stTm); - virBufferAsprintf(&buf, "[%d.%02d.%02d %02d:%02d:%02d %s %d] ", - (1900 + stTm.tm_year), - (1 + stTm.tm_mon), - stTm.tm_mday, - stTm.tm_hour, - stTm.tm_min, - stTm.tm_sec, + nowstr = g_date_time_format(now, "%Y.%m.%d %H:%M:%S"); + virBufferAsprintf(&buf, "[%s %s %d] ", + nowstr, ctl->progname, (int) getpid()); switch (log_level) {