<div dir="auto"><div><br><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sun, Sep 1, 2019, 1:55 PM Radostin Stoyanov &lt;<a href="mailto:rstoyanov1@gmail.com">rstoyanov1@gmail.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
  
    
  
  <div text="#000000" bgcolor="#FFFFFF">
    When run the command:<br>
    <br>
        sudo ltrace -w 1 -f criu/criu --binlog --log-file /tmp/sdf.bin
    check<br>
    <br>
    we can see that the Segmentation fault occurs in criu/sk-unix.c:133<br>
    <br>
        pr_debug(&quot;\t%s: ino %d peer_ino %d family %4d type %4d state %2d
    name %s\n&quot;,<br>
            act, sk-&gt;sd.ino, sk-&gt;peer_ino, sk-&gt;sd.family,
    sk-&gt;type, sk-&gt;state, sk-&gt;name);<br>
    <br>
    This is because flog_encode_msg() does not handle strings properly.<br></div></blockquote></div></div><div dir="auto"><br></div><div dir="auto">sk-&gt;name can be NULL here and this case isn&#39;t handled properly.</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div text="#000000" bgcolor="#FFFFFF">
    <br>
    <br>
    <div class="m_5752743663243829988moz-cite-prefix">On 01/09/2019 07:59, Anastasia Markina
      wrote:<br>
    </div>
    <blockquote type="cite">
      
      <div dir="ltr">Hello!<br>
        I examined the problem. <br>
        <br>
        1) If I run criu without sudo, &quot;criu/criu --binlog --log-file
        /tmp/sdf.bin check&quot;, there is no crash. If I run &quot;sudo criu/criu
        --binlog --log-file /tmp/sdf.bin check&quot;, I have a crash at the
        end. I thought that there is a problem with some test which is
        not executed without sudo.<br>
        <br>
        2) I&#39;ve found that crash takes place in function cr_check(),
        when it calls CHECK_CAT1(check_sock_diag()); (cr-check.c, line
        1331). If I comment this line, everything works without crash,
        so there is something special in check_sock_diag().<br>
        <br>
        3) Going deeper, actual crash takes place in libnetlink.c, in
        the  nlmsg_receive()  function, when it is called from
        do_rtnl_req() for the second time.<br>
        <br>
        4) In nlmsg_receive(), crash also takes place not on the first
        iteration of its internal cycle. Actually it crashes when
        calling callback function passed as its 3rd parameter, but the
        address of this function is not changed, so there is something
        with its parameters...<br>
        <br>
        5) It looks like there was some inaccurate memory access, which
        wasn&#39;t seen, but now additional variables introduced for the
        binary logging changed memory distribution, and so this
        inaccuracy shows itself... <br>
        <br>
        Of course I can be wrong in my last assumption, but still
        check_sock_diag() is the only place to cause a crash...
        Therefore it&#39;s unlikely that logging is directly related to this
        crash.<br>
        <br>
        6) I can do more debugging with some help - e.g. if someone
        explain what is done in nlmsg_receive() and its callbacks, this
        would speed-up things...<br>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">сб, 31 авг. 2019 г. в 15:40,
          Andrei Vagin &lt;<a href="mailto:avagin@gmail.com" target="_blank" rel="noreferrer">avagin@gmail.com</a>&gt;:<br>
        </div>
        <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          <div dir="auto">
            <div>This patch doesn&#39;t help. I run criu with the -o option,
              it&#39;s a short form of --log-file. I tried to run with
              --log-file and it&#39;s segfaulted too.</div>
            <div dir="auto"><br>
              <div class="gmail_quote" dir="auto">
                <div dir="ltr" class="gmail_attr">On Sat, Aug 31, 2019,
                  12:45 PM Anastasia Markina &lt;<a href="mailto:asyamarkina2@gmail.com" target="_blank" rel="noreferrer">asyamarkina2@gmail.com</a>&gt;
                  wrote:<br>
                </div>
                <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
                  <div dir="auto">
                    <div dir="auto">I&#39;m really sorry, I&#39;ve just found a
                      bug in my criu patch: the crash takes place if log
                      filename is not set via commandline options. The
                      fix is trivial, &quot;flog_ctx.readonly=1; /* don&#39;t try
                      to write into it */&quot; inserted into the criu/log.c,
                      line 245, fixes it. It turns flog off if there is
                      no log file name. I checked other cases, but not
                      this one...</div>
                    <div dir="auto"><br>
                    </div>
                    <div dir="auto">If you run criu with —log-file ...
                      parameter, this bug is not activated.</div>
                    <div dir="auto"><br>
                    </div>
                    <div dir="auto">I&#39;ve updated it in <a href="https://github.com/anastasiamarkina/criu/tree/nastya-flog2" rel="noreferrer noreferrer" target="_blank">https://github.com/anastasiamarkina/criu/tree/nastya-flog2</a>,
                      and I will be happy to follow with any updates
                      needed. Should I make updated patch into the
                      mailing list?</div>
                  </div>
                  <br>
                  <div class="gmail_quote">
                    <div dir="ltr" class="gmail_attr">пт, 30 авг. 2019
                      г., 12:13 Andrei Vagin &lt;<a href="mailto:avagin@gmail.com" rel="noreferrer noreferrer" target="_blank">avagin@gmail.com</a>&gt;:<br>
                    </div>
                    <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Mon, Aug 26,
                      2019 at 05:49:24PM +0300, Anastasia Markina wrote:<br>
                      &gt; Hello! I&#39;ve finalized my work for the GSoC
                      project as a patch, attached to<br>
                      &gt; this message. As before, it is also available
                      in my github repo,<br>
                      &gt; <a href="https://github.com/anastasiamarkina/criu/tree/nastya-flog2" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">https://github.com/anastasiamarkina/criu/tree/nastya-flog2</a><br>
                      &gt; <br>
                      &gt; The next part is a fragment of binlog.txt
                      file included into the patch,<br>
                      &gt; which explains how to use it:<br>
                      &gt; <br>
                      &gt; USAGE: TURNING ON BINARY LOGGING<br>
                      &gt; <br>
                      &gt; Classical text logging is done by default.<br>
                      &gt; Binary logging is turned on by the --binlog
                      command line parameter.<br>
                      &gt; It should be combined with --log-file
                      filename parameter to specify the log<br>
                      &gt; file name (this second parameter is used with
                      both text and binary logging).<br>
                      &gt; <br>
                      &gt; The example:<br>
                      &gt; <br>
                      &gt; criu --log-file /tmp/sdf.bin --binlog check<br>
                      &gt; <br>
                      &gt; USAGE: READING BINARY LOG FILE<br>
                      &gt; <br>
                      &gt; There is a --print-log parameter which turnes
                      criy into a log reader.<br>
                      &gt; It should be combined with --log-file
                      filename parameter, which specifies<br>
                      &gt; the log file name. When these parameters are
                      used, CRIU prints all messages<br>
                      &gt; from the binary log file on the screen and
                      exits. This looks as follows:<br>
                      &gt; <br>
                      &gt; criu --log-file /tmp/sdf.bin --binlog
                      --print-log<br>
                      <br>
                      On my laptop, criu segfaulted with binlog:<br>
                      <br>
                      $ ./criu/criu check --binlog -o /tmp/test.log<br>
                      Segmentation fault (core dumped)<br>
                      <br>
                      (gdb) bt<br>
                      #0  0x00007fb629e45120 in __memchr_avx2 () from
                      /lib64/libc.so.6<br>
                      #1  0x00007fb629d77d4f in memccpy () from
                      /lib64/libc.so.6<br>
                      #2  0x00000000004c754c in flog_encode_msg
                      (ctx=0x676ca0 &lt;flog_ctx&gt;,<br>
                      nargs=nargs@entry=7, mask=mask@entry=65, <br>
                          format=format@entry=0x534888 &quot;\t%s: ino %d
                      peer_ino %d family %4d<br>
                      type %4d state %2d name %s\n&quot;) at
                      flog/src/flog.c:202<br>
                      #3  0x00000000004a7b62 in show_one_unix
                      (act=act@entry=0x510c69<br>
                      &quot;Collected&quot;, sk=sk@entry=0xf7ab90) at
                      criu/sk-unix.c:133<br>
                      #4  0x00000000004ac664 in unix_collect_one
                      (ns=0x7ffe4151e830,<br>
                      tb=0x7ffe4151e660, m=0x56b490 &lt;buf+1968&gt;) at
                      criu/sk-unix.c:764<br>
                      #5  unix_receive_one (h=h@entry=0x56b480
                      &lt;buf+1952&gt;,<br>
                      ns=ns@entry=0x7ffe4151e830,
                      arg=arg@entry=0x7ffe4151e7c0) at<br>
                      criu/sk-unix.c:783<br>
                      #6  0x000000000046bc4f in nlmsg_receive
                      (buf=&lt;optimized out&gt;,<br>
                      arg=&lt;optimized out&gt;, ns=&lt;optimized
                      out&gt;, err_cb=&lt;optimized out&gt;,<br>
                      cb=&lt;optimized out&gt;, len=&lt;optimized
                      out&gt;)<br>
                          at criu/libnetlink.c:41<br>
                      #7  do_rtnl_req (nl=nl@entry=7,
                      req=req@entry=0x7ffe4151e7b0,<br>
                      size=size@entry=72, receive_callback=0x4ac3e0
                      &lt;unix_receive_one&gt;,<br>
                      error_callback=error_callback@entry=0x4ad810
                      &lt;collect_err&gt;, <br>
                          ns=ns@entry=0x7ffe4151e830,
                      arg=0x7ffe4151e7c0) at<br>
                      criu/libnetlink.c:120<br>
                      #8  0x00000000004af6dc in do_collect_req
                      (arg=0x7ffe4151e7c0,<br>
                      ns=&lt;optimized out&gt;, error_callback=0x4ad810
                      &lt;collect_err&gt;,<br>
                      receive_callback=&lt;optimized out&gt;, size=72,
                      req=0x7ffe4151e7b0, nl=7)<br>
                          at criu/sockets.c:817<br>
                      #9  collect_sockets (ns=ns@entry=0x7ffe4151e830)
                      at criu/sockets.c:817<br>
                      #10 0x000000000043d3fd in check_sock_diag () at
                      criu/cr-check.c:127<br>
                      #11 0x000000000043f29c in cr_check () at
                      criu/cr-check.c:1331<br>
                      #12 0x0000000000424b37 in main (argc=&lt;optimized
                      out&gt;,<br>
                      argv=0x7ffe4151eba8, envp=&lt;optimized out&gt;)
                      at criu/crtools.c:257<br>
                      <br>
                      Have you tried to run zdtm tests with this binary
                      logging?<br>
                      <br>
                      How do you handle log messages from parasite and
                      restorer?<br>
                      <br>
                      Did you run any perfomance tests to compare the
                      text and bin logging<br>
                      engines?<br>
                      <br>
                      &gt; <br>
                      &gt; P.S. Thank you for the possibility to work
                      with the project!<br>
                      <br>
                      &gt; From 515a0edf4ffdbfc173e237553e29eae993e8aab6
                      Mon Sep 17 00:00:00 2001<br>
                      &gt; From: Anastasia Markina &lt;<a href="mailto:asyamarkina2@gmail.com" rel="noreferrer noreferrer noreferrer" target="_blank">asyamarkina2@gmail.com</a>&gt;<br>
                      &gt; Date: Thu, 25 Jul 2019 15:51:04 +0300<br>
                      &gt; Subject: [PATCH] criu binary logging based on
                      slightly modified flog engine<br>
                      &gt;  merging flog code into criu and making the
                      first working version with binlog<br>
                      &gt;  log file name is specified after the
                      --log-file key as usual; added --binlog<br>
                      &gt;  option to save binary log instead of text;
                      added --print-log option to print<br>
                      &gt;  messages from binary log file and exit added
                      documentation about binlog<br>
                      &gt;<br>
                      <br>
                      SOB is required.<br>
                      <a href="https://criu.org/How_to_submit_patches" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">https://criu.org/How_to_submit_patches</a><br>
                      <br>
                      &gt; ---<br>
                      &gt;  Documentation/binlog.txt  |  52 +++++++++<br>
                      &gt;  Makefile                  |  13 +++<br>
                      &gt;  criu/Makefile             |   1 +<br>
                      &gt;  criu/Makefile.packages    |   2 +-<br>
                      &gt;  criu/config.c             |   2 +<br>
                      &gt;  criu/crtools.c            | 111
                      ++++++++++++-------<br>
                      &gt;  criu/include/cr_options.h |   2 +<br>
                      &gt;  criu/include/criu-log.h   |   1 +<br>
                      &gt;  criu/include/log.h        |  36 +++++-<br>
                      &gt;  criu/log.c                |  40 +++++--<br>
                      &gt;  flog/Makefile             |   8 ++<br>
                      &gt;  flog/include/flog.h       |   9 ++<br>
                      &gt;  flog/include/uapi/flog.h  | 168
                      ++++++++++++++++++++++++++++<br>
                      &gt;  flog/src/flog.c           | 227
                      ++++++++++++++++++++++++++++++++++++++<br>
                      <br>
                      This patch has to be splitted on five patches or
                      maybe even more:<br>
                      1. Merge flog<br>
                      2. Makefile changes<br>
                      3. Introduce the binlog option<br>
                      4. Integrate flog with CRIU<br>
                      5. Documentations<br>
                      <br>
                      In addition, we need to add a test for this binary
                      logging.<br>
                      <br>
                      &gt;  14 files changed, 620 insertions(+), 52
                      deletions(-)<br>
                      &gt;  create mode 100644 Documentation/binlog.txt<br>
                      &gt;  create mode 100644 flog/Makefile<br>
                      &gt;  create mode 100644 flog/include/flog.h<br>
                      &gt;  create mode 100644 flog/include/uapi/flog.h<br>
                      &gt;  create mode 100644 flog/src/flog.c<br>
                      &gt; <br>
                      &gt; diff --git a/Documentation/binlog.txt
                      b/Documentation/binlog.txt<br>
                      &gt; new file mode 100644<br>
                      &gt; index 00000000..1a5c80c1<br>
                      &gt; --- /dev/null<br>
                      &gt; +++ b/Documentation/binlog.txt<br>
                      &gt; @@ -0,0 +1,52 @@<br>
                      &gt; +CRIU binary logging<br>
                      &gt; +===================<br>
                      &gt; +<br>
                      &gt; +Usage: turning on binary logging<br>
                      &gt; +--------------------------------<br>
                      &gt; +<br>
                      &gt; +Classical text logging is done by default.<br>
                      &gt; +Binary logging is turned on by the
                      `--binlog` command line parameter.<br>
                      &gt; +It should be combined with `--log-file
                      filename` parameter to specify<br>
                      &gt; +the log file name (this second parameter is
                      used with both text and binary logging).<br>
                      &gt; +<br>
                      &gt; +The example:<br>
                      &gt; +<br>
                      &gt; +`criu --log-file /tmp/sdf.bin --binlog
                      check`<br>
                      &gt; +<br>
                      &gt; +Usage: reading binary log file<br>
                      &gt; +------------------------------<br>
                      &gt; +<br>
                      &gt; +There is a `--print-log` parameter which
                      turnes criy into a log reader.<br>
                      &gt; +It should be combined with `--log-file
                      filename` parameter, which specifies<br>
                      &gt; +the log file name. When these parameters are
                      used, CRIU prints all messages<br>
                      &gt; +from the binary log file on the screen and
                      exits. This looks as follows:<br>
                      &gt; +<br>
                      &gt; +`criu --log-file /tmp/sdf.bin --binlog
                      --print-log`<br>
                      &gt; +<br>
                      &gt; +Binary log file format<br>
                      &gt; +----------------------<br>
                      &gt; +<br>
                      &gt; +Text logging in CRIU is based on the printf
                      functions family, with format string<br>
                      &gt; +followed by arguments. To make logging in
                      binary form faster, CRIU just stores<br>
                      &gt; +format string and arguments in binary log
                      without parsing. When binary log file<br>
                      &gt; +is read with `--print-log` parameter, these
                      data are taken from the binary log<br>
                      &gt; +records and passed to a printf function.<br>
                      &gt; +<br>
                      &gt; +Binary log file format is highly inspired by
                      the [flog experimental project](<a href="https://github.com/cyrillos/flog" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">https://github.com/cyrillos/flog</a>).<br>
                      &gt; +Each log message is stored as a format
                      string aned a variable number of<br>
                      &gt; +arguments. The variable size record has
                      following structure:<br>
                      &gt; +<br>
                      &gt; +<br>
                      &gt; +| field   | datatype     |  explanation     
                                    |<br>
                      &gt;
                      +|---------|--------------|---------------------------------|<br>
                      &gt; +| magic   | unsigned int | magic code, equal
                      to `0x676f6c66` |<br>
                      &gt; +| version | unsigned int | binlog file
                      version, equal to `1` |<br>
                      &gt; +| size    | unsigned int | actual size of
                      the record (is needed because of variable
                      arguments|<br>
                      &gt; +| nargs   | unsigned int | number of
                      arguments |<br>
                      &gt; +| mask    | unsigned int | mask, which
                      encodes the argument type, e.g. long integer or
                      string|<br>
                      &gt; +| fmt     | long         | offset to the
                      format string, starting from the beginning of the
                      record|<br>
                      &gt; +| args[0] | long         | 1st argument: the
                      value, if it is a number, or the offset to the
                      string, starting from the beginning of the record
                      |<br>
                      &gt; +| .....   |              | |<br>
                      &gt; +| args[nargs-1] | long   | last argument:
                      the value, if it is a number, or the offset to the
                      string, starting from the beginning of the record
                      |<br>
                      &gt; +| .....   |              | format string and
                      all other strings passed as arguments, if any |<br>
                      &gt; +<br>
                      &gt; diff --git a/Makefile b/Makefile<br>
                      &gt; index 0140330e..c2091a88 100644<br>
                      &gt; --- a/Makefile<br>
                      &gt; +++ b/Makefile<br>
                      &gt; @@ -127,6 +127,8 @@ ifeq ($(GMON),1)<br>
                      &gt;  export GMON GMONLDOPT<br>
                      &gt;  endif<br>
                      &gt;  <br>
                      &gt; +CFLAGS                       += -iquote
                      flog/include/ -iquote flog/include/uapi<br>
                      &gt; +<br>
                      &gt;  AFLAGS                       +=
                      -D__ASSEMBLY__<br>
                      &gt;  CFLAGS                       +=
                      $(USERCFLAGS) $(WARNINGS) $(DEFINES) -iquote
                      include/<br>
                      &gt;  HOSTCFLAGS           += $(WARNINGS)
                      $(DEFINES) -iquote include/<br>
                      &gt; @@ -218,6 +220,17 @@ soccr/built-in.o:
                      $(CONFIG_HEADER) .FORCE<br>
                      &gt;  $(SOCCR_A): |soccr/built-in.o<br>
                      &gt;  criu-deps    += $(SOCCR_A)<br>
                      &gt;  <br>
                      &gt; +#<br>
                      &gt; +# Fast logging library<br>
                      &gt; +FLOG_A := flog/libflog.a<br>
                      &gt; +flog/Makefile: ;<br>
                      &gt; +flog/%: $(CONFIG_HEADER) .FORCE<br>
                      &gt; +     $(Q) $(MAKE) $(build)=flog $@<br>
                      &gt; +flog/built-in.o: $(CONFIG_HEADER) .FORCE<br>
                      &gt; +     $(Q) $(MAKE) $(build)=flog all<br>
                      &gt; +$(FLOG_A): | flog/built-in.o<br>
                      &gt; +criu-deps    += $(FLOG_A)<br>
                      &gt; +<br>
                      &gt;  #<br>
                      &gt;  # CRIU building done in own directory<br>
                      &gt;  # with slightly different rules so we<br>
                      &gt; diff --git a/criu/Makefile b/criu/Makefile<br>
                      &gt; index 4134e505..ee0aa291 100644<br>
                      &gt; --- a/criu/Makefile<br>
                      &gt; +++ b/criu/Makefile<br>
                      &gt; @@ -70,6 +70,7 @@ PROGRAM-BUILTINS    +=
                      images/built-in.o<br>
                      &gt;  PROGRAM-BUILTINS     += $(obj)/built-in.o<br>
                      &gt;  PROGRAM-BUILTINS     += $(ARCH-LIB)<br>
                      &gt;  PROGRAM-BUILTINS     += soccr/libsoccr.a<br>
                      &gt; +PROGRAM-BUILTINS     += flog/libflog.a<br>
                      &gt;  PROGRAM-BUILTINS     += $(COMPEL_LIBS)<br>
                      &gt;  <br>
                      &gt;  $(obj)/built-in.o: pie<br>
                      &gt; diff --git a/criu/Makefile.packages
                      b/criu/Makefile.packages<br>
                      &gt; index f380fa2f..65111f9c 100644<br>
                      &gt; --- a/criu/Makefile.packages<br>
                      &gt; +++ b/criu/Makefile.packages<br>
                      &gt; @@ -32,7 +32,7 @@ REQ-DEB-PKG-NAMES   +=
                      python-future<br>
                      &gt;  REQ-RPM-PKG-TEST-NAMES       +=
                      $(PYTHON)-pyyaml<br>
                      &gt;  endif<br>
                      &gt;  <br>
                      &gt; -export LIBS          += -lprotobuf-c -ldl
                      -lnl-3 -lsoccr -Lsoccr/ -lnet<br>
                      &gt; +export LIBS          += -lprotobuf-c -ldl
                      -lnl-3 -lsoccr -Lsoccr/ -lnet -lffi<br>
                      &gt;  <br>
                      &gt;  check-packages-failed:<br>
                      &gt;       $(warning Can not find some of the
                      required libraries)<br>
                      &gt; diff --git a/criu/config.c b/criu/config.c<br>
                      &gt; index 3a54afd4..7d79c638 100644<br>
                      &gt; --- a/criu/config.c<br>
                      &gt; +++ b/criu/config.c<br>
                      &gt; @@ -458,6 +458,8 @@ int parse_options(int
                      argc, char **argv, bool *usage_error,<br>
                      &gt;               BOOL_OPT(SK_EST_PARAM,
                      &amp;opts.tcp_established_ok),<br>
                      &gt;               { &quot;close&quot;,                     
                      required_argument,      0, 1043 },<br>
                      &gt;               BOOL_OPT(&quot;log-pid&quot;,
                      &amp;opts.log_file_per_pid),<br>
                      &gt; +             BOOL_OPT(&quot;binlog&quot;,
                      &amp;opts.binlog),<br>
                      &gt; +             BOOL_OPT(&quot;print-log&quot;,
                      &amp;opts.printlog),<br>
                      &gt;               { &quot;version&quot;,                   
                      no_argument,            0, &#39;V&#39;  },<br>
                      &gt;               BOOL_OPT(&quot;evasive-devices&quot;,
                      &amp;opts.evasive_devices),<br>
                      &gt;               { &quot;pidfile&quot;,                   
                      required_argument,      0, 1046 },<br>
                      &gt; diff --git a/criu/crtools.c b/criu/crtools.c<br>
                      &gt; index 97a6d6d6..010d8d11 100644<br>
                      &gt; --- a/criu/crtools.c<br>
                      &gt; +++ b/criu/crtools.c<br>
                      &gt; @@ -48,6 +48,14 @@<br>
                      &gt;  #include &quot;sysctl.h&quot;<br>
                      &gt;  #include &quot;img-remote.h&quot;<br>
                      &gt;  <br>
                      &gt; +flog_ctx_t flog_ctx;<br>
                      &gt; +<br>
                      &gt; +<br>
                      &gt; +int criu_quit(int ret_val) {<br>
                      &gt; +     log_fini();     <br>
                      &gt; +     exit(ret_val);<br>
                      &gt; +}<br>
                      &gt; +<br>
                      &gt;  int main(int argc, char *argv[], char
                      *envp[])<br>
                      &gt;  {<br>
                      &gt;       int ret = -1;<br>
                      &gt; @@ -55,7 +63,14 @@ int main(int argc, char
                      *argv[], char *envp[])<br>
                      &gt;       bool has_exec_cmd = false;<br>
                      &gt;       bool has_sub_command;<br>
                      &gt;       int state = PARSING_GLOBAL_CONF;<br>
                      &gt; +     <br>
                      &gt; +     flog_ctx.readonly=1; <br>
                      &gt; +     /* It is not known yet if we will have
                      binlog, but let&#39;s not try to <br>
                      &gt; +      * write into it for safety reasons <br>
                      &gt; +      */<br>
                      &gt; +      <br>
                      &gt;  <br>
                      &gt; +     /* FIXME: where to put flog_fini? */<br>
                      &gt;       BUILD_BUG_ON(CTL_32 !=
                      SYSCTL_TYPE__CTL_32);<br>
                      &gt;       BUILD_BUG_ON(__CTL_STR !=
                      SYSCTL_TYPE__CTL_STR);<br>
                      &gt;       /* We use it for fd overlap handling in
                      clone_service_fd() */<br>
                      &gt; @@ -67,20 +82,34 @@ int main(int argc, char
                      *argv[], char *envp[])<br>
                      &gt;  <br>
                      &gt;       cr_pb_init();<br>
                      &gt;       setproctitle_init(argc, argv, envp);<br>
                      &gt; -<br>
                      &gt; -     if (argc &lt; 2)<br>
                      &gt; +     <br>
                      &gt; +     if (argc &lt; 2) {<br>
                      &gt;               goto usage;<br>
                      &gt; -<br>
                      &gt; +     }<br>
                      &gt; +     <br>
                      &gt;       init_opts();<br>
                      &gt;  <br>
                      &gt; -<br>
                      &gt;       ret = parse_options(argc, argv,
                      &amp;usage_error, &amp;has_exec_cmd, state);<br>
                      &gt;  <br>
                      &gt; +     if (opts.printlog) {<br>
                      &gt; +                             <br>
                      &gt; +             if (log_init(opts.output))<br>
                      &gt; +                     return 1;       <br>
                      &gt; +             /* print and exit */<br>
                      &gt; +             printf(&quot;--- printing log from
                      %s file ---\n&quot;, opts.output);<br>
                      &gt; +             struct stat st;               
                       <br>
                      &gt; +             stat(opts.output, &amp;st);   
                                   <br>
                      &gt; +             if(st.st_size) <br>
                      &gt; +                   
                       flog_decode_all(&amp;flog_ctx, STDOUT_FILENO);<br>
                      &gt; +             printf(&quot;--- end of the log
                      ---\n&quot;);<br>
                      &gt; +             criu_quit(0);<br>
                      &gt; +     }<br>
                      &gt; +     <br>
                      &gt;       if (ret == 1)<br>
                      &gt; -             return 1;<br>
                      &gt; +             return 1;       <br>
                      &gt;       if (ret == 2)<br>
                      &gt; -             goto usage;<br>
                      &gt; -<br>
                      &gt; +             goto usage;     <br>
                      &gt; +     <br>
                      &gt;       log_set_loglevel(opts.log_level);<br>
                      &gt;  <br>
                      &gt;       if (!strcmp(argv[1], &quot;swrk&quot;)) {<br>
                      &gt; @@ -98,6 +127,7 @@ int main(int argc, char
                      *argv[], char *envp[])<br>
                      &gt;  <br>
                      &gt;       if (check_options()) {<br>
                      &gt;             
                       flush_early_log_buffer(STDERR_FILENO);<br>
                      &gt; +             flog_fini(&amp;flog_ctx);<br>
                      &gt;               return 1;<br>
                      &gt;       }<br>
                      &gt;  <br>
                      &gt; @@ -106,7 +136,7 @@ int main(int argc, char
                      *argv[], char *envp[])<br>
                      &gt;  <br>
                      &gt;       if (opts.work_dir == NULL)<br>
                      &gt;               SET_CHAR_OPTS(work_dir,
                      opts.imgs_dir);<br>
                      &gt; -<br>
                      &gt; +     <br>
                      &gt;       if (optind &gt;= argc) {<br>
                      &gt;               pr_msg(&quot;Error: command is
                      required\n&quot;);<br>
                      &gt;               goto usage;<br>
                      &gt; @@ -131,8 +161,8 @@ int main(int argc, char
                      *argv[], char *envp[])<br>
                      &gt;               }<br>
                      &gt;  <br>
                      &gt;               opts.exec_cmd = xmalloc((argc -
                      optind) * sizeof(char *));<br>
                      &gt; -             if (!opts.exec_cmd)<br>
                      &gt; -                     return 1;<br>
                      &gt; +             if (!opts.exec_cmd) <br>
                      &gt; +                     criu_quit(1);<br>
                      &gt;               memcpy(opts.exec_cmd,
                      &amp;argv[optind + 1], (argc - optind - 1) *
                      sizeof(char *));<br>
                      &gt;               opts.exec_cmd[argc - optind -
                      1] = NULL;<br>
                      &gt;       } else {<br>
                      &gt; @@ -148,7 +178,7 @@ int main(int argc, char
                      *argv[], char *envp[])<br>
                      &gt;       if (strcmp(argv[optind], &quot;service&quot;)) {<br>
                      &gt;               ret =
                      open_image_dir(opts.imgs_dir);<br>
                      &gt;               if (ret &lt; 0)<br>
                      &gt; -                     return 1;<br>
                      &gt; +                     criu_quit(1);<br>
                      &gt;       }<br>
                      &gt;  <br>
                      &gt;       /*<br>
                      &gt; @@ -163,14 +193,14 @@ int main(int argc, char
                      *argv[], char *envp[])<br>
                      &gt;  <br>
                      &gt;       if (chdir(opts.work_dir)) {<br>
                      &gt;               pr_perror(&quot;Can&#39;t change
                      directory to %s&quot;, opts.work_dir);<br>
                      &gt; -             return 1;<br>
                      &gt; +             criu_quit(1);<br>
                      &gt;       }<br>
                      &gt;  <br>
                      &gt;       if (log_init(opts.output))<br>
                      &gt; -             return 1;<br>
                      &gt; -<br>
                      &gt; +             return 1;               <br>
                      &gt; +     <br>
                      &gt;       if (kerndat_init())<br>
                      &gt; -             return 1;<br>
                      &gt; +             criu_quit(1);<br>
                      &gt;  <br>
                      &gt;       if (opts.deprecated_ok)<br>
                      &gt;               pr_debug(&quot;DEPRECATED ON\n&quot;);<br>
                      &gt; @@ -178,7 +208,7 @@ int main(int argc, char
                      *argv[], char *envp[])<br>
                      &gt;       if (!list_empty(&amp;opts.inherit_fds))
                      {<br>
                      &gt;               if (strcmp(argv[optind],
                      &quot;restore&quot;)) {<br>
                      &gt;                       pr_err(&quot;--inherit-fd is
                      restore-only option\n&quot;);<br>
                      &gt; -                     return 1;<br>
                      &gt; +                     criu_quit(1);<br>
                      &gt;               }<br>
                      &gt;               /* now that log file is set up,
                      print inherit fd list */<br>
                      &gt;               inherit_fd_log();<br>
                      &gt; @@ -190,7 +220,7 @@ int main(int argc, char
                      *argv[], char *envp[])<br>
                      &gt;       if (!strcmp(argv[optind], &quot;dump&quot;)) {<br>
                      &gt;               if (!opts.tree_id)<br>
                      &gt;                       goto opt_pid_missing;<br>
                      &gt; -             return
                      cr_dump_tasks(opts.tree_id);<br>
                      &gt; +           
                       criu_quit(cr_dump_tasks(opts.tree_id));<br>
                      &gt;       }<br>
                      &gt;  <br>
                      &gt;       if (!strcmp(argv[optind], &quot;pre-dump&quot;))
                      {<br>
                      &gt; @@ -199,10 +229,10 @@ int main(int argc, char
                      *argv[], char *envp[])<br>
                      &gt;  <br>
                      &gt;               if (opts.lazy_pages) {<br>
                      &gt;                       pr_err(&quot;Cannot pre-dump
                      with --lazy-pages\n&quot;);<br>
                      &gt; -                     return 1;<br>
                      &gt; +                     criu_quit(1);<br>
                      &gt;               }<br>
                      &gt;  <br>
                      &gt; -             return
                      cr_pre_dump_tasks(opts.tree_id) != 0;<br>
                      &gt; +           
                       criu_quit(cr_pre_dump_tasks(opts.tree_id) != 0);<br>
                      &gt;       }<br>
                      &gt;  <br>
                      &gt;       if (!strcmp(argv[optind], &quot;restore&quot;)) {<br>
                      &gt; @@ -217,39 +247,41 @@ int main(int argc, char
                      *argv[], char *envp[])<br>
                      &gt;                       ret = 1;<br>
                      &gt;               }<br>
                      &gt;  <br>
                      &gt; -             return ret != 0;<br>
                      &gt; +             criu_quit(ret != 0);<br>
                      &gt;       }<br>
                      &gt;  <br>
                      &gt;       if (!strcmp(argv[optind],
                      &quot;lazy-pages&quot;))<br>
                      &gt; -             return
                      cr_lazy_pages(opts.daemon_mode) != 0;<br>
                      &gt; +           
                       criu_quit(cr_lazy_pages(opts.daemon_mode) != 0);<br>
                      &gt;  <br>
                      &gt; -     if (!strcmp(argv[optind], &quot;check&quot;))<br>
                      &gt; -             return cr_check() != 0;<br>
                      &gt; +     if (!strcmp(argv[optind], &quot;check&quot;)) {<br>
                      &gt; +             ret = cr_check();             
                       <br>
                      &gt; +             criu_quit(ret != 0);<br>
                      &gt; +     }<br>
                      &gt;  <br>
                      &gt;       if (!strcmp(argv[optind],
                      &quot;page-server&quot;))<br>
                      &gt; -             return
                      cr_page_server(opts.daemon_mode, false, -1) != 0;<br>
                      &gt; +           
                       criu_quit(cr_page_server(opts.daemon_mode, false,
                      -1) != 0);<br>
                      &gt;  <br>
                      &gt;       if (!strcmp(argv[optind],
                      &quot;image-cache&quot;)) {<br>
                      &gt;               if (!opts.port)<br>
                      &gt;                       goto opt_port_missing;<br>
                      &gt; -             return
                      image_cache(opts.daemon_mode,
                      DEFAULT_CACHE_SOCKET);<br>
                      &gt; +           
                       criu_quit(image_cache(opts.daemon_mode,
                      DEFAULT_CACHE_SOCKET));<br>
                      &gt;       }<br>
                      &gt;  <br>
                      &gt;       if (!strcmp(argv[optind],
                      &quot;image-proxy&quot;)) {<br>
                      &gt;               if (!opts.addr) {<br>
                      &gt;                       pr_msg(&quot;Error: address
                      not specified\n&quot;);<br>
                      &gt; -                     return 1;<br>
                      &gt; +                     criu_quit(1);<br>
                      &gt;               }<br>
                      &gt;               if (!opts.port)<br>
                      &gt;                       goto opt_port_missing;<br>
                      &gt; -             return
                      image_proxy(opts.daemon_mode,
                      DEFAULT_PROXY_SOCKET);<br>
                      &gt; +           
                       criu_quit(image_proxy(opts.daemon_mode,
                      DEFAULT_PROXY_SOCKET));<br>
                      &gt;       }<br>
                      &gt;  <br>
                      &gt;       if (!strcmp(argv[optind], &quot;service&quot;))<br>
                      &gt; -             return
                      cr_service(opts.daemon_mode);<br>
                      &gt; +           
                       criu_quit(cr_service(opts.daemon_mode));<br>
                      &gt;  <br>
                      &gt;       if (!strcmp(argv[optind], &quot;dedup&quot;))<br>
                      &gt; -             return cr_dedup() != 0;<br>
                      &gt; +             criu_quit(cr_dedup() != 0);<br>
                      &gt;  <br>
                      &gt;       if (!strcmp(argv[optind], &quot;cpuinfo&quot;)) {<br>
                      &gt;               if (!argv[optind + 1]) {<br>
                      &gt; @@ -259,22 +291,23 @@ int main(int argc, char
                      *argv[], char *envp[])<br>
                      &gt;               if (!strcmp(argv[optind + 1],
                      &quot;dump&quot;))<br>
                      &gt;                       return cpuinfo_dump();<br>
                      &gt;               else if (!strcmp(argv[optind +
                      1], &quot;check&quot;))<br>
                      &gt; -                     return cpuinfo_check();<br>
                      &gt; +                   
                       criu_quit(cpuinfo_check());<br>
                      &gt;       }<br>
                      &gt;  <br>
                      &gt;       if (!strcmp(argv[optind], &quot;exec&quot;)) {<br>
                      &gt;               pr_msg(&quot;The \&quot;exec\&quot; action is
                      deprecated by the Compel library.\n&quot;);<br>
                      &gt; -             return -1;<br>
                      &gt; +             criu_quit(-1);<br>
                      &gt;       }<br>
                      &gt;  <br>
                      &gt;       if (!strcmp(argv[optind], &quot;show&quot;)) {<br>
                      &gt;               pr_msg(&quot;The \&quot;show\&quot; action is
                      deprecated by the CRIT utility.\n&quot;);<br>
                      &gt;               pr_msg(&quot;To view an image use
                      the \&quot;crit decode -i $name --pretty\&quot;
                      command.\n&quot;);<br>
                      &gt; -             return -1;<br>
                      &gt; +             criu_quit(-1);<br>
                      &gt;       }<br>
                      &gt; -<br>
                      &gt; +     <br>
                      &gt;       pr_msg(&quot;Error: unknown command: %s\n&quot;,
                      argv[optind]);<br>
                      &gt;  usage:<br>
                      &gt; +     printf(&quot;usage\n&quot;);<br>
                      &gt;       pr_msg(&quot;\n&quot;<br>
                      &gt;  &quot;Usage:\n&quot;<br>
                      &gt;  &quot;  criu dump|pre-dump -t PID
                      [&lt;options&gt;]\n&quot;<br>
                      &gt; @@ -302,8 +335,8 @@ usage:<br>
                      &gt;       );<br>
                      &gt;  <br>
                      &gt;       if (usage_error) {<br>
                      &gt; -             pr_msg(&quot;\nTry -h|--help for
                      more info\n&quot;);<br>
                      &gt; -             return 1;<br>
                      &gt; +             pr_msg(&quot;\nTry -h|--help for
                      more info\n&quot;);                              <br>
                      &gt; +             criu_quit(1);<br>
                      &gt;       }<br>
                      &gt;  <br>
                      &gt;       pr_msg(&quot;\n&quot;<br>
                      &gt; @@ -425,7 +458,9 @@ usage:<br>
                      &gt;  &quot;\n&quot;<br>
                      &gt;  &quot;* Logging:\n&quot;<br>
                      &gt;  &quot;  -o|--log-file FILE    log file name\n&quot;<br>
                      &gt; +&quot;     --binlog           use faster binary
                      log instead of slower text log\n&quot;<br>
                      &gt;  &quot;     --log-pid          enable per-process
                      logging to separate FILE.pid files\n&quot;<br>
                      &gt; +&quot;     --print-log        print log from the
                      binlog file and exit\n&quot;<br>
                      &gt;  &quot;  -v[v...]|--verbosity  increase verbosity
                      (can use multiple v)\n&quot;<br>
                      &gt;  &quot;  -vNUM|--verbosity=NUM set verbosity to
                      NUM (higher level means more output):\n&quot;<br>
                      &gt;  &quot;                          -v1 - only errors
                      and messages\n&quot;<br>
                      &gt; @@ -466,13 +501,13 @@ usage:<br>
                      &gt;  &quot;  -V|--version          show version\n&quot;<br>
                      &gt;       );<br>
                      &gt;  <br>
                      &gt; -     return 0;<br>
                      &gt; +     criu_quit(0);<br>
                      &gt;  <br>
                      &gt;  opt_port_missing:<br>
                      &gt;       pr_msg(&quot;Error: port not specified\n&quot;);<br>
                      &gt; -     return 1;<br>
                      &gt; +     criu_quit(1);<br>
                      &gt;  <br>
                      &gt;  opt_pid_missing:<br>
                      &gt;       pr_msg(&quot;Error: pid not specified\n&quot;);<br>
                      &gt; -     return 1;<br>
                      &gt; +     criu_quit(1);<br>
                      &gt;  }<br>
                      &gt; diff --git a/criu/include/cr_options.h
                      b/criu/include/cr_options.h<br>
                      &gt; index c519c740..a79bdebc 100644<br>
                      &gt; --- a/criu/include/cr_options.h<br>
                      &gt; +++ b/criu/include/cr_options.h<br>
                      &gt; @@ -81,6 +81,8 @@ struct cr_options {<br>
                      &gt;       int                   
                       evasive_devices;<br>
                      &gt;       int                     link_remap_ok;<br>
                      &gt;       int                   
                       log_file_per_pid;<br>
                      &gt; +     int                     binlog;<br>
                      &gt; +     int                     printlog;<br>
                      &gt;       bool                    swrk_restore;<br>
                      &gt;       char                    *output;<br>
                      &gt;       char                    *root;<br>
                      &gt; diff --git a/criu/include/criu-log.h
                      b/criu/include/criu-log.h<br>
                      &gt; index 21ef5430..57792a44 100644<br>
                      &gt; --- a/criu/include/criu-log.h<br>
                      &gt; +++ b/criu/include/criu-log.h<br>
                      &gt; @@ -25,6 +25,7 @@<br>
                      &gt;  struct timeval;<br>
                      &gt;  <br>
                      &gt;  extern int log_init(const char *output);<br>
                      &gt; +<br>
                      &gt;  extern void log_fini(void);<br>
                      &gt;  extern int log_init_by_pid(pid_t pid);<br>
                      &gt;  extern void log_closedir(void);<br>
                      &gt; diff --git a/criu/include/log.h
                      b/criu/include/log.h<br>
                      &gt; index 15787b09..08c57381 100644<br>
                      &gt; --- a/criu/include/log.h<br>
                      &gt; +++ b/criu/include/log.h<br>
                      &gt; @@ -9,6 +9,11 @@<br>
                      &gt;  #include &lt;errno.h&gt;<br>
                      &gt;  #include &lt;stdarg.h&gt;<br>
                      &gt;  <br>
                      &gt; +#include &quot;flog.h&quot;<br>
                      &gt; +<br>
                      &gt; +/* FIXME: Should be in options? */<br>
                      &gt; +extern flog_ctx_t flog_ctx;<br>
                      &gt; +<br>
                      &gt;  extern void vprint_on_level(unsigned int
                      loglevel, const char *format,<br>
                      &gt;               va_list params);<br>
                      &gt;  <br>
                      &gt; @@ -32,35 +37,53 @@ extern void
                      print_on_level(unsigned int loglevel, const char
                      *format, ...)<br>
                      &gt;  <br>
                      &gt;  void flush_early_log_buffer(int fd);<br>
                      &gt;  <br>
                      &gt; +#ifdef CR_NOGLIBC<br>
                      &gt; +#undef flog_encode<br>
                      &gt; +#define flog_encode(ctx, fmt, ...)<br>
                      &gt; +#endif<br>
                      &gt; +<br>
                      &gt;  #define print_once(loglevel, fmt, ...)     
                                                       \<br>
                      &gt;       do {                                   
                                              \<br>
                      &gt;               static bool __printed;         
                                              \<br>
                      &gt;               if (!__printed) {             
                                               \<br>
                      &gt; +                   
                       flog_encode(&amp;flog_ctx, fmt, ##__VA_ARGS__); 
                         \<br>
                      &gt;                     
                       print_on_level(loglevel, fmt, ##__VA_ARGS__);   \<br>
                      &gt;                       __printed = 1;         
                                              \<br>
                      &gt;               }                             
                                               \<br>
                      &gt;       } while (0)<br>
                      &gt;  <br>
                      &gt;  #define pr_msg(fmt, ...)                   
                                               \<br>
                      &gt; +     do {                                   
                                              \<br>
                      &gt; +     flog_encode(&amp;flog_ctx, fmt,
                      ##__VA_ARGS__);                     \<br>
                      &gt;       print_on_level(LOG_MSG,               
                                               \<br>
                      &gt; -                    fmt, ##__VA_ARGS__)<br>
                      &gt; +                    fmt, ##__VA_ARGS__);   
                                               \<br>
                      &gt; +     } while (0)<br>
                      &gt;  <br>
                      &gt;  #define pr_info(fmt, ...)                   
                                              \<br>
                      &gt; +     do {                                   
                                              \<br>
                      &gt; +     flog_encode(&amp;flog_ctx, fmt,
                      ##__VA_ARGS__);                     \<br>
                      &gt;       print_on_level(LOG_INFO,               
                                              \<br>
                      &gt; -                    LOG_PREFIX fmt,
                      ##__VA_ARGS__)<br>
                      &gt; +                    LOG_PREFIX fmt,
                      ##__VA_ARGS__);                  \<br>
                      &gt; +     } while (0)<br>
                      &gt;  <br>
                      &gt;  #define pr_err(fmt, ...)                   
                                               \<br>
                      &gt; +     do {                                   
                                              \<br>
                      &gt; +     flog_encode(&amp;flog_ctx, fmt,
                      ##__VA_ARGS__);                     \<br>
                      &gt;       print_on_level(LOG_ERROR,             
                                               \<br>
                      &gt;                      &quot;Error (%s:%d): &quot;
                      LOG_PREFIX fmt,                \<br>
                      &gt; -                    __FILE__, __LINE__,
                      ##__VA_ARGS__)<br>
                      &gt; +                    __FILE__, __LINE__,
                      ##__VA_ARGS__);              \<br>
                      &gt; +     } while (0)<br>
                      &gt;  <br>
                      &gt;  #define pr_err_once(fmt, ...)               
                                                      \<br>
                      &gt;       print_once(LOG_ERROR, fmt,
                      ##__VA_ARGS__)<br>
                      &gt;  <br>
                      &gt;  #define pr_warn(fmt, ...)                   
                                              \<br>
                      &gt; +     do {                                   
                                              \<br>
                      &gt; +     flog_encode(&amp;flog_ctx, fmt,
                      ##__VA_ARGS__);                     \<br>
                      &gt;       print_on_level(LOG_WARN,               
                                              \<br>
                      &gt;                      &quot;Warn  (%s:%d): &quot;
                      LOG_PREFIX fmt,                \<br>
                      &gt; -                    __FILE__, __LINE__,
                      ##__VA_ARGS__)<br>
                      &gt; +                    __FILE__, __LINE__,
                      ##__VA_ARGS__);              \<br>
                      &gt; +     } while (0)<br>
                      &gt;  <br>
                      &gt;  #define pr_warn_once(fmt, ...)             
                                                       \<br>
                      &gt;         print_once(LOG_WARN,                 
                                              \<br>
                      &gt; @@ -68,8 +91,11 @@ void
                      flush_early_log_buffer(int fd);<br>
                      &gt;                       __FILE__, __LINE__,
                      ##__VA_ARGS__)<br>
                      &gt;  <br>
                      &gt;  #define pr_debug(fmt, ...)                 
                                               \<br>
                      &gt; +     do {                                   
                                              \<br>
                      &gt; +     flog_encode(&amp;flog_ctx, fmt,
                      ##__VA_ARGS__);                     \<br>
                      &gt;       print_on_level(LOG_DEBUG,             
                                               \<br>
                      &gt; -                    LOG_PREFIX fmt,
                      ##__VA_ARGS__)<br>
                      &gt; +                    LOG_PREFIX fmt,
                      ##__VA_ARGS__);                  \<br>
                      &gt; +     } while (0)<br>
                      &gt;  <br>
                      &gt;  #ifndef CR_NOGLIBC<br>
                      &gt;  <br>
                      &gt; diff --git a/criu/log.c b/criu/log.c<br>
                      &gt; index 8bdf8353..723fe72d 100644<br>
                      &gt; --- a/criu/log.c<br>
                      &gt; +++ b/criu/log.c<br>
                      &gt; @@ -10,6 +10,7 @@<br>
                      &gt;  #include &lt;sys/time.h&gt;<br>
                      &gt;  #include &lt;sys/resource.h&gt;<br>
                      &gt;  #include &lt;sys/utsname.h&gt;<br>
                      &gt; +#include &lt;sys/stat.h&gt;<br>
                      &gt;  <br>
                      &gt;  #include &lt;fcntl.h&gt;<br>
                      &gt;  <br>
                      &gt; @@ -207,10 +208,11 @@ void
                      flush_early_log_buffer(int fd)<br>
                      &gt;  int log_init(const char *output)<br>
                      &gt;  {<br>
                      &gt;       int new_logfd, fd;<br>
                      &gt; +     int log_file_open_mode, log_file_perm;<br>
                      &gt;  <br>
                      &gt;       gettimeofday(&amp;start, NULL);<br>
                      &gt;       reset_buf_off();<br>
                      &gt; -<br>
                      &gt; +     memset(&amp;flog_ctx, 0,
                      sizeof(flog_ctx));<br>
                      &gt;       if (output &amp;&amp; !strncmp(output,
                      &quot;-&quot;, 2)) {<br>
                      &gt;               new_logfd = dup(STDOUT_FILENO);<br>
                      &gt;               if (new_logfd &lt; 0) {<br>
                      &gt; @@ -218,7 +220,23 @@ int log_init(const char
                      *output)<br>
                      &gt;                       return -1;<br>
                      &gt;               }<br>
                      &gt;       } else if (output) {<br>
                      &gt; -             new_logfd = open(output,
                      O_CREAT|O_TRUNC|O_WRONLY|O_APPEND, 0600);<br>
                      &gt; +             if (opts.printlog) {<br>
                      &gt; +                     /* read old binlog */<br>
                      &gt; +                     log_file_open_mode =
                      O_RDONLY;<br>
                      &gt; +                     flog_ctx.readonly=1; /*
                      don&#39;t try to write into it */<br>
                      &gt; +                     struct stat st;       
                               <br>
                      &gt; +                     stat(opts.output,
                      &amp;st);                 <br>
                      &gt; +                   
                       flog_ctx.size=st.st_size;<br>
                      &gt; +             }<br>
                      &gt; +             else if (opts.binlog) {<br>
                      &gt; +                     log_file_open_mode =
                      O_RDWR | O_CREAT | O_TRUNC;<br>
                      &gt; +             }<br>
                      &gt; +             else {<br>
                      &gt; +                     flog_ctx.readonly=1; /*
                      no binlog, don&#39;t try to write into it */<br>
                      &gt; +                     log_file_open_mode =
                      O_CREAT|O_TRUNC|O_WRONLY|O_APPEND;<br>
                      &gt; +             }<br>
                      &gt; +             log_file_perm =
                      opts.binlog?0644:0600;<br>
                      &gt; +             new_logfd = open(output,
                      log_file_open_mode, log_file_perm);<br>
                      &gt;               if (new_logfd &lt; 0) {<br>
                      &gt;                       pr_perror(&quot;Can&#39;t create
                      log file %s&quot;, output);<br>
                      &gt;                       return -1;<br>
                      &gt; @@ -234,15 +252,19 @@ int log_init(const char
                      *output)<br>
                      &gt;       fd = install_service_fd(LOG_FD_OFF,
                      new_logfd);<br>
                      &gt;       if (fd &lt; 0)<br>
                      &gt;               goto err;<br>
                      &gt; -<br>
                      &gt; +                     <br>
                      &gt; +     if (opts.binlog||opts.printlog) {<br>
                      &gt; +             <br>
                      &gt; +             flog_map_buf(fd,
                      &amp;flog_ctx);<br>
                      &gt; +     }<br>
                      &gt; +     <br>
                      &gt; +     <br>
                      &gt;       init_done = 1;<br>
                      &gt;  <br>
                      &gt;       /*<br>
                      &gt;        * Once logging is setup this write out
                      all early log messages.<br>
                      &gt;        * Only those messages which have to
                      correct log level are printed.<br>
                      &gt;        */<br>
                      &gt; -     flush_early_log_buffer(fd);<br>
                      &gt; -<br>
                      &gt;       print_versions();<br>
                      &gt;  <br>
                      &gt;       return 0;<br>
                      &gt; @@ -277,7 +299,9 @@ int log_init_by_pid(pid_t
                      pid)<br>
                      &gt;  <br>
                      &gt;  void log_fini(void)<br>
                      &gt;  {<br>
                      &gt; -     close_service_fd(LOG_FD_OFF);<br>
                      &gt; +     flog_fini(&amp;flog_ctx);<br>
                      &gt; +     <br>
                      &gt; +     <br>
                      &gt;  }<br>
                      &gt;  <br>
                      &gt;  static void soccr_print_on_level(unsigned
                      int loglevel, const char *format, ...)<br>
                      &gt; @@ -392,9 +416,9 @@ void
                      vprint_on_level(unsigned int loglevel, const char
                      *format, va_list params)<br>
                      &gt;  }<br>
                      &gt;  <br>
                      &gt;  void print_on_level(unsigned int loglevel,
                      const char *format, ...)<br>
                      &gt; -{<br>
                      &gt; +{    <br>
                      &gt;       va_list params;<br>
                      &gt; -<br>
                      &gt; +     if (opts.binlog) return;<br>
                      &gt;       va_start(params, format);<br>
                      &gt;       vprint_on_level(loglevel, format,
                      params);<br>
                      &gt;       va_end(params);<br>
                      &gt; diff --git a/flog/Makefile b/flog/Makefile<br>
                      &gt; new file mode 100644<br>
                      &gt; index 00000000..71e398ed<br>
                      &gt; --- /dev/null<br>
                      &gt; +++ b/flog/Makefile<br>
                      &gt; @@ -0,0 +1,8 @@<br>
                      &gt; +ccflags-y    += -iquote flog/include<br>
                      &gt; +ccflags-y    += -iquote include<br>
                      &gt; +ccflags-y    += -fno-strict-aliasing<br>
                      &gt; +ldflags-y    += -r<br>
                      &gt; +<br>
                      &gt; +lib-name := libflog.a<br>
                      &gt; +<br>
                      &gt; +lib-y += src/flog.o<br>
                      &gt; diff --git a/flog/include/flog.h
                      b/flog/include/flog.h<br>
                      &gt; new file mode 100644<br>
                      &gt; index 00000000..f00c2054<br>
                      &gt; --- /dev/null<br>
                      &gt; +++ b/flog/include/flog.h<br>
                      &gt; @@ -0,0 +1,9 @@<br>
                      &gt; +#ifndef __FLOG_H__<br>
                      &gt; +#define __FLOG_H__<br>
                      &gt; +<br>
                      &gt; +#include &lt;string.h&gt;<br>
                      &gt; +#include &lt;errno.h&gt;<br>
                      &gt; +<br>
                      &gt; +#include &quot;uapi/flog.h&quot;<br>
                      &gt; +<br>
                      &gt; +#endif /* __FLOG_H__ */<br>
                      &gt; diff --git a/flog/include/uapi/flog.h
                      b/flog/include/uapi/flog.h<br>
                      &gt; new file mode 100644<br>
                      &gt; index 00000000..8ab3566c<br>
                      &gt; --- /dev/null<br>
                      &gt; +++ b/flog/include/uapi/flog.h<br>
                      &gt; @@ -0,0 +1,168 @@<br>
                      &gt; +#ifndef __UAPI_FLOG_H__<br>
                      &gt; +#define __UAPI_FLOG_H__<br>
                      &gt; +<br>
                      &gt; +#include &lt;stdbool.h&gt;<br>
                      &gt; +#include &lt;string.h&gt;<br>
                      &gt; +#include &lt;errno.h&gt;<br>
                      &gt; +<br>
                      &gt; +/*<br>
                      &gt; + * We work with up to 32 arguments in macros
                      here.<br>
                      &gt; + * If more provided -- behaviour is
                      undefined.<br>
                      &gt; + */<br>
                      &gt; +<br>
                      &gt; +/*<br>
                      &gt; + * By Laurent Deniau at <a href="https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s</a><br>
                      &gt; + */<br>
                      &gt; +#define FLOG_PP_NARG_(...)                 
                       FLOG_PP_ARG_N(__VA_ARGS__)<br>
                      &gt; +#define FLOG_PP_NARG(...)                   
                      FLOG_PP_NARG_(1, ##__VA_ARGS__, FLOG_PP_RSEQ_N())<br>
                      &gt; +<br>
                      &gt; +#define FLOG_PP_ARG_N( _0, _1, _2, _3, _4, 
                       \<br>
                      &gt; +                    _5, _6, _7, _8, _9,     
                      \<br>
                      &gt; +                   _10,_11,_12,_13,_14,     
                      \<br>
                      &gt; +                   _15,_16,_17,_18,_19,     
                      \<br>
                      &gt; +                   _20,_21,_22,_23,_24,     
                      \<br>
                      &gt; +                   _25,_26,_27,_28,_29,     
                      \<br>
                      &gt; +                   _30,_31,  N, ...)       
                       N<br>
                      &gt; +<br>
                      &gt; +#define FLOG_PP_RSEQ_N()                   
                       \<br>
                      &gt; +                    31, 30, 29, 28, 27,     
                      \<br>
                      &gt; +                    26, 25, 24, 23, 22,     
                      \<br>
                      &gt; +                    21, 20, 19, 18, 17,     
                      \<br>
                      &gt; +                    16, 15, 14, 13, 12,     
                      \<br>
                      &gt; +                    11, 10,  9,  8,  7,     
                      \<br>
                      &gt; +                     6,  5,  4,  3,  2,     
                      \<br>
                      &gt; +                     1,  0<br>
                      &gt; +<br>
                      &gt; +#define FLOG_GENMASK_0(N, x)         0<br>
                      &gt; +#define FLOG_GENMASK_1(N,  op, x, ...)     
                        (op(N,  0, x))<br>
                      &gt; +#define FLOG_GENMASK_2(N,  op, x, ...)     
                       ((op(N,  1, x)) | FLOG_GENMASK_1(N,  op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_3(N,  op, x, ...)     
                       ((op(N,  2, x)) | FLOG_GENMASK_2(N,  op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_4(N,  op, x, ...)     
                       ((op(N,  3, x)) | FLOG_GENMASK_3(N,  op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_5(N,  op, x, ...)     
                       ((op(N,  4, x)) | FLOG_GENMASK_4(N,  op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_6(N,  op, x, ...)     
                       ((op(N,  5, x)) | FLOG_GENMASK_5(N,  op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_7(N,  op, x, ...)     
                       ((op(N,  6, x)) | FLOG_GENMASK_6(N,  op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_8(N,  op, x, ...)     
                       ((op(N,  7, x)) | FLOG_GENMASK_7(N,  op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_9(N,  op, x, ...)     
                       ((op(N,  8, x)) | FLOG_GENMASK_8(N,  op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_10(N, op, x, ...)     
                       ((op(N,  9, x)) | FLOG_GENMASK_9(N,  op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_11(N, op, x, ...)     
                       ((op(N, 10, x)) | FLOG_GENMASK_10(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_12(N, op, x, ...)     
                       ((op(N, 11, x)) | FLOG_GENMASK_11(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_13(N, op, x, ...)     
                       ((op(N, 12, x)) | FLOG_GENMASK_12(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_14(N, op, x, ...)     
                       ((op(N, 13, x)) | FLOG_GENMASK_13(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_15(N, op, x, ...)     
                       ((op(N, 14, x)) | FLOG_GENMASK_14(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_16(N, op, x, ...)     
                       ((op(N, 15, x)) | FLOG_GENMASK_15(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_17(N, op, x, ...)     
                       ((op(N, 16, x)) | FLOG_GENMASK_16(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_18(N, op, x, ...)     
                       ((op(N, 17, x)) | FLOG_GENMASK_17(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_19(N, op, x, ...)     
                       ((op(N, 18, x)) | FLOG_GENMASK_18(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_20(N, op, x, ...)     
                       ((op(N, 19, x)) | FLOG_GENMASK_19(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_21(N, op, x, ...)     
                       ((op(N, 20, x)) | FLOG_GENMASK_20(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_22(N, op, x, ...)     
                       ((op(N, 21, x)) | FLOG_GENMASK_21(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_23(N, op, x, ...)     
                       ((op(N, 22, x)) | FLOG_GENMASK_22(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_24(N, op, x, ...)     
                       ((op(N, 23, x)) | FLOG_GENMASK_23(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_25(N, op, x, ...)     
                       ((op(N, 24, x)) | FLOG_GENMASK_24(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_26(N, op, x, ...)     
                       ((op(N, 25, x)) | FLOG_GENMASK_25(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_27(N, op, x, ...)     
                       ((op(N, 26, x)) | FLOG_GENMASK_26(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_28(N, op, x, ...)     
                       ((op(N, 27, x)) | FLOG_GENMASK_27(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_29(N, op, x, ...)     
                       ((op(N, 28, x)) | FLOG_GENMASK_28(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_30(N, op, x, ...)     
                       ((op(N, 29, x)) | FLOG_GENMASK_29(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_31(N, op, x, ...)     
                       ((op(N, 30, x)) | FLOG_GENMASK_30(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +#define FLOG_GENMASK_32(N, op, x, ...)     
                       ((op(N, 31, x)) | FLOG_GENMASK_31(N, op, 
                      __VA_ARGS__))<br>
                      &gt; +<br>
                      &gt; +#define FLOG_CONCAT(arg1, arg2)             
                      FLOG_CONCAT1(arg1, arg2)<br>
                      &gt; +#define FLOG_CONCAT1(arg1, arg2)   
                       FLOG_CONCAT2(arg1, arg2)<br>
                      &gt; +#define FLOG_CONCAT2(arg1, arg2)   
                       arg1##arg2<br>
                      &gt; +<br>
                      &gt; +#define FLOG_GENMASK_(N, op, ...)   
                      FLOG_CONCAT(FLOG_GENMASK_, N)(N, op,
                      ##__VA_ARGS__)<br>
                      &gt; +#define FLOG_GENMASK(op, ...)               
                      FLOG_GENMASK_(FLOG_PP_NARG(__VA_ARGS__), op,
                      ##__VA_ARGS__)<br>
                      &gt; +<br>
                      &gt; +#define flog_genbit(ord, n, v, ...)         
                                              \<br>
                      &gt; +     _Generic((v),                         
                                               \<br>
                      &gt; +                                           
                                               \<br>
                      &gt; +              /* Basic types */             
                                              \<br>
                      &gt; +              char:                         
                      0,                      \<br>
                      &gt; +              signed char:                 
                       0,                      \<br>
                      &gt; +              unsigned char:               
                       0,                      \<br>
                      &gt; +              signed short int:             
                      0,                      \<br>
                      &gt; +              unsigned short int:           
                      0,                      \<br>
                      &gt; +              signed int:                   
                      0,                      \<br>
                      &gt; +              unsigned int:                 
                      0,                      \<br>
                      &gt; +              signed long:                 
                       0,                      \<br>
                      &gt; +              unsigned long:               
                       0,                      \<br>
                      &gt; +              signed long long:             
                      0,                      \<br>
                      &gt; +              unsigned long long:           
                      0,                      \<br>
                      &gt; +                                           
                                               \<br>
                      &gt; +              /* Not used for a while */   
                                               \<br>
                      &gt; +              /* float:                     
                      12, */                  \<br>
                      &gt; +              /* double:                   
                       13, */                  \<br>
                      &gt; +              /* long double:               
                      14, */                  \<br>
                      &gt; +                                           
                                               \<br>
                      &gt; +              /* Basic poniters */         
                                               \<br>
                      &gt; +              char *:                       
                      (1u &lt;&lt; (ord - n - 1)),  \<br>
                      &gt; +              signed char *:               
                       (1u &lt;&lt; (ord - n - 1)),  \<br>
                      &gt; +              unsigned char *:             
                       (1u &lt;&lt; (ord - n - 1)),  \<br>
                      &gt; +              signed short int *:           
                      0,                      \<br>
                      &gt; +              unsigned short int *:         
                      0,                      \<br>
                      &gt; +              signed int *:                 
                      0,                      \<br>
                      &gt; +              unsigned int *:               
                      0,                      \<br>
                      &gt; +              signed long *:               
                       0,                      \<br>
                      &gt; +              unsigned long *:             
                       0,                      \<br>
                      &gt; +              signed long long *:           
                      0,                      \<br>
                      &gt; +              unsigned long long *:         
                      0,                      \<br>
                      &gt; +              void *:                       
                      0,                      \<br>
                      &gt; +                                           
                                               \<br>
                      &gt; +              /* Const basic pointers */   
                                               \<br>
                      &gt; +              const char *:                 
                      (1u &lt;&lt; (ord - n - 1)),  \<br>
                      &gt; +              const signed char *:         
                       (1u &lt;&lt; (ord - n - 1)),  \<br>
                      &gt; +              const unsigned char *:       
                       (1u &lt;&lt; (ord - n - 1)),  \<br>
                      &gt; +              const signed short int *:     
                      0,                      \<br>
                      &gt; +              const unsigned short int *:   
                      0,                      \<br>
                      &gt; +              const signed int *:           
                      0,                      \<br>
                      &gt; +              const unsigned int *:         
                      0,                      \<br>
                      &gt; +              const signed long *:         
                       0,                      \<br>
                      &gt; +              const unsigned long *:       
                       0,                      \<br>
                      &gt; +              const signed long long *:     
                      0,                      \<br>
                      &gt; +              const unsigned long long *:   
                      0,                      \<br>
                      &gt; +              const void *:                 
                      0,                      \<br>
                      &gt; +                                           
                                               \<br>
                      &gt; +              /* Systypes and pointers */   
                                              \<br>
                      &gt; +              default:                     
                       -1)<br>
                      &gt; +<br>
                      &gt; +#define FLOG_MAGIC   0x676f6c66<br>
                      &gt; +#define FLOG_VERSION 1<br>
                      &gt; +<br>
                      &gt; +typedef struct {<br>
                      &gt; +     unsigned int    magic;<br>
                      &gt; +     unsigned int    version;<br>
                      &gt; +     unsigned int    size;<br>
                      &gt; +     unsigned int    nargs;<br>
                      &gt; +     unsigned int    mask;<br>
                      &gt; +     long            fmt;<br>
                      &gt; +     long            args[0];<br>
                      &gt; +} flog_msg_t;<br>
                      &gt; +<br>
                      &gt; +typedef struct {<br>
                      &gt; +     char            *buf;<br>
                      &gt; +     char            *pos;<br>
                      &gt; +     size_t          size;<br>
                      &gt; +     size_t          left;<br>
                      &gt; +     int             readonly;<br>
                      &gt; +} flog_ctx_t;<br>
                      &gt; +<br>
                      &gt; +extern int flog_init(flog_ctx_t *ctx);<br>
                      &gt; +extern void flog_fini(flog_ctx_t *ctx);<br>
                      &gt; +<br>
                      &gt; +extern void flog_decode_all(flog_ctx_t *ctx,
                      int fdout);<br>
                      &gt; +<br>
                      &gt; +extern int flog_encode_msg(flog_ctx_t *ctx,<br>
                      &gt; +                        unsigned int nargs,
                      unsigned int mask,<br>
                      &gt; +                        const char *format,
                      ...);<br>
                      &gt; +extern int flog_decode_msg(flog_msg_t *m,
                      int fdout);<br>
                      &gt; +<br>
                      &gt; +extern int flog_map_buf(int fdout,
                      flog_ctx_t *flog_ctx);<br>
                      &gt; +<br>
                      &gt; +#define flog_encode(ctx, fmt, ...)         
                                                       \<br>
                      &gt; +     flog_encode_msg(ctx,                   
                                                      \<br>
                      &gt; +                   
                       FLOG_PP_NARG(__VA_ARGS__),                       
                            \<br>
                      &gt; +                   
                       FLOG_GENMASK(flog_genbit, ##__VA_ARGS__),       
                             \<br>
                      &gt; +                     fmt, ##__VA_ARGS__)<br>
                      &gt; +<br>
                      &gt; +#endif /* __UAPI_FLOG_H__ */<br>
                      &gt; diff --git a/flog/src/flog.c
                      b/flog/src/flog.c<br>
                      &gt; new file mode 100644<br>
                      &gt; index 00000000..9a538795<br>
                      &gt; --- /dev/null<br>
                      &gt; +++ b/flog/src/flog.c<br>
                      &gt; @@ -0,0 +1,227 @@<br>
                      &gt; +#include &lt;stdio.h&gt;<br>
                      &gt; +#include &lt;stdlib.h&gt;<br>
                      &gt; +#include &lt;stdarg.h&gt;<br>
                      &gt; +#include &lt;unistd.h&gt;<br>
                      &gt; +#include &lt;stdint.h&gt;<br>
                      &gt; +<br>
                      &gt; +#include &lt;sys/param.h&gt;<br>
                      &gt; +#include &lt;sys/mman.h&gt;<br>
                      &gt; +<br>
                      &gt; +#include &lt;ffi.h&gt;<br>
                      &gt; +<br>
                      &gt; +#include &quot;common/compiler.h&quot;<br>
                      &gt; +<br>
                      &gt; +#include &quot;flog.h&quot;<br>
                      &gt; +<br>
                      &gt; +#define BUF_SIZE (1&lt;&lt;20)<br>
                      &gt; +<br>
                      &gt; +static char _mbuf[BUF_SIZE];<br>
                      &gt; +static char *mbuf = _mbuf;<br>
                      &gt; +static char *fbuf;<br>
                      &gt; +static uint64_t fsize;<br>
                      &gt; +static uint64_t mbuf_size = sizeof(_mbuf);<br>
                      &gt; +static int binlog_fd;<br>
                      &gt; +<br>
                      &gt; +int flog_map_buf(int fdout, flog_ctx_t
                      *flog_ctx)<br>
                      &gt; +{<br>
                      &gt; +     uint64_t off = 0;<br>
                      &gt; +     void *addr;<br>
                      &gt; +     <br>
                      &gt; +     mbuf_size = 2 * BUF_SIZE;<br>
                      &gt; +     <br>
                      &gt; +     if (flog_ctx-&gt;size==0) 
                      flog_ctx-&gt;size=BUF_SIZE;<br>
                      &gt; +<br>
                      &gt; +     /*<br>
                      &gt; +      * Two buffers are mmaped into memory.
                      A new one is mapped when a first<br>
                      &gt; +      * one is completly filled.<br>
                      &gt; +      */<br>
                      &gt; +     if (fbuf &amp;&amp; (mbuf - fbuf &lt;
                      BUF_SIZE))<br>
                      &gt; +             return 0;<br>
                      &gt; +<br>
                      &gt; +     if (fbuf) {<br>
                      &gt; +             if (munmap(fbuf, BUF_SIZE * 2))
                      {<br>
                      &gt; +                     fprintf(stderr, &quot;Unable
                      to unmap a buffer: %m&quot;);<br>
                      &gt; +                     return 1;<br>
                      &gt; +             }<br>
                      &gt; +             off = mbuf - fbuf - BUF_SIZE;<br>
                      &gt; +             fbuf = NULL;<br>
                      &gt; +     }<br>
                      &gt; +<br>
                      &gt; +     if (fsize == 0)<br>
                      &gt; +             fsize += BUF_SIZE;<br>
                      &gt; +     fsize += BUF_SIZE;<br>
                      &gt; +<br>
                      &gt; +     if (!flog_ctx-&gt;readonly) {<br>
                      &gt; +             if (ftruncate(fdout, fsize)) {<br>
                      &gt; +                     fprintf(stderr, &quot;Unable
                      to truncate a file: %m&quot;);<br>
                      &gt; +                     return -1;<br>
                      &gt; +             }<br>
                      &gt; +     }       <br>
                      &gt; +     if (!fbuf) {<br>
                      &gt; +             if (!flog_ctx-&gt;readonly) { 
                                          <br>
                      &gt; +                     addr = mmap(NULL,
                      BUF_SIZE * 2, PROT_WRITE | PROT_READ,<br>
                      &gt; +                         MAP_FILE |
                      MAP_SHARED, fdout, fsize - 2 * BUF_SIZE);<br>
                      &gt; +             }<br>
                      &gt; +             else {                  <br>
                      &gt; +                     addr = mmap(NULL,
                      flog_ctx-&gt;size, PROT_READ,<br>
                      &gt; +                         MAP_FILE |
                      MAP_SHARED, fdout, 0);<br>
                      &gt; +                     mbuf_size =
                      flog_ctx-&gt;size;<br>
                      &gt; +             }<br>
                      &gt; +     }<br>
                      &gt; +     else {<br>
                      &gt; +             addr = mremap(fbuf + BUF_SIZE,
                      BUF_SIZE,<br>
                      &gt; +                             BUF_SIZE * 2,
                      MREMAP_FIXED, fbuf);<br>
                      &gt; +     }<br>
                      &gt; +     if (addr == MAP_FAILED) {<br>
                      &gt; +             fprintf(stderr, &quot;Unable to map
                      a buffer: %m&quot;);<br>
                      &gt; +             return -1;<br>
                      &gt; +     }<br>
                      &gt; +     <br>
                      &gt; +     fbuf = addr;<br>
                      &gt; +     mbuf = fbuf + off;<br>
                      &gt; +<br>
                      &gt; +     binlog_fd=fdout;<br>
                      &gt; +     flog_init(flog_ctx);<br>
                      &gt; +     return 0;<br>
                      &gt; +}<br>
                      &gt; +<br>
                      &gt; +int flog_init(flog_ctx_t *ctx)<br>
                      &gt; +{<br>
                      &gt; +     ctx-&gt;size = ctx-&gt;left =
                      mbuf_size; <br>
                      &gt; +     ctx-&gt;pos = ctx-&gt;buf = mbuf;<br>
                      &gt; +     if (!ctx-&gt;buf)<br>
                      &gt; +             return -ENOMEM;<br>
                      &gt; +     <br>
                      &gt; +     return 0;<br>
                      &gt; +}<br>
                      &gt; +<br>
                      &gt; +void flog_fini(flog_ctx_t *ctx)<br>
                      &gt; +{<br>
                      &gt; +     if (mbuf == _mbuf)<br>
                      &gt; +             return;<br>
                      &gt; +     munmap(ctx-&gt;buf, BUF_SIZE * 2);<br>
                      &gt; +     ctx-&gt;size=(size_t) (ctx-&gt;pos -
                      ctx-&gt;buf);<br>
                      &gt; +     if (!ctx-&gt;readonly) {<br>
                      &gt; +             if (ftruncate(binlog_fd,
                      ctx-&gt;size)) {<br>
                      &gt; +                     fprintf(stderr, &quot;Unable
                      to truncate a file: %m&quot;);<br>
                      &gt; +             }<br>
                      &gt; +     }<br>
                      &gt; +     <br>
                      &gt; +}<br>
                      &gt; +<br>
                      &gt; +int flog_decode_msg(flog_msg_t *ro_m, int
                      fdout)<br>
                      &gt; +{<br>
                      &gt; +     ffi_type *args[34] = {<br>
                      &gt; +             [0]             =
                      &amp;ffi_type_sint,<br>
                      &gt; +             [1]             =
                      &amp;ffi_type_pointer,<br>
                      &gt; +             [2 ... 33]      =
                      &amp;ffi_type_slong<br>
                      &gt; +     };<br>
                      &gt; +     void *values[34];<br>
                      &gt; +     ffi_cif cif;<br>
                      &gt; +     ffi_arg rc;<br>
                      &gt; +     flog_msg_t *m;<br>
                      &gt; +     size_t i, ret = 0;<br>
                      &gt; +     char *fmt;<br>
                      &gt; +<br>
                      &gt; +     m=malloc(ro_m-&gt;size);<br>
                      &gt; +     memcpy(m, ro_m, ro_m-&gt;size);<br>
                      &gt; +     values[0] = (void *)&amp;fdout;<br>
                      &gt; +     if (m-&gt;magic != FLOG_MAGIC) {<br>
                      &gt; +             return -EINVAL;<br>
                      &gt; +     }<br>
                      &gt; +     if (m-&gt;version != FLOG_VERSION) {<br>
                      &gt; +             return -EINVAL;<br>
                      &gt; +     }<br>
                      &gt; +<br>
                      &gt; +     fmt = (void *)m + m-&gt;fmt;<br>
                      &gt; +     values[1] = &amp;fmt;<br>
                      &gt; +     <br>
                      &gt; +     for (i = 0; i &lt; m-&gt;nargs; i++) { 
                                    <br>
                      &gt; +             values[i + 2] = (void
                      *)&amp;m-&gt;args[i];<br>
                      &gt; +             if (m-&gt;mask &amp; (1u
                      &lt;&lt; i)) {<br>
                      &gt; +                     m-&gt;args[i] =
                      (long)((void *)m + m-&gt;args[i]);<br>
                      &gt; +             }       <br>
                      &gt; +             <br>
                      &gt; +     }<br>
                      &gt; +     <br>
                      &gt; +     int sdf=ffi_prep_cif(&amp;cif,
                      FFI_DEFAULT_ABI, m-&gt;nargs + 2,<br>
                      &gt; +                      &amp;ffi_type_sint,
                      args);<br>
                      &gt; +     if ( sdf == FFI_OK) {<br>
                      &gt; +             ffi_call(&amp;cif,
                      FFI_FN(dprintf), &amp;rc, values);<br>
                      &gt; +     } else<br>
                      &gt; +             ret = -1;<br>
                      &gt; +     <br>
                      &gt; +     free(m);<br>
                      &gt; +     return ret;<br>
                      &gt; +}<br>
                      &gt; +<br>
                      &gt; +void flog_decode_all(flog_ctx_t *ctx, int
                      fdout)<br>
                      &gt; +{<br>
                      &gt; +     flog_msg_t *m;<br>
                      &gt; +     char *pos;<br>
                      &gt; +     printf(&quot;log size is %ld\n&quot;,
                      ctx-&gt;size);<br>
                      &gt; +     if (ctx-&gt;size == 0)<br>
                      &gt; +             return;<br>
                      &gt; +     if (ctx-&gt;readonly)
                      ctx-&gt;pos=ctx-&gt;buf + ctx-&gt;size;<br>
                      &gt; +     for (pos = ctx-&gt;buf; pos &lt;
                      ctx-&gt;pos; ) {<br>
                      &gt; +             m = (void *)pos;<br>
                      &gt; +             flog_decode_msg(m ,fdout);<br>
                      &gt; +             pos += m-&gt;size;<br>
                      &gt; +     }<br>
                      &gt; +}<br>
                      &gt; +<br>
                      &gt; +int flog_encode_msg(flog_ctx_t *ctx,
                      unsigned int nargs, unsigned int mask, const char
                      *format, ...)<br>
                      &gt; +{    <br>
                      &gt; +     if (ctx-&gt;readonly) {            <br>
                      &gt; +             return 0;<br>
                      &gt; +     }<br>
                      &gt; +     flog_msg_t *m = (void *)ctx-&gt;pos;<br>
                      &gt; +     char *str_start, *p;<br>
                      &gt; +     va_list argptr;<br>
                      &gt; +     size_t i;<br>
                      &gt; +<br>
                      &gt; +     m-&gt;nargs = nargs;<br>
                      &gt; +     m-&gt;mask = mask;<br>
                      &gt; +<br>
                      &gt; +     str_start = (void *)m-&gt;args +
                      sizeof(m-&gt;args[0]) * nargs;<br>
                      &gt; +     p = memccpy(str_start, format, 0,
                      ctx-&gt;left - (str_start - ctx-&gt;pos));<br>
                      &gt; +     if (!p)<br>
                      &gt; +             return -ENOMEM;<br>
                      &gt; +<br>
                      &gt; +     m-&gt;fmt = str_start - ctx-&gt;pos;<br>
                      &gt; +     str_start = p;<br>
                      &gt; +     va_start(argptr, format);<br>
                      &gt; +     for (i = 0; i &lt; nargs; i++) {<br>
                      &gt; +             m-&gt;args[i] =
                      (long)va_arg(argptr, long);<br>
                      &gt; +             /*<br>
                      &gt; +              * If we got a string, we
                      should either<br>
                      &gt; +              * reference it when in rodata,
                      or make<br>
                      &gt; +              * a copy (FIXME implement
                      rodata refs).<br>
                      &gt; +              */<br>
                      &gt; +             if (mask &amp; (1u &lt;&lt; i))
                      {<br>
                      &gt; +                     p = memccpy(str_start,
                      (void *)m-&gt;args[i], 0, ctx-&gt;left -
                      (str_start - ctx-&gt;pos));<br>
                      &gt; +                     if (!p)<br>
                      &gt; +                             return -ENOMEM;<br>
                      &gt; +        </blockquote></div></blockquote></div></div></div></blockquote></div></blockquote></div></blockquote></div></div></div>