case the backing block device of the file system of the file
is used. If the bandwidth is suffixed with K, M, G, or T,
the specified bandwidth is parsed as Kilobytes, Megabytes,
- Gigabytes, or Terabytes, respectively (Example:
+ Gigabytes, or Terabytes, respectively, to the base of
+ 1000. (Example:
"/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 5M"). This
controls the <literal>blkio.read_bps_device</literal> and
<literal>blkio.write_bps_device</literal> control group
attributes. Use this option multiple times to set bandwidth
limits for multiple devices. For details about these control
- group attributes, see
- <ulink url="https://www.kernel.org/doc/Documentation/cgroups/blkio-controller.txt">blkio-controller.txt</ulink>.
+ group attributes, see <ulink
+ url="https://www.kernel.org/doc/Documentation/cgroups/blkio-controller.txt">blkio-controller.txt</ulink>.
</para>
<para>Implies
<term><varname>ReceiveBuffer=</varname></term>
<term><varname>SendBuffer=</varname></term>
<listitem><para>Takes an integer
- argument controlling the receive
- or send buffer sizes of this
- socket, respectively. This controls the SO_RCVBUF
- and SO_SNDBUF socket options (see
+ argument controlling the receive or
+ send buffer sizes of this socket,
+ respectively. This controls the
+ SO_RCVBUF and SO_SNDBUF socket options
+ (see
<citerefentry><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>
- for details.).</para></listitem>
+ for details.). The usual suffixes K,
+ M, G are supported and are understood
+ to the base of 1024.</para></listitem>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>PipeSize=</varname></term>
- <listitem><para>Takes an integer
- value. Controls the pipe buffer size
+ <listitem><para>Takes an size in
+ bytes. Controls the pipe buffer size
of FIFOs configured in this socket
unit. See
<citerefentry><refentrytitle>fcntl</refentrytitle><manvolnum>2</manvolnum></citerefentry>
- for details.</para></listitem>
+ for details. The usual suffixes K, M,
+ G are supported and are understood to
+ the base of 1024.</para></listitem>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>MTUBytes=</varname></term>
<listitem>
- <para>The maximum transmission unit in bytes to set for the device.</para>
+ <para>The maximum transmission unit in bytes to set for
+ the device. The usual suffixes K, M, G, are supported and
+ are understood to the base of 1024.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>BitsPerSecond=</varname></term>
<listitem>
- <para>The speed to set for the device, the value is rounded down
- to the nearest Mbps.</para>
+ <para>The speed to set for the device, the value is
+ rounded down to the nearest Mbps. The usual suffixes K, M,
+ G, are supported and are understood to the base of
+ 1000.</para>
</listitem>
</varlistentry>
<varlistentry>
Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections)
Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive)
Socket.Priority, config_parse_int, 0, offsetof(Socket, priority)
-Socket.ReceiveBuffer, config_parse_bytes_size, 0, offsetof(Socket, receive_buffer)
-Socket.SendBuffer, config_parse_bytes_size, 0, offsetof(Socket, send_buffer)
+Socket.ReceiveBuffer, config_parse_iec_size, 0, offsetof(Socket, receive_buffer)
+Socket.SendBuffer, config_parse_iec_size, 0, offsetof(Socket, send_buffer)
Socket.IPTOS, config_parse_ip_tos, 0, offsetof(Socket, ip_tos)
Socket.IPTTL, config_parse_int, 0, offsetof(Socket, ip_ttl)
Socket.Mark, config_parse_int, 0, offsetof(Socket, mark)
-Socket.PipeSize, config_parse_bytes_size, 0, offsetof(Socket, pipe_size)
+Socket.PipeSize, config_parse_iec_size, 0, offsetof(Socket, pipe_size)
Socket.FreeBind, config_parse_bool, 0, offsetof(Socket, free_bind)
Socket.Transparent, config_parse_bool, 0, offsetof(Socket, transparent)
Socket.Broadcast, config_parse_bool, 0, offsetof(Socket, broadcast)
assert_cc(sizeof(uint64_t) == sizeof(off_t));
- r = parse_bytes(rvalue, &bytes);
+ r = parse_size(rvalue, 1024, &bytes);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Memory limit '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
return 0;
}
return 0;
}
- r = parse_bytes(bandwidth, &bytes);
+ r = parse_size(bandwidth, 1000, &bytes);
if (r < 0 || bytes <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
return 0;
}
#endif
{ config_parse_int, "INTEGER" },
{ config_parse_unsigned, "UNSIGNED" },
- { config_parse_bytes_size, "SIZE" },
+ { config_parse_iec_size, "SIZE" },
+ { config_parse_iec_off, "SIZE" },
+ { config_parse_si_size, "SIZE" },
{ config_parse_bool, "BOOLEAN" },
{ config_parse_string, "STRING" },
{ config_parse_path, "PATH" },
Journal.SyncIntervalSec, config_parse_sec, 0, offsetof(Server, sync_interval_usec)
Journal.RateLimitInterval, config_parse_sec, 0, offsetof(Server, rate_limit_interval)
Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(Server, rate_limit_burst)
-Journal.SystemMaxUse, config_parse_bytes_off, 0, offsetof(Server, system_metrics.max_use)
-Journal.SystemMaxFileSize, config_parse_bytes_off, 0, offsetof(Server, system_metrics.max_size)
-Journal.SystemKeepFree, config_parse_bytes_off, 0, offsetof(Server, system_metrics.keep_free)
-Journal.RuntimeMaxUse, config_parse_bytes_off, 0, offsetof(Server, runtime_metrics.max_use)
-Journal.RuntimeMaxFileSize, config_parse_bytes_off, 0, offsetof(Server, runtime_metrics.max_size)
-Journal.RuntimeKeepFree, config_parse_bytes_off, 0, offsetof(Server, runtime_metrics.keep_free)
+Journal.SystemMaxUse, config_parse_iec_off, 0, offsetof(Server, system_metrics.max_use)
+Journal.SystemMaxFileSize, config_parse_iec_off, 0, offsetof(Server, system_metrics.max_size)
+Journal.SystemKeepFree, config_parse_iec_off, 0, offsetof(Server, system_metrics.keep_free)
+Journal.RuntimeMaxUse, config_parse_iec_off, 0, offsetof(Server, runtime_metrics.max_use)
+Journal.RuntimeMaxFileSize, config_parse_iec_off, 0, offsetof(Server, runtime_metrics.max_size)
+Journal.RuntimeKeepFree, config_parse_iec_off, 0, offsetof(Server, runtime_metrics.keep_free)
Journal.MaxRetentionSec, config_parse_sec, 0, offsetof(Server, max_retention_usec)
Journal.MaxFileSec, config_parse_sec, 0, offsetof(Server, max_file_usec)
Journal.ForwardToSyslog, config_parse_bool, 0, offsetof(Server, forward_to_syslog)
DEFINE_PARSER(nsec, nsec_t, parse_nsec)
DEFINE_PARSER(sec, usec_t, parse_sec)
-
-int config_parse_bytes_size(const char* unit,
+int config_parse_iec_size(const char* unit,
const char *filename,
unsigned line,
const char *section,
assert(rvalue);
assert(data);
- r = parse_bytes(rvalue, &o);
+ r = parse_size(rvalue, 1024, &o);
if (r < 0 || (off_t) (size_t) o != o) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse byte value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
return 0;
}
+int config_parse_si_size(const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ size_t *sz = data;
+ off_t o;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = parse_size(rvalue, 1000, &o);
+ if (r < 0 || (off_t) (size_t) o != o) {
+ log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ *sz = (size_t) o;
+ return 0;
+}
-int config_parse_bytes_off(const char* unit,
+int config_parse_iec_off(const char* unit,
const char *filename,
unsigned line,
const char *section,
assert_cc(sizeof(off_t) == sizeof(uint64_t));
- r = parse_bytes(rvalue, bytes);
+ r = parse_size(rvalue, 1024, bytes);
if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse bytes value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
int config_parse_long(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_uint64(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_double(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bytes_size(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bytes_off(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_iec_size(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_si_size(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_iec_off(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_bool(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_show_status(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_string(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
return n;
}
-int parse_bytes(const char *t, off_t *bytes) {
- static const struct {
+int parse_size(const char *t, off_t base, off_t *size) {
+
+ /* Soo, sometimes we want to parse IEC binary suffxies, and
+ * sometimes SI decimal suffixes. This function can parse
+ * both. Which one is the right way depends on the
+ * context. Wikipedia suggests that SI is customary for
+ * hardrware metrics and network speeds, while IEC is
+ * customary for most data sizes used by software and volatile
+ * (RAM) memory. Hence be careful which one you pick!
+ *
+ * In either case we use just K, M, G as suffix, and not Ki,
+ * Mi, Gi or so (as IEC would suggest). That's because that's
+ * frickin' ugly. But this means you really need to make sure
+ * to document which base you are parsing when you use this
+ * call. */
+
+ struct table {
const char *suffix;
unsigned long long factor;
- } table[] = {
+ };
+
+ static const struct table iec[] = {
{ "B", 1 },
{ "K", 1024ULL },
{ "M", 1024ULL*1024ULL },
{ "", 1 },
};
+ static const struct table si[] = {
+ { "B", 1 },
+ { "K", 1000ULL },
+ { "M", 1000ULL*1000ULL },
+ { "G", 1000ULL*1000ULL*1000ULL },
+ { "T", 1000ULL*1000ULL*1000ULL*1000ULL },
+ { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
+ { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL },
+ { "", 1 },
+ };
+
+ const struct table *table;
const char *p;
unsigned long long r = 0;
+ unsigned n_entries;
assert(t);
- assert(bytes);
+ assert(base == 1000 || base == 1024);
+ assert(size);
+
+ if (base == 1000) {
+ table = si;
+ n_entries = ELEMENTSOF(si);
+ } else {
+ table = iec;
+ n_entries = ELEMENTSOF(iec);
+ }
p = t;
do {
e += strspn(e, WHITESPACE);
- for (i = 0; i < ELEMENTSOF(table); i++)
+ for (i = 0; i < n_entries; i++)
if (startswith(e, table[i].suffix)) {
unsigned long long tmp;
if ((unsigned long long) l > ULLONG_MAX / table[i].factor)
break;
}
- if (i >= ELEMENTSOF(table))
+ if (i >= n_entries)
return -EINVAL;
} while (*p);
- *bytes = r;
+ *size = r;
return 0;
}
void close_nointr_nofail(int fd);
void close_many(const int fds[], unsigned n_fd);
+int parse_size(const char *t, off_t base, off_t *size);
+
int parse_boolean(const char *v) _pure_;
-int parse_bytes(const char *t, off_t *bytes);
int parse_pid(const char *s, pid_t* ret_pid);
int parse_uid(const char *s, uid_t* ret_uid);
#define parse_gid(s, ret_uid) parse_uid(s, ret_uid)
} else if (streq(field, "MemoryLimit")) {
off_t bytes;
- r = parse_bytes(eq, &bytes);
+ r = parse_size(eq, 1024, &bytes);
if (r < 0) {
log_error("Failed to parse bytes specification %s", assignment);
return -EINVAL;
return -EINVAL;
}
- r = parse_bytes(bandwidth, &bytes);
+ r = parse_size(bandwidth, 1000, &bytes);
if (r < 0) {
log_error("Failed to parse byte value %s.", bandwidth);
return -EINVAL;
assert(errno == 12);
}
-static void test_parse_bytes(void) {
+static void test_parse_size(void) {
off_t bytes;
- assert_se(parse_bytes("111", &bytes) == 0);
+ assert_se(parse_size("111", 1024, &bytes) == 0);
assert_se(bytes == 111);
- assert_se(parse_bytes(" 112 B", &bytes) == 0);
+ assert_se(parse_size(" 112 B", 1024, &bytes) == 0);
assert_se(bytes == 112);
- assert_se(parse_bytes("3 K", &bytes) == 0);
+ assert_se(parse_size("3 K", 1024, &bytes) == 0);
assert_se(bytes == 3*1024);
- assert_se(parse_bytes(" 4 M 11K", &bytes) == 0);
+ assert_se(parse_size(" 4 M 11K", 1024, &bytes) == 0);
assert_se(bytes == 4*1024*1024 + 11 * 1024);
- assert_se(parse_bytes("3B3G", &bytes) == 0);
+ assert_se(parse_size("3B3G", 1024, &bytes) == 0);
assert_se(bytes == 3ULL*1024*1024*1024 + 3);
- assert_se(parse_bytes("3B3G4T", &bytes) == 0);
+ assert_se(parse_size("3B3G4T", 1024, &bytes) == 0);
assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3);
- assert_se(parse_bytes("12P", &bytes) == 0);
+ assert_se(parse_size("12P", 1024, &bytes) == 0);
assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024);
- assert_se(parse_bytes("3E 2P", &bytes) == 0);
+ assert_se(parse_size("3E 2P", 1024, &bytes) == 0);
assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024);
- assert_se(parse_bytes("12X", &bytes) == -EINVAL);
+ assert_se(parse_size("12X", 1024, &bytes) == -EINVAL);
- assert_se(parse_bytes("1024E", &bytes) == -ERANGE);
- assert_se(parse_bytes("-1", &bytes) == -ERANGE);
- assert_se(parse_bytes("-1024E", &bytes) == -ERANGE);
+ assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE);
+ assert_se(parse_size("-1", 1024, &bytes) == -ERANGE);
+ assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE);
- assert_se(parse_bytes("-1024P", &bytes) == -ERANGE);
+ assert_se(parse_size("-1024P", 1024, &bytes) == -ERANGE);
- assert_se(parse_bytes("-10B 20K", &bytes) == -ERANGE);
+ assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE);
}
static void test_strextend(void) {
test_u64log2();
test_get_process_comm();
test_protect_errno();
- test_parse_bytes();
+ test_parse_size();
test_strextend();
test_strrep();
test_split_pair();
Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy)
Link.Name, config_parse_ifname, 0, offsetof(link_config, name)
Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias)
-Link.MTUBytes, config_parse_bytes_size, 0, offsetof(link_config, mtu)
-Link.BitsPerSecond, config_parse_bytes_size, 0, offsetof(link_config, speed)
+Link.MTUBytes, config_parse_iec_size, 0, offsetof(link_config, mtu)
+Link.BitsPerSecond, config_parse_si_size, 0, offsetof(link_config, speed)
Link.Duplex, config_parse_duplex, 0, offsetof(link_config, duplex)
Link.WakeOnLan, config_parse_wol, 0, offsetof(link_config, wol)