[systemd-devel] [PATCH 2/2] systemctl: add "systemctl cat"

2013-11-22 Thread Shawn Landden
---
 TODO  |  2 --
 src/shared/fileio.c   | 73 -
 src/shared/fileio.h   |  1 +
 src/systemctl/systemctl.c | 91 +++
 4 files changed, 149 insertions(+), 18 deletions(-)

diff --git a/TODO b/TODO
index 6ba4b31..7c6003b 100644
--- a/TODO
+++ b/TODO
@@ -125,8 +125,6 @@ Features:
 
 * optimize the cgroup propagation bits, especially unit_get_members_mask(), 
cgroup_context_get_mask()
 
-* "systemctl cat" or "systemctl view" command or or so, that cats the backing 
unit file of a service, plus its drop-ins and shows them in a pager
-
 * rfkill,backlight: we probably should run the load tools inside of the udev 
rules so that the state is properly initialized by the time other software sees 
it
 
 * tmpfiles: when applying ownership to /run/log/journal, also do this for the 
journal fails contained in it
diff --git a/src/shared/fileio.c b/src/shared/fileio.c
index 733b320..ac1b409 100644
--- a/src/shared/fileio.c
+++ b/src/shared/fileio.c
@@ -20,6 +20,7 @@
 ***/
 
 #include 
+#include 
 #include "fileio.h"
 #include "util.h"
 #include "strv.h"
@@ -117,6 +118,77 @@ int read_one_line_file(const char *fn, char **line) {
 return 0;
 }
 
