#
a6b29104 |
| 10-Jul-2024 |
Alexander Hansen <alexander.hansen@9elements.com> |
console-server: Add UART Mux Support
This commit adds support for uart-muxes which can be controlled via gpios.
Change-Id: I91a4de1962554adf4302a2a59d2b371f492dc21d Signed-off-by: Alexander Hansen
console-server: Add UART Mux Support
This commit adds support for uart-muxes which can be controlled via gpios.
Change-Id: I91a4de1962554adf4302a2a59d2b371f492dc21d Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com> Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
show more ...
|
#
7851a396 |
| 09-Jul-2024 |
Andrew Jeffery <andrew@codeconstruct.com.au> |
obmc-console: Address more instances of realloc() with size 0
There are some portability concerns around the behavior of passing a zero size to realloc*() APIs. One instance caught by valgrind was f
obmc-console: Address more instances of realloc() with size 0
There are some portability concerns around the behavior of passing a zero size to realloc*() APIs. One instance caught by valgrind was fixed in 2f1abc37384d ("Fix realloc() with size 0"). All invocations of realloc*() APIs were evaluated, and those fixed here are the ones that were at risk.
There's a broader problem of the code-base assuming realloc*() calls don't return NULL (and malloc() also). The returned pointer is usually written into the pointer object passed as the first argument, which means the existing object would be leaked. Fixing that is a bigger endeavor as the callers of the functions invoking realloc*() are often written with the assumption that the result is not NULL. However, with this change, at least one of the realloc*() concerns is put to rest.
Change-Id: I5dd6f4f8cc3164e400c87ea37afc350840a1865d Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
show more ...
|
#
e2826c7d |
| 04-Jul-2024 |
Jeremy Kerr <jk@codeconstruct.com.au> |
console-server: allow separate handler instances
Currently, each handler (socket-handler, tty-handler and log-handler) provides a statically-allocated instance of a handler, which gets initialized f
console-server: allow separate handler instances
Currently, each handler (socket-handler, tty-handler and log-handler) provides a statically-allocated instance of a handler, which gets initialized for a console through the ->init callback.
We have upcoming changes that may create more than one console object, in which case means we will need multiple instances of each handler type.
This change splits the handler type from the handler instance; the former is now struct handler_type, with struct handler being the instance. Handler modules define a (const) struct handler_type, and ->init() now returns a newly-allocated instance of a handler of that type.
This allows multiple handlers of each type.
Because the handler instances are allocated by type->init, we now require both ->init and ->fini to be present on registered handlers.
We no longer need the `bool active` member of the handler, as instances are always active.
Change-Id: Id97f15bd6445e17786f5883b849de8559c5ea434 Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
show more ...
|
Revision tags: v1.1.0 |
|
#
bd992c9f |
| 09-May-2023 |
Ninad Palsule <ninadpalsule@us.ibm.com> |
Add Connect() method to console DBUS object
Added new poller and consumer for the console DBUS data.
Note: We initially developed SocketName attribute but it is now deprecated/removed.
The t
Add Connect() method to console DBUS object
Added new poller and consumer for the console DBUS data.
Note: We initially developed SocketName attribute but it is now deprecated/removed.
The tree of default object: $ busctl tree xyz.openbmc_project.Console.default `-/xyz `-/xyz/openbmc_project `-/xyz/openbmc_project/console `-/xyz/openbmc_project/console/default
The introspect of default console: $ busctl introspect xyz.openbmc_project.Console.default /xyz/openbmc_project/console/default NAME TYPE SIGNATURE RESULT/VALUE FLAGS org.freedesktop.DBus.Introspectable interface - - - .Introspect method - s - org.freedesktop.DBus.Peer interface - - - .GetMachineId method - s - .Ping method - - - org.freedesktop.DBus.Properties interface - - - .Get method ss v - .GetAll method s a{sv} - .Set method ssv - - .PropertiesChanged signal sa{sv}as - - xyz.openbmc_project.Console.Access interface - - - .Connect method - h - xyz.openbmc_project.console interface - - - .setBaudRate method u x - .baudrate property u 0 -
Tested: Performed integration testing with bmcweb.
Change-Id: I2444b1083cf26536f43c6f6b4b0857a2921c4f78 Signed-off-by: Ninad Palsule <ninadpalsule@us.ibm.com>
show more ...
|
#
954be0fb |
| 03-May-2023 |
Andrew Jeffery <andrew@aj.id.au> |
console-server: Add --console-id option
Allow specification of the console-id on the command-line. Specification on the command line takes precedence over the value in the configuration file.
Signe
console-server: Add --console-id option
Allow specification of the console-id on the command-line. Specification on the command line takes precedence over the value in the configuration file.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-Id: Ia143e997b9f5386493564aa92e44e2813173e238
show more ...
|
#
9a8f30ec |
| 01-May-2023 |
Andrew Jeffery <andrew@aj.id.au> |
obmc-console: Introduce console-id, deprecate socket-id
The name `socket-id` exposes too much detail about the implementation. Really the tag identifies the console, so name it as such.
Maintain ba
obmc-console: Introduce console-id, deprecate socket-id
The name `socket-id` exposes too much detail about the implementation. Really the tag identifies the console, so name it as such.
Maintain backwards compatibility until we've converted all the in-tree OpenBMC users over to `console-id`. Once that's done we can drop support for `socket-id`.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-Id: I5aa2ba84835d64901e459b42bfe7be59043466c7
show more ...
|
#
b14ca19c |
| 31-Mar-2023 |
Ninad Palsule <ninadpalsule@us.ibm.com> |
Added new dbus interface to query console info
obmc-console recipe configure consoles by setting the socket-id field in the console server config file. obmc-console server use this socket id to buil
Added new dbus interface to query console info
obmc-console recipe configure consoles by setting the socket-id field in the console server config file. obmc-console server use this socket id to build a abract socket name and register new service "xyz.openbmc_project.Console.Access". The leaf of the object path will be socket-id configured. It also exposes the unix abstract socket name through SocketName property. The socket name is sent as a byte stream as abstract socket contains null character at the start.
*** For example if recipe configured socket-id as "console0" the *** following object is exported through dbus interface
# Tree for "console0" console. $ busctl tree xyz.openbmc_project.Console.console0 `-/xyz `-/xyz/openbmc_project `-/xyz/openbmc_project/console `-/xyz/openbmc_project/console/console0
# Get SocketName property for console0 object $ busctl get-property xyz.openbmc_project.Console.console0 /xyz/openbmc_project/console/console0 xyz.openbmc_project.Console.Access SocketName ay 22 0 111 98 109 99 45 99 111 110 115 111 108 101 46 99 111 110 115 111 108 101 48
# Tree for "hypervisor" console $ busctl tree xyz.openbmc_project.Console.hypervisor `-/xyz `-/xyz/openbmc_project `-/xyz/openbmc_project/console `-/xyz/openbmc_project/console/hypervisor
# Get SocketName property for hypervisor object $ busctl get-property xyz.openbmc_project.Console.hypervisor /xyz/openbmc_project/console/hypervisor xyz.openbmc_project.Console.Access SocketName ay 24 0 111 98 109 99 45 99 111 110 115 111 108 101 46 104 121 112 101 114 118 105 115 111 114
# Note that this is an example of two consoles one is 'console0' and # second is 'hypervisor'. I have formated the output to easy viewing. # We also have one extra service for console that is coming from the # service exist today to get/set the tty device baud rate. $ busctl call xyz.openbmc_project.ObjectMapper \ /xyz/openbmc_project/object_mapper xyz.openbmc_project.ObjectMapper \ GetSubTree sias /xyz/openbmc_project/console 0 1 \ xyz.openbmc_project.Console.Access a{sa{sas}} 2 "/xyz/openbmc_project/console/console0" \ 1 "xyz.openbmc_project.Console.console0" 4 "org.freedesktop.DBus.Introspectable" "org.freedesktop.DBus.Peer" "org.freedesktop.DBus.Properties" "xyz.openbmc_project.Console.Access" "/xyz/openbmc_project/console/hypervisor" 2 "xyz.openbmc_project.Console.hypervisor" 4 "org.freedesktop.DBus.Introspectable" "org.freedesktop.DBus.Peer" "org.freedesktop.DBus.Properties" "xyz.openbmc_project.Console.Access" "xyz.openbmc_project.console" 4 "org.freedesktop.DBus.Introspectable" "org.freedesktop.DBus.Peer" "org.freedesktop.DBus.Properties" "xyz.openbmc_project.Console.Access"
Tested: Tested on the rainer system with busctl command and integration with bmcweb
Related commits: 1) phosphor-dbus-interface: https://gerrit.openbmc.org/c/openbmc/phosphor-dbus-interfaces/+/61486 2) obmc-console: https://gerrit.openbmc.org/c/openbmc/obmc-console/+/62496 3) bmcweb: https://gerrit.openbmc.org/c/openbmc/bmcweb/+/62525
Change-Id: Ifb70ce5585c3937f3abd904ffbae51ca67f58724 Signed-off-by: Ninad Palsule <ninadpalsule@us.ibm.com>
show more ...
|
#
b70f8713 |
| 18-Apr-2023 |
Andrew Jeffery <andrew@aj.id.au> |
obmc-console: Fix readability-isolate-declaration
For example:
``` /usr/bin/clang-tidy -checks=-*, readability-isolate-declaration -export-fixes /tmp/tmpoo7fbs72/tmpo8xiwfxs.yaml -p=build /mnt/host
obmc-console: Fix readability-isolate-declaration
For example:
``` /usr/bin/clang-tidy -checks=-*, readability-isolate-declaration -export-fixes /tmp/tmpoo7fbs72/tmpo8xiwfxs.yaml -p=build /mnt/host/andrew/home/andrew/src/openbmc/obmc-console/test/test-client-escape.c /mnt/host/andrew/home/andrew/src/openbmc/obmc-console/build/../config.c:61:2: error: multiple declarations in a single statement reduces readability [readability-isolate-declaration,-warnings-as-errors] char *name, *value; ^~~~~~~~~~~~~~~~~~~ /mnt/host/andrew/home/andrew/src/openbmc/obmc-console/build/../config.c:62:2: error: multiple declarations in a single statement reduces readability [readability-isolate-declaration,-warnings-as-errors] char *p, *line; ^~~~~~~~~~~~~~~ /mnt/host/andrew/home/andrew/src/openbmc/obmc-console/build/../config.c:110:2: error: multiple declarations in a single statement reduces readability [readability-isolate-declaration,-warnings-as-errors] size_t size, len; ^~~~~~~~~~~~~~~~~ /mnt/host/andrew/home/andrew/src/openbmc/obmc-console/build/../config.c:170:2: error: multiple declarations in a single statement reduces readability [readability-isolate-declaration,-warnings-as-errors] struct config_item *item, *next; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /mnt/host/andrew/home/andrew/src/openbmc/obmc-console/build/../console-client.c:263:2: error: multiple declarations in a single statement reduces readability [readability-isolate-declaration,-warnings-as-errors] struct console_client _client, *client; ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 warnings generated. ```
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-Id: Ia7829b1672ea2dfb3fa020c7c48bd8266e6a1769
show more ...
|
#
0b7b0477 |
| 18-Apr-2023 |
Andrew Jeffery <andrew@aj.id.au> |
obmc-console: Fix readability-else-after-return
``` /usr/bin/clang-tidy -checks=-*, readability-else-after-return -export-fixes /tmp/tmpzmyw6on0/tmpdk8wt96i.yaml -p=build /mnt/host/andrew/home/andre
obmc-console: Fix readability-else-after-return
``` /usr/bin/clang-tidy -checks=-*, readability-else-after-return -export-fixes /tmp/tmpzmyw6on0/tmpdk8wt96i.yaml -p=build /mnt/host/andrew/home/andrew/src/openbmc/obmc-console/test/test-ringbuffer-boundary-poll.c /mnt/host/andrew/home/andrew/src/openbmc/obmc-console/build/../ringbuffer.c:131:4: error: do not use 'else' after 'return' [readability-else-after-return,-warnings-as-errors] } else { ^~~~~~ ```
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-Id: Ic80538a64f061f9ed3d3d71293dcf4f3d99cb6e4
show more ...
|
#
2834c5b1 |
| 18-Apr-2023 |
Andrew Jeffery <andrew@aj.id.au> |
obmc-console: Fix readability-braces-around-statements
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-Id: I88d2bdcb15106298d83a1cf7176e069092820f1d
|
#
91b52175 |
| 18-Apr-2023 |
Andrew Jeffery <andrew@aj.id.au> |
obmc-console: Address bugprone-sizeof-expression
Disable the lint where we know the implementation is valid, but do not disable it globally.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-I
obmc-console: Address bugprone-sizeof-expression
Disable the lint where we know the implementation is valid, but do not disable it globally.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-Id: Ie1640d82138fe91a401188cf966250103a25dde6
show more ...
|
#
19c74d58 |
| 18-Apr-2023 |
Andrew Jeffery <andrew@aj.id.au> |
obmc-console: Extract definition of _GNU_SOURCE
Avoid triggering bugprone-reserved-identifier
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-Id: I8b4d40c92c1e9633bdb078c3f8d6d97ffb248cc2
|
#
5c359cc6 |
| 18-Apr-2023 |
Andrew Jeffery <andrew@aj.id.au> |
obmc-console: Fix bugprone-narrowing-conversions
For example:
``` /mnt/host/andrew/home/andrew/src/openbmc/obmc-console/build/../console-server.c:769:9: error: narrowing conversion from 'ssize_t' (
obmc-console: Fix bugprone-narrowing-conversions
For example:
``` /mnt/host/andrew/home/andrew/src/openbmc/obmc-console/build/../console-server.c:769:9: error: narrowing conversion from 'ssize_t' (aka 'long') to signed type 'int' is implementation-defined [bugprone-narrowing-conversions,-warnings-as-errors] rc = read(console->tty_fd, buf, sizeof(buf)); ^ ```
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-Id: I67c158b411f1533ca3b5a62803116e95907e8c5b
show more ...
|
#
a72711af |
| 18-Apr-2023 |
Andrew Jeffery <andrew@aj.id.au> |
obmc-console: Add clang-format configuration
And apply the formatting.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-Id: I75251051affa5129c8698185baf8d151302b19d6
|
#
21f4cb4a |
| 18-Apr-2023 |
Andrew Jeffery <andrew@aj.id.au> |
socket-handler: Fix void pointer arithmetic
``` cc -Iobmc-console-server.p -I. -I.. -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Wpedantic -Werror -std=gnu17 -O2 -g
socket-handler: Fix void pointer arithmetic
``` cc -Iobmc-console-server.p -I. -I.. -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Wpedantic -Werror -std=gnu17 -O2 -g '-DLOCALSTATEDIR="/var/local"' '-DSYSCONFDIR="etc"' -MD -MQ obmc-console-server.p/socket-handler.c.o -MF obmc-console-server.p/socket-handler.c.o.d -o obmc-console-server.p/socket-handler.c.o -c ../socket-handler.c ../socket-handler.c: In function ‘send_all’: ../socket-handler.c:125:35: error: pointer of type ‘void *’ used in arithmetic [-Werror=pointer-arith] 125 | rc = send(fd, buf + pos, len - pos, flags); | ^ cc1: all warnings being treated as errors ```
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-Id: I2ce817c08b6f5ef7adb4bbf3a79142cd2fee696b
show more ...
|
#
fd048328 |
| 17-Apr-2023 |
Andrew Jeffery <andrew@aj.id.au> |
obmc-console: Mark unused parameters as such
As part of the clean up, remove the size parameter from log_trim(). log_trim() is a static function that only has one call site, so it was straight-forwa
obmc-console: Mark unused parameters as such
As part of the clean up, remove the size parameter from log_trim(). log_trim() is a static function that only has one call site, so it was straight-forward to fix without applying __attribute__((unused)).
Change-Id: Ic61821934dab644590adb4df09b7a8f547aa1c5a Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
show more ...
|
#
cc07530f |
| 31-Mar-2023 |
Jonathan Doman <jonathan.doman@intel.com> |
Support systemd socket activation
Check if systemd passed us a socket when starting obmc-console before creating the socket ourselves. This will support use cases where we don't need obmc-console un
Support systemd socket activation
Check if systemd passed us a socket when starting obmc-console before creating the socket ourselves. This will support use cases where we don't need obmc-console until a SoL is activated by the user.
Tested: Verified that existing unit file installation is unchanged - statically enabled obmc-console@.service instances will be started.
Then disabled obmc-console@ttyS2.service and enabled obmc-console@ttyS2.socket (with a drop-in change to override ListenStream to "obmc-console") and verifed that activating Redfish and SSH SoL would start obmc-console@ttyS2.service and console redirection worked.
Change-Id: I42e96af46a5893145abf27761e97fd4f1b73719d Signed-off-by: Jonathan Doman <jonathan.doman@intel.com>
show more ...
|
#
ddf2ab7c |
| 09-Feb-2020 |
Andrew Jeffery <andrew@aj.id.au> |
obmc-console: Expose socket ID configuration for client and server
* Add a new option in the server configuration file to use a friendly ID in the socket abstract path * Add a new command-line opt
obmc-console: Expose socket ID configuration for client and server
* Add a new option in the server configuration file to use a friendly ID in the socket abstract path * Add a new command-line option to the client to connect to a particular server socket path.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-Id: I95440ca7c2c76d2c1ef00d92abc9e0ffc32cbf5a
show more ...
|
#
5e7c0786 |
| 09-Feb-2020 |
Andrew Jeffery <andrew@aj.id.au> |
console-socket: Add an optional component to UNIX socket abstract names
Allows multiple instances of obmc-console-server to run concurrently without interfering with each other.
Signed-off-by: Andr
console-socket: Add an optional component to UNIX socket abstract names
Allows multiple instances of obmc-console-server to run concurrently without interfering with each other.
Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Change-Id: I7ef9c14e554c687e8d606e1eaaed82a7f1c06d98
show more ...
|
#
1cecc5de |
| 28-Feb-2019 |
Johnathan Mantey <johnathanx.mantey@intel.com> |
Eliminate excessive CPU consumption when redirecting UART over SSH
Redirecting the external UART via SSH caused the console-server, console-client, and dropbear to consume ~30% of the available CPU
Eliminate excessive CPU consumption when redirecting UART over SSH
Redirecting the external UART via SSH caused the console-server, console-client, and dropbear to consume ~30% of the available CPU each when a large amount of data was being written to the UART output.
Buffering all of the small 16550 FIFO bytes into a larger packet and then sending that to the SSH SW allows more efficient transmission over the ethernet connection.
Tested this by "ssh root@<bmc.ip.addr> -p 2200" on a system running a CentOS distribution. Using a BASH console run a large binary file through "od -t x1 <fname>" to create a large amount of traffic. At the BMC console run "top" to review the CPU usage. My experience is after this change is applied: console-server: ~25% CPU dropbear: ~3% CPU console-client: ~1% CPU
Change-Id: Ibabfd285e97a487e7ff040e1cb3159fbff360328 Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
show more ...
|
#
fcf8541b |
| 18-Dec-2018 |
Vernon Mauery <vernon.mauery@linux.intel.com> |
obmc-console-server: bind/connect with the correct sockaddr size
Abstract unix sockets start with the nul-charater, but are not nul terminated. In fact, the nul-character has no meaning in the path.
obmc-console-server: bind/connect with the correct sockaddr size
Abstract unix sockets start with the nul-charater, but are not nul terminated. In fact, the nul-character has no meaning in the path. According to the man page unix(7),
abstract: an abstract socket address is distinguished (from a pathname socket) by the fact that sun_path[0] is a null byte ('\0'). The socket's address in this namespace is given by the additional bytes in sun_path that are covered by the specified length of the address structure. (Null bytes in the name have no special significance.)
This means that when calling bind/connect, the size of the sockaddr structure is not sizeof(sockaddr_un), it is sizeof(sockaddr_un) - sizeof(sun_path) + (path_len)
Change-Id: I6560ba8b2a25a60644873adf66f02a60ded42b1d Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
show more ...
|
#
6b1fed27 |
| 07-Feb-2017 |
Jeremy Kerr <jk@ozlabs.org> |
server: improve blocked-write behaviour for handlers
We currently don't implement POLLOUT properly; we never set this for polled events, and will repeat calls to write() if we see EAGAIN.
This chan
server: improve blocked-write behaviour for handlers
We currently don't implement POLLOUT properly; we never set this for polled events, and will repeat calls to write() if we see EAGAIN.
This change improves the behaviour when writes start to block, by tracking when a fd is blocked. Once we detect blocking behaviour, we supress future (non-forced) writes, and wait for POLLOUT so we know when we can write again.
Change-Id: I809bde4e1c7c78a58ea296d5c076b3d93c272558 Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
show more ...
|
#
f733c85a |
| 07-Feb-2017 |
Jeremy Kerr <jk@ozlabs.org> |
server: use ringbuffer for all handlers
Currently, we use the a ringbuffer within the socket handler to manage bursts of data to slower clients.
However, we're also seeing cases where the local tty
server: use ringbuffer for all handlers
Currently, we use the a ringbuffer within the socket handler to manage bursts of data to slower clients.
However, we're also seeing cases where the local tty handler becomes blocking as well. So, we want to implement a buffer within the tty handler too.
This change moves the ringbuffer 'up a layer' - from the socket handler to the core console code.
We remove the ->data_in callback from handlers, and work on the assumption that handlers have registered their own consumer on the console's ringbuffer (through a new helper function, console_ringbuffer_consumer_register()).
Change-Id: Ie8f02d6632578c50bb5e2dfb9bee6ece86432135 Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
show more ...
|
#
55c9712d |
| 07-Feb-2017 |
Jeremy Kerr <jk@ozlabs.org> |
server: Use consistent function names
Put verbs at the end, ie: console_register_poller -> console_poller_register console_register_handler -> console_handler_register
Change-Id: I4fa78137ce54a3f
server: Use consistent function names
Put verbs at the end, ie: console_register_poller -> console_poller_register console_register_handler -> console_handler_register
Change-Id: I4fa78137ce54a3f15aad87c3371569b084e47094 Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
show more ...
|
#
c9775ce7 |
| 07-Feb-2017 |
Jeremy Kerr <jk@ozlabs.org> |
server: Use ringbuffer for socket backlog
Currently, the socket handler uses a linear buffer for the backlog data; this means we need to shift up to 128kB of data after each socket write().
This ch
server: Use ringbuffer for socket backlog
Currently, the socket handler uses a linear buffer for the backlog data; this means we need to shift up to 128kB of data after each socket write().
This change introduces a single-producer-multiple-consumer ringbuffer, to avoid the need for memmove()ing data around; we can simply update pointers instead of shifting data.
We add this as a new file (ringbuffer.c), to make it a little more modular. To mitigate the risk of subtle pointer arithmetic issues, we add a set of tests too.
Change-Id: Ib7c5151d3cf1f588436f5461000b6fed22d0681c Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
show more ...
|