]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #1595 from poettering/proxy-fixes
authorDavid Herrmann <dh.herrmann@googlemail.com>
Sun, 18 Oct 2015 10:15:10 +0000 (12:15 +0200)
committerDavid Herrmann <dh.herrmann@googlemail.com>
Sun, 18 Oct 2015 10:15:10 +0000 (12:15 +0200)
bus proxy fixes, and more

26 files changed:
Makefile.am
TODO
configure.ac
hwdb/60-keyboard.hwdb
hwdb/70-mouse.hwdb
man/systemd.time.xml
shell-completion/bash/systemd-run
src/basic/calendarspec.c
src/basic/calendarspec.h
src/basic/missing.h
src/basic/time-util.c
src/basic/time-util.h
src/core/dbus-execute.c
src/core/dbus-manager.c
src/core/execute.c
src/journal/compress.c
src/journal/test-compress-benchmark.c
src/journal/test-compress.c
src/libsystemd/sd-netlink/netlink-internal.h
src/libsystemd/sd-netlink/netlink-socket.c
src/libsystemd/sd-netlink/sd-netlink.c
src/shared/bus-util.c
src/test/test-calendarspec.c
src/test/test-date.c
units/.gitignore
units/tmp.mount.m4 [moved from units/tmp.mount with 85% similarity]

index 8ba4e0e389d8a82a631cc0ea19c6098480ab2feb..205f2a4d8d24830ff7a4cfd72650a0e6c6014a77 100644 (file)
@@ -616,7 +616,8 @@ EXTRA_DIST += \
        units/initrd-udevadm-cleanup-db.service.in \
        units/initrd-switch-root.service.in \
        units/systemd-nspawn@.service.in \
-       units/systemd-update-done.service.in
+       units/systemd-update-done.service.in \
+       units/tmp.mount.m4
 
 if HAVE_SYSV_COMPAT
 nodist_systemunit_DATA += \
diff --git a/TODO b/TODO
index d399ae9477b1eb3e6843b0e159fdb0ffa12cfa90..ba9ee160ff70badbb2da7fac486b8d6180978b27 100644 (file)
--- a/TODO
+++ b/TODO
@@ -176,14 +176,12 @@ Features:
 * networkd/udev: implement SR_IOV configuration in .link files:
   http://lists.freedesktop.org/archives/systemd-devel/2015-January/027451.html
 
-* When RLIMIT_NPROC is set from a unit file it currently always is set
-  for root, not for the user set in User=, which makes it
-  useless. After fixing this, set RLIMIT_NPROC for
-  systemd-journal-xyz, and all other of our services that run under
-  their own user ids, and use User= (but only in a world where userns
-  is ubiquitous since otherwise we cannot invoke those daemons on the
-  host AND in a container anymore). Also, if LimitNPROC= is used
-  without User= we should warn and refuse operation.
+* Set RLIMIT_NPROC for systemd-journal-xyz, and all other of our
+  services that run under their own user ids, and use User= (but only
+  in a world where userns is ubiquitous since otherwise we cannot
+  invoke those daemons on the host AND in a container anymore). Also,
+  if LimitNPROC= is used without User= we should warn and refuse
+  operation.
 
 * logind: maybe allow configuration of the StopTimeout for session scopes
 
index 903eedff142cfd84fe123720ba39ae53df03250e..c96b9fb1d9fe47b3a6926a282036b35d6b408de2 100644 (file)
@@ -530,25 +530,27 @@ AC_SUBST(CERTIFICATEROOT)
 # ------------------------------------------------------------------------------
 have_xz=no
 AC_ARG_ENABLE(xz, AS_HELP_STRING([--disable-xz], [Disable optional XZ support]))
-if test "x$enable_xz" != "xno"; then
+AS_IF([test "x$enable_xz" != "xno"], [
         PKG_CHECK_MODULES(XZ, [ liblzma ],
-                [AC_DEFINE(HAVE_XZ, 1, [Define if XZ is available]) have_xz=yes], have_xz=no)
-        if test "x$have_xz" = xno -a "x$enable_xz" = xyes; then
-                AC_MSG_ERROR([*** XZ support requested but libraries not found])
-        fi
-fi
+                [AC_DEFINE(HAVE_XZ, 1, [Define if XZ is available])
+                 have_xz=yes],
+                 have_xz=no)
+        AS_IF([test "x$have_xz" = xno -a "x$enable_xz" = xyes],
+              [AC_MSG_ERROR([*** XZ support requested but libraries not found])])
+])
 AM_CONDITIONAL(HAVE_XZ, [test "$have_xz" = "yes"])
 
 # ------------------------------------------------------------------------------
 have_zlib=no
 AC_ARG_ENABLE(zlib, AS_HELP_STRING([--disable-zlib], [Disable optional ZLIB support]))
-if test "x$enable_zlib" != "xno"; then
+AS_IF([test "x$enable_zlib" != "xno"], [
         PKG_CHECK_MODULES(ZLIB, [ zlib ],
-                [AC_DEFINE(HAVE_ZLIB, 1, [Define if ZLIB is available]) have_zlib=yes], have_zlib=no)
-        if test "x$have_zlib" = xno -a "x$enable_zlib" = xyes; then
-                AC_MSG_ERROR([*** ZLIB support requested but libraries not found])
-        fi
-fi
+                [AC_DEFINE(HAVE_ZLIB, 1, [Define if ZLIB is available])
+                 have_zlib=yes],
+                 have_zlib=no)
+        AS_IF([test "x$have_zlib" = xno -a "x$enable_zlib" = xyes],
+              [AC_MSG_ERROR([*** ZLIB support requested but libraries not found])])
+])
 AM_CONDITIONAL(HAVE_ZLIB, [test "$have_zlib" = "yes"])
 
 # ------------------------------------------------------------------------------
@@ -556,20 +558,24 @@ have_bzip2=no
 AC_ARG_ENABLE(bzip2, AS_HELP_STRING([--enable-bzip2], [Disable optional BZIP2 support]))
 AS_IF([test "x$enable_bzip2" != "xno"], [
         AC_CHECK_HEADERS(bzlib.h,
-                [AC_DEFINE(HAVE_BZIP2, 1, [Define in BZIP2 is available])
+                [AC_DEFINE(HAVE_BZIP2, 1, [Define if BZIP2 is available])
                  have_bzip2=yes],
-                [AS_IF([test "x$have_bzip2" = xyes], [AC_MSG_ERROR([*** BZIP2 support requested but headers not found])])
-        ])
+                [AS_IF([test "x$enable_bzip2" = xyes],
+                       [AC_MSG_ERROR([*** BZIP2 support requested but headers not found])])]
+        )
 ])
 AM_CONDITIONAL(HAVE_BZIP2, [test "$have_bzip2" = "yes"])
 
 # ------------------------------------------------------------------------------
 have_lz4=no