+ssize_t sendfile_full(int out_fd, const char *fn) {
+_cleanup_fclose_ FILE *f;
+struct stat st;
+int r;
+ssize_t s;
+
+size_t n, l;
+_cleanup_free_ char *buf = NULL;
+
+assert(out_fd > 0);
+assert(fn);
+
+f = fopen(fn, "r");
+if (!f)
+return -errno;
+
+r = fstat(fileno(f), &st);
+if (r < 0)
+return -errno;
+
+s = sendfile(out_fd, fileno(f), NULL, st.st_size);
+if (s < 0)
+if (errno == EINVAL || errno == ENOSYS) {
+/* continue below */
+} else
+return -errno;
+else
+return s;
+
+/* sendfile() failed, fall back to read/write */
+
+/* Safety check */
+if (st.st_size > 4*1024*1024)
+return -E2BIG;
+
+n = st.st_size > 0 ? st.st_size : LINE_MAX;
+l = 0;
+
+while (true) {
+char *t;
+size_t k;
+
+t = realloc(buf, n);
+if (!t)
+return -ENOMEM;
+
+buf = t;
+k = fread(buf + l, 1, n - l, f);
+
+if (k <= 0) {
+if (ferror(f))
+return -errno;
+
+break;
+}
+
+l += k;
+n *= 2;
+
+/* Safety check */
+if (n > 4*1024*1024)
+return -E2BIG;
+}
+
+r = write(out_fd, buf, l);
+if (r < 0)
+return -errno;
+
+return (ssize_t) l;
+}
+
 int read_full_file(const char *fn, char **contents, size_t *size) {
 _cleanup_fclose_ FILE *f = NULL;
 size_t n, l;
@@ -168,7 +240,6 @@ int read_full_file(const char *fn, char **contents, size_t 
*size) {
 
 buf[l] = 0;
 *contents = buf;
-buf = NULL;
 
 if (size)
 *size = l;
diff --git a/src/shared/fileio.h b/src/shared/fileio.h
index 59e4150..06c2887 100644
--- a/src/shared/fileio.h
+++ b/src/shared/fileio.h
@@ -31,6 +31,7 @@ int write_string_file_atomic(const char *fn, const char 
*line);
 
 int read_one_line_file(const char *fn, char **line);
 int read_full_file(const char *fn, char **contents, size_t *size);
+ssize_t sendfile_full(int out_fd, const char *fn);
 
 int parse_env_file(const char *fname, const char *separator, ...) _sentinel_;
 int load_env_file(const char *fname, const char *separator, char ***l);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 576396f..18d5e45 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3665,16 +3665,25 @@ static int show_all(
 return 0;
 }
 
-static int get_unit_from_arg(sd_bus *bus, char *arg, char **unitp, bool 
interpret_as_job_id) {
-uint32_t id;
+static int cat(sd_bus *bus, char **args) {
 int r = 0;
+char **name;
 
-if (safe_atou32(arg, &id) < 0) {
-_cleanup_free_ char *n = NULL;
-char *unit;
-/* Interpret as unit name */
+_cleanup_free_ char *unit = NULL, *n = NULL;
+
+assert(bus);
+assert(args);
 
-n = unit_name_mangle(arg);
+pager_open_if_enabled();
+
+STRV_FOREACH(name, args+1) {
+_cleanup_free_ char *fragment_path = NULL;
+_cleanup_strv_free_ char **dropin_paths = NULL;
+sd_bus_error error;
+FILE *stdout;
+char **path;
+
+n = unit_name_mangle(*name);
 if (!n)
 r

[systemd-devel] [PATCH 2/2] systemctl: add "systemctl cat"

2013-11-23 Thread Shawn Landden
---
 TODO  |  2 --
 src/shared/fileio.c   | 73 -
 src/shared/fileio.h   |  1 +
 src/systemctl/systemctl.c | 91 +++
 4 files changed, 164 insertions(+), 3 deletions(-)

diff --git a/TODO b/TODO
index 6ba4b31..7c6003b 100644
--- a/TODO
+++ b/TODO
@@ -125,8 +125,6 @@ Features:
 
 * optimize the cgroup propagation bits, especially unit_get_members_mask(), 
cgroup_context_get_mask()
 
-* "systemctl cat" or "systemctl view" command or or so, that cats the backing 
unit file of a service, plus its drop-ins and shows them in a pager
-
 * rfkill,backlight: we probably should run the load tools inside of the udev 
rules so that the state is properly initialized by the time other software sees 
it
 
 * tmpfiles: when applying ownership to /run/log/journal, also do this for the 
journal fails contained in it
diff --git a/src/shared/fileio.c b/src/shared/fileio.c
index 733b320..ac1b409 100644
--- a/src/shared/fileio.c
+++ b/src/shared/fileio.c
@@ -20,6 +20,7 @@
 ***/
 
 #include 
+#include 
 #include "fileio.h"
 #include "util.h"
 #include "strv.h"
@@ -117,6 +118,77 @@ int read_one_line_file(const char *fn, char **line) {
 return 0;
 }
 
+ssize_t sendfile_full(int out_fd, const char *fn) {
+_cleanup_fclose_ FILE *f;
+struct stat st;
+int r;
+ssize_t s;
+
+size_t n, l;
+_cleanup_free_ char *buf = NULL;
+
+assert(out_fd > 0);
+assert(fn);
+
+f = fopen(fn, "r");
+if (!f)
+return -errno;
+
+r = fstat(fileno(f), &st);
+if (r < 0)
+return -errno;
+
+s = sendfile(out_fd, fileno(f), NULL, st.st_size);
+if (s < 0)
+if (errno == EINVAL || errno == ENOSYS) {
+/* continue below */
+} else
+return -errno;
+else
+return s;
+
+/* sendfile() failed, fall back to read/write */
+
+/* Safety check */
+if (st.st_size > 4*1024*1024)
+return -E2BIG;
+
+n = st.st_size > 0 ? st.st_size : LINE_MAX;
+l = 0;
+
+while (true) {
+char *t;
+size_t k;
+
+t = realloc(buf, n);
+if (!t)
+return -ENOMEM;
+
+buf = t;
+k = fread(buf + l, 1, n - l, f);
+
+if (k <= 0) {
+if (ferror(f))
+return -errno;
+
+break;
+}
+
+l += k;
+n *= 2;
+
+/* Safety check */
+if (n > 4*1024*1024)
+return -E2BIG;
+}
+
+r = write(out_fd, buf, l);
+if (r < 0)
+return -errno;
+
+return (ssize_t) l;
+}
+
 int read_full_file(const char *fn, char **contents, size_t *size) {
 _cleanup_fclose_ FILE *f = NULL;
 size_t n, l;
@@ -168,7 +240,6 @@ int read_full_file(const char *fn, char **contents, size_t 
*size) {
 
 buf[l] = 0;
 *contents = buf;
-buf = NULL;
 
 if (size)
 *size = l;
diff --git a/src/shared/fileio.h b/src/shared/fileio.h
index 59e4150..06c2887 100644
--- a/src/shared/fileio.h
+++ b/src/shared/fileio.h
@@ -31,6 +31,7 @@ int write_string_file_atomic(const char *fn, const char 
*line);
 
 int read_one_line_file(const char *fn, char **line);
 int read_full_file(const char *fn, char **contents, size_t *size);
+ssize_t sendfile_full(int out_fd, const char *fn);
 
 int parse_env_file(const char *fname, const char *separator, ...) _sentinel_;
 int load_env_file(const char *fname, const char *separator, char ***l);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 6cb7a82..18d5e45 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3665,6 +3665,95 @@ static int show_all(
 return 0;
 }
 
+static int cat(sd_bus *bus, char **args) {
+int r = 0;
+char **name;
+
+_cleanup_free_ char *unit = NULL, *n = NULL;
+
+assert(bus);
+assert(args);
+
+pager_open_if_enabled();
+
+STRV_FOREACH(name, args+1) {
+_cleanup_free_ char *fragment_path = NULL;
+_cleanup_strv_free_ char **dropin_paths = NULL;
+sd_bus_error error;
+FILE *stdout;
+char **path;
+
+n = unit_name_mangle(*name);
+if (!n)
+return log_oom();
+
+unit = unit_dbus_path_from_name(n);
+if (!unit)
+return log_oom();
+
+if (need_daemon_reload(bus, n)) {
+log_error("Unit file of %s changed on disk. Run 
'systemctl%s daemon-reload'.",
+

Re: [systemd-devel] [PATCH 2/2] systemctl: add "systemctl cat"

2013-11-28 Thread Zbigniew Jędrzejewski-Szmek
On Sat, Nov 23, 2013 at 07:52:53PM -0800, Shawn Landden wrote:
> ---
>  TODO  |  2 --
>  src/shared/fileio.c   | 73 -
>  src/shared/fileio.h   |  1 +
>  src/systemctl/systemctl.c | 91 
> +++
>  4 files changed, 164 insertions(+), 3 deletions(-)
> 
> diff --git a/TODO b/TODO
> index 6ba4b31..7c6003b 100644
> --- a/TODO
> +++ b/TODO
> @@ -125,8 +125,6 @@ Features:
>  
>  * optimize the cgroup propagation bits, especially unit_get_members_mask(), 
> cgroup_context_get_mask()
>  
> -* "systemctl cat" or "systemctl view" command or or so, that cats the 
> backing unit file of a service, plus its drop-ins and shows them in a pager
> -
>  * rfkill,backlight: we probably should run the load tools inside of the udev 
> rules so that the state is properly initialized by the time other software 
> sees it
>  
>  * tmpfiles: when applying ownership to /run/log/journal, also do this for 
> the journal fails contained in it
> diff --git a/src/shared/fileio.c b/src/shared/fileio.c
> index 733b320..ac1b409 100644
> --- a/src/shared/fileio.c
> +++ b/src/shared/fileio.c
> @@ -20,6 +20,7 @@
>  ***/
>  
>  #include 
> +#include 
>  #include "fileio.h"
>  #include "util.h"
>  #include "strv.h"
> @@ -117,6 +118,77 @@ int read_one_line_file(const char *fn, char **line) {
>  return 0;
>  }
>  
> +ssize_t sendfile_full(int out_fd, const char *fn) {
> +_cleanup_fclose_ FILE *f;
> +struct stat st;
> +int r;
> +ssize_t s;
> +
> +size_t n, l;
> +_cleanup_free_ char *buf = NULL;
> +
> +assert(out_fd > 0);
> +assert(fn);
> +
> +f = fopen(fn, "r");
> +if (!f)
> +return -errno;
> +
> +r = fstat(fileno(f), &st);
> +if (r < 0)
> +return -errno;
> +
> +s = sendfile(out_fd, fileno(f), NULL, st.st_size);
> +if (s < 0)
> +if (errno == EINVAL || errno == ENOSYS) {
> +/* continue below */
> +} else
> +return -errno;
> +else
> +return s;
> +
> +/* sendfile() failed, fall back to read/write */
> +
> +/* Safety check */
> +if (st.st_size > 4*1024*1024)
> +return -E2BIG;
> +
> +n = st.st_size > 0 ? st.st_size : LINE_MAX;
> +l = 0;
> +
> +while (true) {
> +char *t;
> +size_t k;
> +
> +t = realloc(buf, n);
> +if (!t)
> +return -ENOMEM;
Can you convert this to GREEDY_REALLOC? It should be a bit simpler then.

> +
> +buf = t;
> +k = fread(buf + l, 1, n - l, f);
> +
> +if (k <= 0) {
> +if (ferror(f))
> +return -errno;
> +
> +break;
> +}
> +
> +l += k;
> +n *= 2;
> +
> +/* Safety check */
> +if (n > 4*1024*1024)
> +return -E2BIG;
> +}
> +
> +r = write(out_fd, buf, l);
> +if (r < 0)
> +return -errno;
> +
> +return (ssize_t) l;
> +}
> +
>  int read_full_file(const char *fn, char **contents, size_t *size) {
>  _cleanup_fclose_ FILE *f = NULL;
>  size_t n, l;
> @@ -168,7 +240,6 @@ int read_full_file(const char *fn, char **contents, 
> size_t *size) {
>  
>  buf[l] = 0;
>  *contents = buf;
> -buf = NULL;
>  
>  if (size)
>  *size = l;
> diff --git a/src/shared/fileio.h b/src/shared/fileio.h
> index 59e4150..06c2887 100644
> --- a/src/shared/fileio.h
> +++ b/src/shared/fileio.h
> @@ -31,6 +31,7 @@ int write_string_file_atomic(const char *fn, const char 
> *line);
>  
>  int read_one_line_file(const char *fn, char **line);
>  int read_full_file(const char *fn, char **contents, size_t *size);
> +ssize_t sendfile_full(int out_fd, const char *fn);
>  
>  int parse_env_file(const char *fname, const char *separator, ...) _sentinel_;
>  int load_env_file(const char *fname, const char *separator, char ***l);
> diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
> index 6cb7a82..18d5e45 100644
> --- a/src/systemctl/systemctl.c
> +++ b/src/systemctl/systemctl.c
> @@ -3665,6 +3665,95 @@ static int show_all(
>  return 0;
>  }
>  
> +static int cat(sd_bus *bus, char **args) {
> +int r = 0;
> +char **name;
> +
> +_cleanup_free_ char *unit = NULL, *n = NULL;
> +
> +assert(bus);
> +assert(args);
> +
> +pager_open_if_enabled();
> +
> +STRV_FOREACH(name, args+1) {
> +_cleanup_free_ char *fragment_path = NULL;
> +_cleanup_strv_free_ char **dropin_paths = NULL;
> +sd_bus_error error;
> +FILE *stdou

Re: [systemd-devel] [PATCH 2/2] systemctl: add "systemctl cat"

2013-11-28 Thread Shawn Landden
On Wed, Nov 27, 2013 at 11:59 PM, Zbigniew Jędrzejewski-Szmek
 wrote:
> On Sat, Nov 23, 2013 at 07:52:53PM -0800, Shawn Landden wrote:
>> ---
>>  TODO  |  2 --
>>  src/shared/fileio.c   | 73 -
>>  src/shared/fileio.h   |  1 +
>>  src/systemctl/systemctl.c | 91 
>> +++
>>  4 files changed, 164 insertions(+), 3 deletions(-)
>>
>> diff --git a/TODO b/TODO
>> index 6ba4b31..7c6003b 100644
>> --- a/TODO
>> +++ b/TODO
>> @@ -125,8 +125,6 @@ Features:
>>
>>  * optimize the cgroup propagation bits, especially unit_get_members_mask(), 
>> cgroup_context_get_mask()
>>
>> -* "systemctl cat" or "systemctl view" command or or so, that cats the 
>> backing unit file of a service, plus its drop-ins and shows them in a pager
>> -
>>  * rfkill,backlight: we probably should run the load tools inside of the 
>> udev rules so that the state is properly initialized by the time other 
>> software sees it
>>
>>  * tmpfiles: when applying ownership to /run/log/journal, also do this for 
>> the journal fails contained in it
>> diff --git a/src/shared/fileio.c b/src/shared/fileio.c
>> index 733b320..ac1b409 100644
>> --- a/src/shared/fileio.c
>> +++ b/src/shared/fileio.c
>> @@ -20,6 +20,7 @@
>>  ***/
>>
>>  #include 
>> +#include 
>>  #include "fileio.h"
>>  #include "util.h"
>>  #include "strv.h"
>> @@ -117,6 +118,77 @@ int read_one_line_file(const char *fn, char **line) {
>>  return 0;
>>  }
>>
>> +ssize_t sendfile_full(int out_fd, const char *fn) {
>> +_cleanup_fclose_ FILE *f;
>> +struct stat st;
>> +int r;
>> +ssize_t s;
>> +
>> +size_t n, l;
>> +_cleanup_free_ char *buf = NULL;
>> +
>> +assert(out_fd > 0);
>> +assert(fn);
>> +
>> +f = fopen(fn, "r");
>> +if (!f)
>> +return -errno;
>> +
>> +r = fstat(fileno(f), &st);
>> +if (r < 0)
>> +return -errno;
>> +
>> +s = sendfile(out_fd, fileno(f), NULL, st.st_size);
>> +if (s < 0)
>> +if (errno == EINVAL || errno == ENOSYS) {
>> +/* continue below */
>> +} else
>> +return -errno;
>> +else
>> +return s;
>> +
>> +/* sendfile() failed, fall back to read/write */
>> +
>> +/* Safety check */
>> +if (st.st_size > 4*1024*1024)
>> +return -E2BIG;
>> +
>> +n = st.st_size > 0 ? st.st_size : LINE_MAX;
>> +l = 0;
>> +
>> +while (true) {
>> +char *t;
>> +size_t k;
>> +
>> +t = realloc(buf, n);
>> +if (!t)
>> +return -ENOMEM;
> Can you convert this to GREEDY_REALLOC? It should be a bit simpler then.
GREEDY_REALLOC isn't appropriate here, (or read_full_file() which this
code is from), as in general stat is going to succeed and we are going
to read
the whole file in one run.
>
>> +
>> +buf = t;
>> +k = fread(buf + l, 1, n - l, f);
>> +
>> +if (k <= 0) {
>> +if (ferror(f))
>> +return -errno;
>> +
>> +break;
>> +}
>> +
>> +l += k;
>> +n *= 2;
>> +
>> +/* Safety check */
>> +if (n > 4*1024*1024)
>> +return -E2BIG;
>> +}
>> +
>> +r = write(out_fd, buf, l);
>> +if (r < 0)
>> +return -errno;
>> +
>> +return (ssize_t) l;
>> +}
>> +
>>  int read_full_file(const char *fn, char **contents, size_t *size) {
>>  _cleanup_fclose_ FILE *f = NULL;
>>  size_t n, l;
>> @@ -168,7 +240,6 @@ int read_full_file(const char *fn, char **contents, 
>> size_t *size) {
>>
>>  buf[l] = 0;
>>  *contents = buf;
>> -buf = NULL;
>>
>>  if (size)
>>  *size = l;
>> diff --git a/src/shared/fileio.h b/src/shared/fileio.h
>> index 59e4150..06c2887 100644
>> --- a/src/shared/fileio.h
>> +++ b/src/shared/fileio.h
>> @@ -31,6 +31,7 @@ int write_string_file_atomic(const char *fn, const char 
>> *line);
>>
>>  int read_one_line_file(const char *fn, char **line);
>>  int read_full_file(const char *fn, char **contents, size_t *size);
>> +ssize_t sendfile_full(int out_fd, const char *fn);
>>
>>  int parse_env_file(const char *fname, const char *separator, ...) 
>> _sentinel_;
>>  int load_env_file(const char *fname, const char *separator, char ***l);
>> diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
>> index 6cb7a82..18d5e45 100644
>> --- a/src/systemctl/systemctl.c
>> +++ b/src/systemctl/systemctl.c
>> @@ -3665,6 +3665,95 @@ static int show_all(
>>  return 0;
>>  }
>>
>> +static int cat(sd_bus *bus, char **args) {
>> +int r = 0;
>> +char **name;
>> +
>> +