-AC_ARG_ENABLE(lz4, AS_HELP_STRING([--enable-lz4], [Enable optional LZ4 support]))
-AS_IF([test "x$enable_lz4" = "xyes"], [
-        AC_CHECK_HEADERS(lz4.h,
-               [AC_DEFINE(HAVE_LZ4, 1, [Define in LZ4 is available]) have_lz4=yes],
-               [AC_MSG_ERROR([*** LZ4 support requested but headers not found])])
+AC_ARG_ENABLE(lz4, AS_HELP_STRING([--disable-lz4], [Disable optional LZ4 support]))
+AS_IF([test "x$enable_lz4" != "xno"], [
+        PKG_CHECK_MODULES(LZ4, [ liblz4 >= 125 ],
+               [AC_DEFINE(HAVE_LZ4, 1, [Define in LZ4 is available])
+                have_lz4=yes],
+                have_lz4=no)
+        AS_IF([test "x$have_lz4" = xno -a "x$enable_lz4" = xyes],
+              [AC_MSG_ERROR([*** LZ4 support requested but libraries not found])])
 ])
 AM_CONDITIONAL(HAVE_LZ4, [test "$have_lz4" = "yes"])
 
index 3e49449ae9c5f914101277692d69e33b72184790..9cb724acc0b671337eb8e71dfc461a625fa2f36c 100644 (file)
@@ -494,6 +494,9 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook445G1NotebookPC:pvr
 # HP ProBook 450 G0
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook450G0:pvr*
  KEYBOARD_KEY_81=f20                                    # Fn+F8; Microphone mute button, should be micmute
+# HP ProBook 6555b
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard:pnHPProBook6555b:*
+ KEYBOARD_KEY_b2=www                                    # Earth
 
 ###########################################################
 # IBM
index 55e68a913839606b12c9f7e82d43e114c2f430fe..2383d586a3bbac6170abd734490c3afa5dcfc1e9 100644 (file)
@@ -311,6 +311,9 @@ mouse:usb:v046dpc05a:name:Logitech USB Optical Mouse:
 mouse:usb:v046dpc065:name:Logitech USB Laser Mouse:
 # Logitech V500 Cordless Notebook Mouse
 mouse:usb:v046dpc510:name:Logitech USB Receiver:
+# Logitech M560 Wireless Mouse
+mouse:usb:v046dp402d:name:Logitech M560:
+mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:402d:
  MOUSE_DPI=1000@125
 
 # Logitech V220 Cordless Optical Mouse
index 64358351d5a764fcd7ef685201f35f0db63b982c..826e9fc5a55ab7ae66aab742dbad03cf4d7700db 100644 (file)
   <refsect1>
     <title>Parsing Timestamps</title>
 
-    <para>When parsing systemd will accept a similar timestamp syntax,
-    but excluding any timezone specification (this limitation might be
-    removed eventually). The weekday specification is optional, but
-    when the weekday is specified it must either be in the abbreviated
+    <para>When parsing systemd will accept a similar syntax, but expects
+    no timezone specification, unless it is given as the literal string
+    "UTC". In this case the time is considered in UTC time, otherwise in
+    the local timezone. The weekday specification is optional, but when
+    the weekday is specified it must either be in the abbreviated
     (<literal>Wed</literal>) or non-abbreviated
     (<literal>Wednesday</literal>) English language form (case does
     not matter), and is not subject to the locale choice of the user.
     00:00.</para>
 
     <para>Examples for valid timestamps and their normalized form
-    (assuming the current time was 2012-11-23 18:15:22):</para>
+    (assuming the current time was 2012-11-23 18:15:22 and the timezone
+    was UTC+8, for example TZ=Asia/Shanghai):</para>
 
     <programlisting>Fri 2012-11-23 11:12:13 → Fri 2012-11-23 11:12:13
     2012-11-23 11:12:13 → Fri 2012-11-23 11:12:13
-       2012-11-23 → Fri 2012-11-23 00:00:00
-         12-11-23 → Fri 2012-11-23 00:00:00
-         11:12:13 → Fri 2012-11-23 11:12:13
-      11:12 → Fri 2012-11-23 11:12:00
-        now → Fri 2012-11-23 18:15:22
-      today → Fri 2012-11-23 00:00:00
-        yesterday → Fri 2012-11-22 00:00:00
-         tomorrow → Fri 2012-11-24 00:00:00
-         +3h30min → Fri 2012-11-23 21:45:22
-        -5s → Fri 2012-11-23 18:15:17
-        11min ago → Fri 2012-11-23 18:04:22
-      @1395716396 → Tue 2014-03-25 03:59:56</programlisting>
+2012-11-23 11:12:13 UTC → Fri 2012-11-23 19:12:13
+             2012-11-23 → Fri 2012-11-23 00:00:00
+               12-11-23 → Fri 2012-11-23 00:00:00
+               11:12:13 → Fri 2012-11-23 11:12:13
+       11:12:13.9900009 → Fri 2012-11-23 11:12:13
+                          format_timestamp_us: Fri 2012-11-23 11:12:13.990000
+                  11:12 → Fri 2012-11-23 11:12:00
+                    now → Fri 2012-11-23 18:15:22
+                  today → Fri 2012-11-23 00:00:00
+              today UTC → Fri 2012-11-23 16:00:00
+              yesterday → Fri 2012-11-22 00:00:00
+               tomorrow → Fri 2012-11-24 00:00:00
+               +3h30min → Fri 2012-11-23 21:45:22
+           +3h30min UTC → -EINVAL
+                    -5s → Fri 2012-11-23 18:15:17
+              11min ago → Fri 2012-11-23 18:04:22
+          11min ago UTC → -EINVAL
+            @1395716396 → Tue 2014-03-25 03:59:56</programlisting>
 
     <para>Note that timestamps printed by systemd will not be parsed
     correctly by systemd, as the timezone specification is not
     second component is not specified, <literal>:00</literal> is
     assumed.</para>
 
-    <para>Timezone names may not be specified.</para>
+    <para>A timezone specification is not expected, unless it is given
+    as the literal string "UTC", similarly to timestamps.</para>
 
     <para>The special expressions
     <literal>minutely</literal>,
     <literal>*-*-01 00:00:00</literal>,
     <literal>Mon *-*-* 00:00:00</literal>,
     <literal>*-01-01 00:00:00</literal>,
-    <literal>*-01,04,07,10-01 00:00:0</literal> and
+    <literal>*-01,04,07,10-01 00:00:00</literal> and
     <literal>*-01,07-01 00:00:00</literal> respectively.
     </para>
 
 
 <programlisting>   Sat,Thu,Mon-Wed,Sat-Sun → Mon-Thu,Sat,Sun *-*-* 00:00:00
      Mon,Sun 12-*-* 2,1:23 → Mon,Sun 2012-*-* 01,02:23:00
-       Wed *-1 → Wed *-*-01 00:00:00
-     Wed-Wed,Wed *-1 → Wed *-*-01 00:00:00
-    Wed, 17:48 → Wed *-*-* 17:48:00
+                   Wed *-1 → Wed *-*-01 00:00:00
+           Wed-Wed,Wed *-1 → Wed *-*-01 00:00:00
+                Wed, 17:48 → Wed *-*-* 17:48:00
 Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03
-         *-*-7 0:0:0 → *-*-07 00:00:00
-         10-15 → *-10-15 00:00:00
+               *-*-7 0:0:0 → *-*-07 00:00:00
+                     10-15 → *-10-15 00:00:00
        monday *-12-* 17:00 → Mon *-12-* 17:00:00
  Mon,Fri *-*-3,1,2 *:30:45 → Mon,Fri *-*-01,02,03 *:30:45
       12,14,13,12:20,10,30 → *-*-* 12,13,14:10,20,30:00
  mon,fri *-1/2-1,3 *:30:45 → Mon,Fri *-01/2-01,03 *:30:45
-      03-05 08:05:40 → *-03-05 08:05:40
-      08:05:40 → *-*-* 08:05:40
-         05:40 → *-*-* 05:40:00
+            03-05 08:05:40 → *-03-05 08:05:40
+                  08:05:40 → *-*-* 08:05:40
+                     05:40 → *-*-* 05:40:00
     Sat,Sun 12-05 08:05:40 → Sat,Sun *-12-05 08:05:40
-    Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40
-    2003-03-05 05:40 → 2003-03-05 05:40:00
-    2003-03-05 → 2003-03-05 00:00:00
-         03-05 → *-03-05 00:00:00
-        hourly → *-*-* *:00:00
-         daily → *-*-* 00:00:00
-       monthly → *-*-01 00:00:00
-        weekly → Mon *-*-* 00:00:00
-        yearly → *-01-01 00:00:00
-      annually → *-01-01 00:00:00
-         *:2/3 → *-*-* *:02/3:00</programlisting>
+          Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40
+          2003-03-05 05:40 → 2003-03-05 05:40:00
+      2003-03-05 05:40 UTC → 2003-03-05 05:40:00 UTC
+                2003-03-05 → 2003-03-05 00:00:00
+                     03-05 → *-03-05 00:00:00
+                    hourly → *-*-* *:00:00
+                     daily → *-*-* 00:00:00
+                 daily UTC → *-*-* 00:00:00 UTC
+                   monthly → *-*-01 00:00:00
+                    weekly → Mon *-*-* 00:00:00
+                    yearly → *-01-01 00:00:00
+                  annually → *-01-01 00:00:00
+                     *:2/3 → *-*-* *:02/3:00</programlisting>
 
       <para>Calendar events are used by timer units, see
       <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>
index 462ee33959963d426cbe88274115951f6337b9ff..518812e040958860a20c112c108365fbc14cbecc 100644 (file)
@@ -84,7 +84,7 @@ _systemd_run() {
                          LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices=
                          PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory=
                          TTYPath= SyslogIdentifier= SyslogLevelPrefix= SyslogLevel=
-                         SyslogFacility='
+                         SyslogFacility= TimerSlackNSec='
 
             COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
             return 0
index 2dcc9c55751acd4d81b8dd8b42247fc2599f87bc..a2296f4709b2573ee09f0930e92b4481757ee256 100644 (file)
@@ -279,6 +279,9 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) {
         fputc(':', f);
         format_chain(f, 2, c->second);
 
+        if (c->utc)
+                fputs(" UTC", f);
+
         r = fflush_and_check(f);
         if (r < 0) {
                 free(buf);
@@ -657,6 +660,10 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
         if (!c)
                 return -ENOMEM;
 
+        c->utc = endswith_no_case(p, "UTC");
+        if (c->utc)
+                p = strndupa(p, strlen(p) - strlen(" UTC"));
+
         if (strcaseeq(p, "minutely")) {
                 r = const_chain(0, &c->second);
                 if (r < 0)
@@ -859,13 +866,13 @@ static int find_matching_component(const CalendarComponent *c, int *val) {
         return r;
 }
 
-static bool tm_out_of_bounds(const struct tm *tm) {
+static bool tm_out_of_bounds(const struct tm *tm, bool utc) {
         struct tm t;
         assert(tm);
 
         t = *tm;
 
-        if (mktime(&t) == (time_t) -1)
+        if (mktime_or_timegm(&t, utc) == (time_t) -1)
                 return true;
 
         /* Did any normalization take place? If so, it was out of bounds before */
@@ -878,7 +885,7 @@ static bool tm_out_of_bounds(const struct tm *tm) {
                 t.tm_sec != tm->tm_sec;
 }
 
-static bool matches_weekday(int weekdays_bits, const struct tm *tm) {
+static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) {
         struct tm t;
         int k;
 
@@ -886,7 +893,7 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm) {
                 return true;
 
         t = *tm;
-        if (mktime(&t) == (time_t) -1)
+        if (mktime_or_timegm(&t, utc) == (time_t) -1)
                 return false;
 
         k = t.tm_wday == 0 ? 6 : t.tm_wday - 1;
@@ -904,7 +911,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
 
         for (;;) {
                 /* Normalize the current date */
-                mktime(&c);
+                mktime_or_timegm(&c, spec->utc);
                 c.tm_isdst = -1;
 
                 c.tm_year += 1900;
@@ -916,7 +923,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
                         c.tm_mday = 1;
                         c.tm_hour = c.tm_min = c.tm_sec = 0;
                 }
-                if (r < 0 || tm_out_of_bounds(&c))
+                if (r < 0 || tm_out_of_bounds(&c, spec->utc))
                         return r;
 
                 c.tm_mon += 1;
@@ -927,7 +934,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
                         c.tm_mday = 1;
                         c.tm_hour = c.tm_min = c.tm_sec = 0;
                 }
-                if (r < 0 || tm_out_of_bounds(&c)) {
+                if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
                         c.tm_year ++;
                         c.tm_mon = 0;
                         c.tm_mday = 1;
@@ -938,14 +945,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
                 r = find_matching_component(spec->day, &c.tm_mday);
                 if (r > 0)
                         c.tm_hour = c.tm_min = c.tm_sec = 0;
-                if (r < 0 || tm_out_of_bounds(&c)) {
+                if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
                         c.tm_mon ++;
                         c.tm_mday = 1;
                         c.tm_hour = c.tm_min = c.tm_sec = 0;
                         continue;
                 }
 
-                if (!matches_weekday(spec->weekdays_bits, &c)) {
+                if (!matches_weekday(spec->weekdays_bits, &c, spec->utc)) {
                         c.tm_mday++;
                         c.tm_hour = c.tm_min = c.tm_sec = 0;
                         continue;
@@ -954,7 +961,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
                 r = find_matching_component(spec->hour, &c.tm_hour);
                 if (r > 0)
                         c.tm_min = c.tm_sec = 0;
-                if (r < 0 || tm_out_of_bounds(&c)) {
+                if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
                         c.tm_mday ++;
                         c.tm_hour = c.tm_min = c.tm_sec = 0;
                         continue;
@@ -963,14 +970,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
                 r = find_matching_component(spec->minute, &c.tm_min);
                 if (r > 0)
                         c.tm_sec = 0;
-                if (r < 0 || tm_out_of_bounds(&c)) {
+                if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
                         c.tm_hour ++;
                         c.tm_min = c.tm_sec = 0;
                         continue;
                 }
 
                 r = find_matching_component(spec->second, &c.tm_sec);
-                if (r < 0 || tm_out_of_bounds(&c)) {
+                if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
                         c.tm_min ++;
                         c.tm_sec = 0;
                         continue;
@@ -991,13 +998,13 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next)
         assert(next);
 
         t = (time_t) (usec / USEC_PER_SEC) + 1;
-        assert_se(localtime_r(&t, &tm));
+        assert_se(localtime_or_gmtime_r(&t, &tm, spec->utc));
 
         r = find_next(spec, &tm);
         if (r < 0)
                 return r;
 
-        t = mktime(&tm);
+        t = mktime_or_timegm(&tm, spec->utc);
         if (t == (time_t) -1)
                 return -EINVAL;
 
index 7baf318249bb5c64bc509404bf68d99bad33a017..56dc02f391bc12cd8cc00d73a66d80ed915d6089 100644 (file)
@@ -36,6 +36,7 @@ typedef struct CalendarComponent {
 
 typedef struct CalendarSpec {
         int weekdays_bits;
+        bool utc;
 
         CalendarComponent *year;
         CalendarComponent *month;
index 8d11b80d95d7ea1dd17964a7bb93663887febbe9..70d6c8308eea4a4e28554289cb67abe2f29432a4 100644 (file)
 #define SOL_NETLINK 270
 #endif
 
+#ifndef NETLINK_LIST_MEMBERSHIPS
+#define NETLINK_LIST_MEMBERSHIPS 9
+#endif
+
 #if !HAVE_DECL_PIVOT_ROOT
 static inline int pivot_root(const char *new_root, const char *put_old) {
         return syscall(SYS_pivot_root, new_root, put_old);
index 531931f6e1434e6474c3708e3577b51ccdc213de..d4e0914b27a9030ed8184fc19a71e26df6317d49 100644 (file)
@@ -19,7 +19,6 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <time.h>
 #include <string.h>
 #include <sys/timex.h>
 #include <sys/timerfd.h>
@@ -205,11 +204,8 @@ static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc)
                 return NULL;
 
         sec = (time_t) (t / USEC_PER_SEC);
+        localtime_or_gmtime_r(&sec, &tm, utc);
 
-        if (utc)
-                gmtime_r(&sec, &tm);
-        else
-                localtime_r(&sec, &tm);
         if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
                 return NULL;
 
@@ -235,10 +231,7 @@ static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool ut
                 return NULL;
 
         sec = (time_t) (t / USEC_PER_SEC);
-        if (utc)
-                gmtime_r(&sec, &tm);
-        else
-                localtime_r(&sec, &tm);
+        localtime_or_gmtime_r(&sec, &tm, utc);
 
         if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
                 return NULL;
@@ -484,9 +477,10 @@ int parse_timestamp(const char *t, usec_t *usec) {
         };
 
         const char *k;
+        bool utc;
         struct tm tm, copy;
         time_t x;
-        usec_t plus = 0, minus = 0, ret;
+        usec_t x_usec, plus = 0, minus = 0, ret;
         int r, weekday = -1;
         unsigned i;
 
@@ -511,28 +505,15 @@ int parse_timestamp(const char *t, usec_t *usec) {
         assert(t);
         assert(usec);
 
-        x = time(NULL);
-        assert_se(localtime_r(&x, &tm));
-        tm.tm_isdst = -1;
-
-        if (streq(t, "now"))
-                goto finish;
-
-        else if (streq(t, "today")) {
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
+        if (t[0] == '@')
+                return parse_sec(t + 1, usec);
 
-        } else if (streq(t, "yesterday")) {
-                tm.tm_mday --;
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
+        ret = now(CLOCK_REALTIME);
 
-        } else if (streq(t, "tomorrow")) {
-                tm.tm_mday ++;
-                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+        if (streq(t, "now"))
                 goto finish;
 
-        else if (t[0] == '+') {
+        else if (t[0] == '+') {
                 r = parse_sec(t+1, &plus);
                 if (r < 0)
                         return r;
@@ -546,35 +527,51 @@ int parse_timestamp(const char *t, usec_t *usec) {
 
                 goto finish;
 
-        } else if (t[0] == '@')
-                return parse_sec(t + 1, usec);
-
-        else if (endswith(t, " ago")) {
-                _cleanup_free_ char *z;
-
-                z = strndup(t, strlen(t) - 4);
-                if (!z)
-                        return -ENOMEM;
+        } else if (endswith(t, " ago")) {
+                t = strndupa(t, strlen(t) - strlen(" ago"));
 
-                r = parse_sec(z, &minus);
+                r = parse_sec(t, &minus);
                 if (r < 0)
                         return r;
 
                 goto finish;
-        } else if (endswith(t, " left")) {
-                _cleanup_free_ char *z;
 
-                z = strndup(t, strlen(t) - 4);
-                if (!z)
-                        return -ENOMEM;
+        } else if (endswith(t, " left")) {
+                t = strndupa(t, strlen(t) - strlen(" left"));
 
-                r = parse_sec(z, &plus);
+                r = parse_sec(t, &plus);
                 if (r < 0)
                         return r;
 
                 goto finish;
         }
 
+        utc = endswith_no_case(t, " UTC");
+        if (utc)
+                t = strndupa(t, strlen(t) - strlen(" UTC"));
+
+        x = ret / USEC_PER_SEC;
+        x_usec = 0;
+
+        assert_se(localtime_or_gmtime_r(&x, &tm, utc));
+        tm.tm_isdst = -1;
+
+        if (streq(t, "today")) {
+                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+                goto from_tm;
+
+        } else if (streq(t, "yesterday")) {
+                tm.tm_mday --;
+                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+                goto from_tm;
+
+        } else if (streq(t, "tomorrow")) {
+                tm.tm_mday ++;
+                tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+                goto from_tm;
+        }
+
+
         for (i = 0; i < ELEMENTSOF(day_nr); i++) {
                 size_t skip;
 
@@ -592,66 +589,106 @@ int parse_timestamp(const char *t, usec_t *usec) {
 
         copy = tm;
         k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
-        if (k && *k == 0)
-                goto finish;
+        if (k) {
+                if (*k == '.')
+                        goto parse_usec;
+                else if (*k == 0)
+                        goto from_tm;
+        }
 
         tm = copy;
         k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
-        if (k && *k == 0)
-                goto finish;
+        if (k) {
+                if (*k == '.')
+                        goto parse_usec;
+                else if (*k == 0)
+                        goto from_tm;
+        }
 
         tm = copy;
         k = strptime(t, "%y-%m-%d %H:%M", &tm);
         if (k && *k == 0) {
                 tm.tm_sec = 0;
-                goto finish;
+                goto from_tm;
         }
 
         tm = copy;
         k = strptime(t, "%Y-%m-%d %H:%M", &tm);
         if (k && *k == 0) {
                 tm.tm_sec = 0;
-                goto finish;
+                goto from_tm;
         }
 
         tm = copy;
         k = strptime(t, "%y-%m-%d", &tm);
         if (k && *k == 0) {
                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
+                goto from_tm;
         }
 
         tm = copy;
         k = strptime(t, "%Y-%m-%d", &tm);
         if (k && *k == 0) {
                 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
-                goto finish;
+                goto from_tm;
         }
 
         tm = copy;
         k = strptime(t, "%H:%M:%S", &tm);
-        if (k && *k == 0)
-                goto finish;
+        if (k) {
+                if (*k == '.')
+                        goto parse_usec;
+                else if (*k == 0)
+                        goto from_tm;
+        }
 
         tm = copy;
         k = strptime(t, "%H:%M", &tm);
         if (k && *k == 0) {
                 tm.tm_sec = 0;
-                goto finish;
+                goto from_tm;
         }
 
         return -EINVAL;
 
-finish:
-        x = mktime(&tm);
+parse_usec:
+        {
+                char *end;
+                unsigned long long val;
+                size_t l;
+
+                k++;
+                if (*k < '0' || *k > '9')
+                        return -EINVAL;
+
+                /* base 10 instead of base 0, .09 is not base 8 */
+                errno = 0;
+                val = strtoull(k, &end, 10);
+                if (*end || errno)
+                        return -EINVAL;
+
+                l = end-k;
+
+                /* val has l digits, make them 6 */
+                for (; l < 6; l++)
+                        val *= 10;
+                for (; l > 6; l--)
+                        val /= 10;
+
+                x_usec = val;
+        }
+
+from_tm:
+        x = mktime_or_timegm(&tm, utc);
         if (x == (time_t) -1)
                 return -EINVAL;
 
         if (weekday >= 0 && tm.tm_wday != weekday)
                 return -EINVAL;
 
-        ret = (usec_t) x * USEC_PER_SEC;
+        ret = (usec_t) x * USEC_PER_SEC + x_usec;
 
+finish:
         ret += plus;
         if (ret > minus)
                 ret -= minus;
@@ -1072,3 +1109,11 @@ int get_timezone(char **tz) {
         *tz = z;
         return 0;
 }
+
+time_t mktime_or_timegm(struct tm *tm, bool utc) {
+        return utc ? timegm(tm) : mktime(tm);
+}
+
+struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
+        return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
+}
index 1af01541fc23dc85426b86430c52b7ee41e4b4c8..417376ea9657a5f80104fe11b47133219e507165 100644 (file)
@@ -21,8 +21,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <stdio.h>
 #include <inttypes.h>
+#include <stdio.h>
+#include <time.h>
 
 typedef uint64_t usec_t;
 typedef uint64_t nsec_t;
@@ -117,3 +118,6 @@ clockid_t clock_boottime_or_monotonic(void);
                           "xstrftime: " #buf "[] must be big enough")
 
 int get_timezone(char **timezone);
+
+time_t mktime_or_timegm(struct tm *tm, bool utc);
+struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc);
index 8b1f830476dd98ba58044ffa3f74435f27da42c7..436229330e54d795e55092fdc0b1ea64efca2b9b 100644 (file)
@@ -1171,6 +1171,21 @@ int bus_exec_context_set_transient_property(
 
                 return 1;
 
+        } else if (streq(name, "TimerSlackNSec")) {
+
+                nsec_t n;
+
+                r = sd_bus_message_read(message, "t", &n);
+                if (r < 0)
+                        return r;
+
+                if (mode != UNIT_CHECK) {
+                        c->timer_slack_nsec = n;
+                        unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT "\n", n);
+                }
+
+                return 1;
+
         } else if (rlimit_from_string(name) >= 0) {
                 uint64_t rl;
                 rlim_t x;
index 9ddc65d10b42b16ac454d2db5b5acb70338e200f..00bb39110611005aa952939ef42fb9af525ae5e1 100644 (file)
@@ -20,6 +20,7 @@
 ***/
 
 #include <errno.h>
+#include <sys/prctl.h>
 #include <unistd.h>
 
 #include "log.h"
@@ -346,6 +347,21 @@ static int property_set_runtime_watchdog(
         return watchdog_set_timeout(t);
 }
 
+static int property_get_timer_slack_nsec(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        assert(bus);
+        assert(reply);
+
+        return sd_bus_message_append(reply, "t", (uint64_t) prctl(PR_GET_TIMERSLACK));
+}
+
 static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *path = NULL;
         Manager *m = userdata;
@@ -1993,6 +2009,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultLimitRTPRIO", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
 
         SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
index d6217840c07cc8dbdd397777ea9cd7c6f922e966..51efb7c215a13f6b835f3dbb551692b4a1c8e4b7 100644 (file)
@@ -2314,7 +2314,7 @@ static void strv_fprintf(FILE *f, char **l) {
 }
 
 void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
-        char **e;
+        char **e, **d;
         unsigned i;
 
         assert(c);
@@ -2350,6 +2350,11 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
         STRV_FOREACH(e, c->environment_files)
                 fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
 
+        fprintf(f, "%sRuntimeDirectoryMode: %04o\n", prefix, c->runtime_directory_mode);
+
+        STRV_FOREACH(d, c->runtime_directory)
+                fprintf(f, "%sRuntimeDirectory: %s\n", prefix, *d);
+
         if (c->nice_set)
                 fprintf(f,
                         "%sNice: %i\n",
index c66043e50364d65638d15e0fbcfa1cdbc076383c..8c92e26edd73aef09ad95f90766f3e68cf51b174 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/mman.h>
 
 #ifdef HAVE_XZ
 #  include <lzma.h>
@@ -29,6 +30,7 @@
 
 #ifdef HAVE_LZ4
 #  include <lz4.h>
+#  include <lz4frame.h>
 #endif
 
 #include "compress.h"
 #include "sparse-endian.h"
 #include "journal-def.h"
 
+#ifdef HAVE_LZ4
+DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_compressionContext_t, LZ4F_freeCompressionContext);
+DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_decompressionContext_t, LZ4F_freeDecompressionContext);
+#endif
+
 #define ALIGN_8(l) ALIGN_TO(l, sizeof(size_t))
 
 static const char* const object_compressed_table[_OBJECT_COMPRESSED_MAX] = {
@@ -416,81 +423,96 @@ int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
 #endif
 }
 
-#define LZ4_BUFSIZE (512*1024)
+#define LZ4_BUFSIZE (512*1024u)
 
 int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
 
 #ifdef HAVE_LZ4
+        LZ4F_errorCode_t c;
+        _cleanup_(LZ4F_freeCompressionContextp) LZ4F_compressionContext_t ctx = NULL;
+        _cleanup_free_ char *buf = NULL;
+        char *src = NULL;
+        size_t size, n, total_in = 0, total_out = 0, offset = 0, frame_size;
+        struct stat st;
+        int r;
+        static const LZ4F_compressOptions_t options = {
+                .stableSrc = 1,
+        };
+        static const LZ4F_preferences_t preferences = {
+                .frameInfo.blockSizeID = 5,
+        };
 
-        _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *out = NULL;
-        char *buf;
-        LZ4_stream_t lz4_data = {};
-        le32_t header;
-        size_t total_in = 0, total_out = sizeof(header);
-        ssize_t n;
+        c = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
+        if (LZ4F_isError(c))
+                return -ENOMEM;
 
-        assert(fdf >= 0);
-        assert(fdt >= 0);
+        if (fstat(fdf, &st) < 0)
+                return log_debug_errno(errno, "fstat() failed: %m");
 
-        buf1 = malloc(LZ4_BUFSIZE);
-        buf2 = malloc(LZ4_BUFSIZE);
-        out = malloc(LZ4_COMPRESSBOUND(LZ4_BUFSIZE));
-        if (!buf1 || !buf2 || !out)
-                return log_oom();
+        frame_size = LZ4F_compressBound(LZ4_BUFSIZE, &preferences);
+        size =  frame_size + 64*1024; /* add some space for header and trailer */
+        buf = malloc(size);
+        if (!buf)
+                return -ENOMEM;
 
-        buf = buf1;
-        for (;;) {
-                size_t m;
-                int r;
+        n = offset = LZ4F_compressBegin(ctx, buf, size, &preferences);
+        if (LZ4F_isError(n))
+                return -EINVAL;
 
-                m = LZ4_BUFSIZE;
-                if (max_bytes != (uint64_t) -1 && (uint64_t) m > (max_bytes - total_in))
-                        m = (size_t) (max_bytes - total_in);
+        src = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fdf, 0);
+        if (src == MAP_FAILED)
+                return -errno;
 
-                n = read(fdf, buf, m);
-                if (n < 0)
-                        return -errno;
-                if (n == 0)
-                        break;
+        log_debug("Buffer size is %zu bytes, header size %zu bytes.", size, n);
 
-                total_in += n;
+        while (total_in < (size_t) st.st_size) {
+                ssize_t k;
 
-                r = LZ4_compress_continue(&lz4_data, buf, out, n);
-                if (r == 0) {
-                        log_error("LZ4 compression failed.");
-                        return -EBADMSG;
+                k = MIN(LZ4_BUFSIZE, st.st_size - total_in);
+                n = LZ4F_compressUpdate(ctx, buf + offset, size - offset,
+                                        src + total_in, k, &options);
+                if (LZ4F_isError(n)) {
+                        r = -ENOTRECOVERABLE;
+                        goto cleanup;
                 }
 
-                header = htole32(r);
-                errno = 0;
+                total_in += k;
+                offset += n;
+                total_out += n;
 
-                n = write(fdt, &header, sizeof(header));
-                if (n < 0)
-                        return -errno;
-                if (n != sizeof(header))
-                        return errno ? -errno : -EIO;
-
-                n = loop_write(fdt, out, r, false);
-                if (n < 0)
-                        return n;
+                if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) {
+                        log_debug("Compressed stream longer than %zd bytes", max_bytes);
+                        return -EFBIG;
+                }
 
-                total_out += sizeof(header) + r;
+                if (size - offset < frame_size + 4) {
+                        k = loop_write(fdt, buf, offset, false);
+                        if (k < 0) {
+                                r = k;
+                                goto cleanup;
+                        }
+                        offset = 0;
+                }
+        }
 
-                buf = buf == buf1 ? buf2 : buf1;
+        n = LZ4F_compressEnd(ctx, buf + offset, size - offset, &options);
+        if (LZ4F_isError(n)) {
+                r = -ENOTRECOVERABLE;
+                goto cleanup;
         }
 
-        header = htole32(0);
-        n = write(fdt, &header, sizeof(header));
-        if (n < 0)
-                return -errno;
-        if (n != sizeof(header))
-                return errno ? -errno : -EIO;
+        offset += n;
+        total_out += n;
+        r = loop_write(fdt, buf, offset, false);
+        if (r < 0)
+                goto cleanup;
 
         log_debug("LZ4 compression finished (%zu -> %zu bytes, %.1f%%)",
                   total_in, total_out,
                   (double) total_out / total_in * 100);
-
-        return 0;
+ cleanup:
+        munmap(src, st.st_size);
+        return r;
 #else
         return -EPROTONOSUPPORT;
 #endif
@@ -510,7 +532,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
 
         ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
         if (ret != LZMA_OK) {
-                log_error("Failed to initialize XZ decoder: code %u", ret);
+                log_debug("Failed to initialize XZ decoder: code %u", ret);
                 return -ENOMEM;
         }
 
@@ -536,7 +558,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
 
                 ret = lzma_code(&s, action);
                 if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
-                        log_error("Decompression failed: code %u", ret);
+                        log_debug("Decompression failed: code %u", ret);
                         return -EBADMSG;
                 }
 
@@ -566,14 +588,14 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
                 }
         }
 #else
-        log_error("Cannot decompress file. Compiled without XZ support.");
+        log_debug("Cannot decompress file. Compiled without XZ support.");
         return -EPROTONOSUPPORT;
 #endif
 }
 
-int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
-
 #ifdef HAVE_LZ4
+static int decompress_stream_lz4_v1(int fdf, int fdt, uint64_t max_bytes) {
+
         _cleanup_free_ char *buf = NULL, *out = NULL;
         size_t buf_size = 0;
         LZ4_streamDecode_t lz4_data = {};
@@ -585,7 +607,7 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
 
         out = malloc(4*LZ4_BUFSIZE);
         if (!out)
-                return log_oom();
+                return -ENOMEM;
 
         for (;;) {
                 ssize_t m;
@@ -606,22 +628,24 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
                  * not accept buffers compressed by newer binaries then.
                  */
                 if (m > LZ4_COMPRESSBOUND(LZ4_BUFSIZE * 4)) {
-                        log_error("Compressed stream block too big: %zd bytes", m);
-                        return -EBADMSG;
+                        log_debug("Compressed stream block too big: %zd bytes", m);
+                        return -ENOBUFS;
                 }
 
                 total_in += sizeof(header) + m;
 
                 if (!GREEDY_REALLOC(buf, buf_size, m))
-                        return log_oom();
+                        return -ENOMEM;
 
                 r = loop_read_exact(fdf, buf, m, false);
                 if (r < 0)
                         return r;
 
                 r = LZ4_decompress_safe_continue(&lz4_data, buf, out, m, 4*LZ4_BUFSIZE);
-                if (r <= 0)
-                        log_error("LZ4 decompression failed.");
+                if (r <= 0) {
+                        log_debug("LZ4 decompression failed (legacy format).");
+                        return -EBADMSG;
+                }
 
                 total_out += r;
 
@@ -635,13 +659,80 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
                         return r;
         }
 
-        log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)",
+        log_debug("LZ4 decompression finished (legacy format, %zu -> %zu bytes, %.1f%%)",
                   total_in, total_out,
                   (double) total_out / total_in * 100);
 
         return 0;
+}
+
+static int decompress_stream_lz4_v2(int in, int out, uint64_t max_bytes) {
+        size_t c;
+        _cleanup_(LZ4F_freeDecompressionContextp) LZ4F_decompressionContext_t ctx = NULL;
+        _cleanup_free_ char *buf = NULL;
+        char *src;
+        struct stat st;
+        int r = 0;
+        size_t total_in = 0, total_out = 0;
+
+        c = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
+        if (LZ4F_isError(c))
+                return -ENOMEM;
+
+        if (fstat(in, &st) < 0)
+                return log_debug_errno(errno, "fstat() failed: %m");
+
+        buf = malloc(LZ4_BUFSIZE);
+        if (!buf)
+                return -ENOMEM;
+
+        src = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, in, 0);
+        if (src == MAP_FAILED)
+                return -errno;
+
+        while (total_in < (size_t) st.st_size) {
+                size_t produced = LZ4_BUFSIZE;
+                size_t used = st.st_size - total_in;
+
+                c = LZ4F_decompress(ctx, buf, &produced, src + total_in, &used, NULL);
+                if (LZ4F_isError(c)) {
+                        r = -EBADMSG;
+                        goto cleanup;
+                }
+
+                total_in += used;
+                total_out += produced;
+
+                if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) {
+                        log_debug("Decompressed stream longer than %zd bytes", max_bytes);
+                        r = -EFBIG;
+                        goto cleanup;
+                }
+
+                r = loop_write(out, buf, produced, false);
+                if (r < 0)
+                        goto cleanup;
+        }
+
+        log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)",
+                  total_in, total_out,
+                  (double) total_out / total_in * 100);
+ cleanup:
+        munmap(src, st.st_size);
+        return r;
+}
+#endif
+
+int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
+#ifdef HAVE_LZ4
+        int r;
+
+        r = decompress_stream_lz4_v2(fdf, fdt, max_bytes);
+        if (r == -EBADMSG)
+                r = decompress_stream_lz4_v1(fdf, fdt, max_bytes);
+        return r;
 #else
-        log_error("Cannot decompress file. Compiled without LZ4 support.");
+        log_debug("Cannot decompress file. Compiled without LZ4 support.");
         return -EPROTONOSUPPORT;
 #endif
 }
index c8e5b76c6ce29e234d8a8d2b2e6c7602e6ed9864..0be6820a14a13cb4665a5c89953932e321ae24dc 100644 (file)
@@ -20,6 +20,7 @@
 #include "compress.h"
 #include "util.h"
 #include "macro.h"
+#include "random-util.h"
 
 typedef int (compress_t)(const void *src, uint64_t src_size, void *dst, size_t *dst_size);
 typedef int (decompress_t)(const void *src, uint64_t src_size,
@@ -27,20 +28,31 @@ typedef int (decompress_t)(const void *src, uint64_t src_size,
 
 #define MAX_SIZE (1024*1024LU)
 
-static char* make_buf(size_t count) {
+static char* make_buf(size_t count, const char *type) {
         char *buf;
         size_t i;
 
         buf = malloc(count);
         assert_se(buf);
 
-        for (i = 0; i < count; i++)
-                buf[i] = 'a' + i % ('z' - 'a' + 1);
+        if (streq(type, "zeros"))
+                memzero(buf, count);
+        else if (streq(type, "simple"))
+                for (i = 0; i < count; i++)
+                        buf[i] = 'a' + i % ('z' - 'a' + 1);
+        else if (streq(type, "random")) {
+                random_bytes(buf, count/10);
+                random_bytes(buf + 2*count/10, count/10);
+                random_bytes(buf + 4*count/10, count/20);
+                random_bytes(buf + 6*count/10, count/20);
+                random_bytes(buf + 8*count/10, count/20);
+        } else
+                assert_not_reached("here");
 
         return buf;
 }
 
-static void test_compress_decompress(const char* label,
+static void test_compress_decompress(const char* label, const char* type,
                                      compress_t compress, decompress_t decompress) {
         usec_t n, n2 = 0;
         float dt;
@@ -50,7 +62,7 @@ static void test_compress_decompress(const char* label,
         size_t buf2_allocated = 0;
         size_t skipped = 0, compressed = 0, total = 0;
 
-        text = make_buf(MAX_SIZE);
+        text = make_buf(MAX_SIZE, type);
         buf = calloc(MAX_SIZE + 1, 1);
         assert_se(text && buf);
 
@@ -62,7 +74,8 @@ static void test_compress_decompress(const char* label,
 
                 r = compress(text, i, buf, &j);
                 /* assume compression must be successful except for small inputs */
-                assert_se(r == 0 || (i < 2048 && r == -ENOBUFS));
+                assert_se(r == 0 || (i < 2048 && r == -ENOBUFS) || streq(type, "random"));
+
                 /* check for overwrites */
                 assert_se(buf[i] == 0);
                 if (r != 0) {
@@ -91,23 +104,26 @@ static void test_compress_decompress(const char* label,
 
         dt = (n2-n) / 1e6;
 
-        log_info("%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), "
+        log_info("%s/%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), "
                  "mean compresion %.2f%%, skipped %zu bytes",
-                 label, total, dt,
+                 label, type, total, dt,
                  total / 1024. / 1024 / dt,
                  100 - compressed * 100. / total,
                  skipped);
 }
 
 int main(int argc, char *argv[]) {
+        const char *i;
 
         log_set_max_level(LOG_DEBUG);
 
+        NULSTR_FOREACH(i, "zeros\0simple\0random\0") {
 #ifdef HAVE_XZ
-        test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz);
+                test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz);
 #endif
 #ifdef HAVE_LZ4
-        test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4);
+                test_compress_decompress("LZ4", i, compress_blob_lz4, decompress_blob_lz4);
 #endif
+        }
         return 0;
 }
index f17c00e60dc36a08bad306ec14761725b6a0390f..e51b12407f2c9b14f73666180b7dcdb17c5e2fff 100644 (file)
@@ -144,8 +144,8 @@ static void test_compress_stream(int compression,
                                  const char *srcfile) {
 
         _cleanup_close_ int src = -1, dst = -1, dst2 = -1;
-        char pattern[] = "/tmp/systemd-test.xz.XXXXXX",
-             pattern2[] = "/tmp/systemd-test.xz.XXXXXX";
+        char pattern[] = "/tmp/systemd-test.compressed.XXXXXX",
+             pattern2[] = "/tmp/systemd-test.compressed.XXXXXX";
         int r;
         _cleanup_free_ char *cmd = NULL, *cmd2;
         struct stat st = {};
@@ -185,7 +185,7 @@ static void test_compress_stream(int compression,
 
         assert_se(lseek(dst, 1, SEEK_SET) == 1);
         r = decompress(dst, dst2, st.st_size);
-        assert_se(r == -EBADMSG);
+        assert_se(r == -EBADMSG || r == 0);
 
         assert_se(lseek(dst, 0, SEEK_SET) == 0);
         assert_se(lseek(dst2, 0, SEEK_SET) == 0);
@@ -236,8 +236,7 @@ int main(int argc, char *argv[]) {
                                    compress_blob_lz4, decompress_startswith_lz4,
                                    data, sizeof(data), true);
 
-        /* Produced stream is not compatible with lz4 binary, skip lz4cat check. */
-        test_compress_stream(OBJECT_COMPRESSED_LZ4, NULL,
+        test_compress_stream(OBJECT_COMPRESSED_LZ4, "lz4cat",
                              compress_stream_lz4, decompress_stream_lz4, argv[0]);
 #else
         log_info("/* LZ4 test skipped */");
index 4026e2c341b1333fe3e648e0e30ee6186a8372e0..b9cb80668dd8036a6a13dcba77201cb6aee45476 100644 (file)
@@ -64,6 +64,9 @@ struct sd_netlink {
                 struct sockaddr_nl nl;
         } sockaddr;
 
+        Hashmap *broadcast_group_refs;
+        bool broadcast_group_dont_leave:1; /* until we can rely on 4.2 */
+
         sd_netlink_message **rqueue;
         unsigned rqueue_size;
         size_t rqueue_allocated;
@@ -124,7 +127,8 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret);
 
 int socket_open(int family);
 int socket_bind(sd_netlink *nl);
-int socket_join_broadcast_group(sd_netlink *nl, unsigned group);
+int socket_broadcast_group_ref(sd_netlink *nl, unsigned group);
+int socket_broadcast_group_unref(sd_netlink *nl, unsigned group);
 int socket_write_message(sd_netlink *nl, sd_netlink_message *m);
 int socket_read_message(sd_netlink *nl);
 
index 84ff7c38c925e7b5dca7fb0571cd53d32512dcba..e1b14c3ed2bb4a41b5cd28cd80efa2101d23abd5 100644 (file)
@@ -44,6 +44,65 @@ int socket_open(int family) {
         return fd;
 }
 
+static int broadcast_groups_get(sd_netlink *nl) {
+        _cleanup_free_ uint32_t *groups = NULL;
+        socklen_t len = 0, old_len;
+        unsigned i, j;
+        int r;
+
+        assert(nl);
+        assert(nl->fd > 0);
+
+        r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len);
+        if (r < 0) {
+                if (errno == ENOPROTOOPT) {
+                        nl->broadcast_group_dont_leave = true;
+                        return 0;
+                } else
+                        return -errno;
+        }
+
+        if (len == 0)
+                return 0;
+
+        groups = new0(uint32_t, len);
+        if (!groups)
+                return -ENOMEM;
+
+        old_len = len;
+
+        r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, groups, &len);
+        if (r < 0)
+                return -errno;
+
+        if (old_len != len)
+                return -EIO;
+
+        r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
+        if (r < 0)
+                return r;
+
+        for (i = 0; i < len; i++) {
+                for (j = 0; j < sizeof(uint32_t) * 8; j ++) {
+                        uint32_t offset;
+                        unsigned group;
+
+                        offset = 1U << j;
+
+                        if (!(groups[i] & offset))
+                                continue;
+
+                        group = i * sizeof(uint32_t) * 8 + j + 1;
+
+                        r = hashmap_put(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(1));
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        return 0;
+}
+
 int socket_bind(sd_netlink *nl) {
         socklen_t addrlen;
         int r, one = 1;
@@ -63,11 +122,32 @@ int socket_bind(sd_netlink *nl) {
         if (r < 0)
                 return -errno;
 
+        r = broadcast_groups_get(nl);
+        if (r < 0)
+                return r;
+
         return 0;
 }
 
+static unsigned broadcast_group_get_ref(sd_netlink *nl, unsigned group) {
+        assert(nl);
+
+        return PTR_TO_UINT(hashmap_get(nl->broadcast_group_refs, UINT_TO_PTR(group)));
+}
 
-int socket_join_broadcast_group(sd_netlink *nl, unsigned group) {
+static int broadcast_group_set_ref(sd_netlink *nl, unsigned group, unsigned n_ref) {
+        int r;
+
+        assert(nl);
+
+        r = hashmap_replace(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(n_ref));
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int broadcast_group_join(sd_netlink *nl, unsigned group) {
         int r;
 
         assert(nl);
@@ -81,6 +161,79 @@ int socket_join_broadcast_group(sd_netlink *nl, unsigned group) {
         return 0;
 }
 
+int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) {
+        unsigned n_ref;
+        int r;
+
+        assert(nl);
+
+        n_ref = broadcast_group_get_ref(nl, group);
+
+        n_ref ++;
+
+        r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
+        if (r < 0)
+                return r;
+
+        r = broadcast_group_set_ref(nl, group, n_ref);
+        if (r < 0)
+                return r;
+
+        if (n_ref > 1)
+                /* not yet in the group */
+                return 0;
+
+        r = broadcast_group_join(nl, group);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+static int broadcast_group_leave(sd_netlink *nl, unsigned group) {
+        int r;
+
+        assert(nl);
+        assert(nl->fd >= 0);
+        assert(group > 0);
+
+        if (nl->broadcast_group_dont_leave)
+                return 0;
+
+        r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &group, sizeof(group));
+        if (r < 0)
+                return -errno;
+
+        return 0;
+}
+
+int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) {
+        unsigned n_ref;
+        int r;
+
+        assert(nl);
+
+        n_ref = broadcast_group_get_ref(nl, group);
+
+        assert(n_ref > 0);
+
+        n_ref --;
+
+        r = broadcast_group_set_ref(nl, group, n_ref);
+        if (r < 0)
+                return r;
+
+        if (n_ref > 0)
+                /* still refs left */
+                return 0;
+
+        r = broadcast_group_leave(nl, group);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 /* returns the number of bytes sent, or a negative error code */
 int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
         union {
index f4a0a358a9cb69a14eb677fb380e77e8ccd78aa2..5af28600bafacb9b74339fdb097e22b92a405cf1 100644 (file)
@@ -183,10 +183,11 @@ sd_netlink *sd_netlink_unref(sd_netlink *rtnl) {
                 sd_event_unref(rtnl->event);
 
                 while ((f = rtnl->match_callbacks)) {
-                        LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
-                        free(f);
+                        sd_netlink_remove_match(rtnl, f->type, f->callback, f->userdata);
                 }
 
+                hashmap_free(rtnl->broadcast_group_refs);
+
                 safe_close(rtnl->fd);
                 free(rtnl);
         }
@@ -857,29 +858,29 @@ int sd_netlink_add_match(sd_netlink *rtnl,
         switch (type) {
                 case RTM_NEWLINK:
                 case RTM_DELLINK:
-                        r = socket_join_broadcast_group(rtnl, RTNLGRP_LINK);
+                        r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK);
                         if (r < 0)
                                 return r;
 
                         break;
                 case RTM_NEWADDR:
                 case RTM_DELADDR:
-                        r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR);
+                        r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_IFADDR);
                         if (r < 0)
                                 return r;
 
-                        r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR);
+                        r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_IFADDR);
                         if (r < 0)
                                 return r;
 
                         break;
                 case RTM_NEWROUTE:
                 case RTM_DELROUTE:
-                        r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV4_ROUTE);
+                        r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_ROUTE);
                         if (r < 0)
                                 return r;
 
-                        r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV6_ROUTE);
+                        r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_ROUTE);
                         if (r < 0)
                                 return r;
                         break;
@@ -899,23 +900,50 @@ int sd_netlink_remove_match(sd_netlink *rtnl,
                          sd_netlink_message_handler_t callback,
                          void *userdata) {
         struct match_callback *c;
+        int r;
 
         assert_return(rtnl, -EINVAL);
         assert_return(callback, -EINVAL);
         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
 
-        /* we should unsubscribe from the broadcast groups at this point, but it is not so
-           trivial for a few reasons: the refcounting is a bit of a mess and not obvious
-           how it will look like after we add genetlink support, and it is also not possible
-           to query what broadcast groups were subscribed to when we inherit the socket to get
-           the initial refcount. The latter could indeed be done for the first 32 broadcast
-           groups (which incidentally is all we currently support in .socket units anyway),
-           but we better not rely on only ever using 32 groups. */
         LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
                 if (c->callback == callback && c->type == type && c->userdata == userdata) {
                         LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
                         free(c);
 
+                        switch (type) {
+                                case RTM_NEWLINK:
+                                case RTM_DELLINK:
+                                        r = socket_broadcast_group_unref(rtnl, RTNLGRP_LINK);
+                                        if (r < 0)
+                                                return r;
+
+                                        break;
+                                case RTM_NEWADDR:
+                                case RTM_DELADDR:
+                                        r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_IFADDR);
+                                        if (r < 0)
+                                                return r;
+
+                                        r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_IFADDR);
+                                        if (r < 0)
+                                                return r;
+
+                                        break;
+                                case RTM_NEWROUTE:
+                                case RTM_DELROUTE:
+                                        r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_ROUTE);
+                                        if (r < 0)
+                                                return r;
+
+                                        r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_ROUTE);
+                                        if (r < 0)
+                                                return r;
+                                        break;
+                                default:
+                                        return -EOPNOTSUPP;
+                        }
+
                         return 1;
                 }
 
index 3a45ac4064262e1b776af04523c7dfa12081fa57..a5d6edbba94a38c502297c8a3f25a79f90f0a4d1 100644 (file)
@@ -1655,7 +1655,16 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
                 }
 
                 r = sd_bus_message_append(m, "v", "t", u);
+        } else if (streq(field, "TimerSlackNSec")) {
+                nsec_t n;
 
+                r = parse_nsec(eq, &n);
+                if (r < 0) {
+                        log_error("Failed to parse %s value %s", field, eq);
+                        return -EINVAL;
+                }
+
+                r = sd_bus_message_append(m, "v", "t", n);
         } else {
                 log_error("Unknown assignment %s.", assignment);
                 return -EINVAL;
index 87e1da1258a703444a0988e48d3c875d91e7ac0f..ad36ef19b0e80d67d1e8af19b881a9977b8d0692 100644 (file)
@@ -50,6 +50,44 @@ static void test_one(const char *input, const char *output) {
         assert_se(streq(q, p));
 }
 
+static void test_next(const char *input, const char *new_tz, usec_t after, usec_t expect) {
+        CalendarSpec *c;
+        usec_t u;
+        char *old_tz;
+        char buf[FORMAT_TIMESTAMP_MAX];
+        int r;
+
+        old_tz = getenv("TZ");
+        if (old_tz)
+                old_tz = strdupa(old_tz);
+
+        if (new_tz)
+                assert_se(setenv("TZ", new_tz, 1) >= 0);
+        else
+                assert_se(unsetenv("TZ") >= 0);
+        tzset();
+
+        assert_se(calendar_spec_from_string(input, &c) >= 0);
+
+        printf("\"%s\"\n", input);
+
+        u = after;
+        r = calendar_spec_next_usec(c, after, &u);
+        printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp(buf, sizeof(buf), u));
+        if (expect != (usec_t)-1)
+                assert_se(r >= 0 && u == expect);
+        else
+                assert(r == -ENOENT);
+
+        calendar_spec_free(c);
+
+        if (old_tz)
+                assert_se(setenv("TZ", old_tz, 1) >= 0);
+        else
+                assert_se(unsetenv("TZ") >= 0);
+        tzset();
+}
+
 int main(int argc, char* argv[]) {
         CalendarSpec *c;
 
@@ -82,6 +120,15 @@ int main(int argc, char* argv[]) {
         test_one("semi-annually", "*-01,07-01 00:00:00");
         test_one("annually", "*-01-01 00:00:00");
         test_one("*:2/3", "*-*-* *:02/3:00");
+        test_one("2015-10-25 01:00:00 uTc", "2015-10-25 01:00:00 UTC");
+
+        test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000);
+        test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000);
+        test_next("2016-03-27 03:17:00", "EET", 12345, -1);
+        test_next("2016-03-27 03:17:00 UTC", NULL, 12345, 1459048620000000);
+        test_next("2016-03-27 03:17:00 UTC", "", 12345, 1459048620000000);
+        test_next("2016-03-27 03:17:00 UTC", "CET", 12345, 1459048620000000);
+        test_next("2016-03-27 03:17:00 UTC", "EET", 12345, 1459048620000000);
 
         assert_se(calendar_spec_from_string("test", &c) < 0);
         assert_se(calendar_spec_from_string("", &c) < 0);
index 00b569080ccaa04809882b70af82e7e93197c6de..bd1b2781df47cc08cd5bdac822c925aeab43c209 100644 (file)
 
 #include "util.h"
 
-static void test_one(const char *p) {
+static void test_should_pass(const char *p) {
         usec_t t, q;
         char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX];
 
         assert_se(parse_timestamp(p, &t) >= 0);
-        format_timestamp(buf, sizeof(buf), t);
+        format_timestamp_us(buf, sizeof(buf), t);
         log_info("%s", buf);
 
         /* Chop off timezone */
@@ -42,23 +42,50 @@ static void test_one(const char *p) {
         assert_se(parse_timestamp(buf, &q) >= 0);
 }
 
+static void test_should_fail(const char *p) {
+        usec_t t;
+
+        assert_se(parse_timestamp(p, &t) < 0);
+}
+
+static void test_one(const char *p) {
+        _cleanup_free_ char *with_utc;
+
+        log_info("Test: %s", p);
+        with_utc = strjoin(p, " UTC", NULL);
+        test_should_pass(p);
+        test_should_pass(with_utc);
+}
+
+static void test_one_noutc(const char *p) {
+        _cleanup_free_ char *with_utc;
+
+        log_info("Test: %s", p);
+        with_utc = strjoin(p, " UTC", NULL);
+        test_should_pass(p);
+        test_should_fail(with_utc);
+}
+
 int main(int argc, char *argv[]) {
         test_one("17:41");
         test_one("18:42:44");
+        test_one("18:42:44.0");
+        test_one("18:42:44.999999999999");
         test_one("12-10-02 12:13:14");
         test_one("12-10-2 12:13:14");
         test_one("12-10-03 12:13");
         test_one("2012-12-30 18:42");
         test_one("2012-10-02");
         test_one("Tue 2012-10-02");
-        test_one("now");
+        test_one_noutc("now");
         test_one("yesterday");
         test_one("today");
         test_one("tomorrow");
-        test_one("+2d");
-        test_one("+2y 4d");
-        test_one("5months ago");
-        test_one("@1395716396");
+        test_one_noutc("+2d");
+        test_one_noutc("+2y 4d");
+        test_one_noutc("5months ago");
+        test_one_noutc("@1395716396");
+        test_one_noutc("today UTC");
 
         return 0;
 }
index 883f51f73cba6f19bb9b78fcf4d67b20fe671d73..c89740df05ca12240b05007c998a858f5d6325c6 100644 (file)
@@ -78,4 +78,5 @@
 /systemd-update-utmp.service
 /systemd-user-sessions.service
 /systemd-vconsole-setup.service
+/tmp.mount
 /user@.service
similarity index 85%
rename from units/tmp.mount
rename to units/tmp.mount.m4
index 00a0d28722449038f17e6aa66cb6c70def0cf9f8..d537746dbf94f17e7a5d1b446eb8a46b99c7c241 100644 (file)
@@ -18,4 +18,6 @@ Before=local-fs.target umount.target
 What=tmpfs
 Where=/tmp
 Type=tmpfs
-Options=mode=1777,strictatime
+m4_ifdef(`HAVE_SMACK',
+`Options=mode=1777,strictatime,smackfsroot=*',
+`Options=mode=1777,strictatime')