summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/powerline.c164
-rwxr-xr-xclient/powerline.py104
-rwxr-xr-xclient/powerline.sh53
3 files changed, 321 insertions, 0 deletions
diff --git a/client/powerline.c b/client/powerline.c
new file mode 100644
index 0000000..ff107ec
--- /dev/null
+++ b/client/powerline.c
@@ -0,0 +1,164 @@
+/* vim:fileencoding=utf-8:noet
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#define HANDLE_ERROR(msg) \
+ do { \
+ perror(msg); \
+ exit(EXIT_FAILURE); \
+ } while (0)
+
+#define TEMP_FAILURE_RETRY(var, expression) \
+ do { \
+ ptrdiff_t __result; \
+ do { \
+ __result = (expression); \
+ } while (__result == -1L && errno == EINTR); \
+ var = __result; \
+ } while (0)
+
+extern char **environ;
+
+void do_write(int sd, const char *raw, size_t len) {
+ size_t written = 0;
+ ptrdiff_t n = -1;
+
+ while (written < len) {
+ TEMP_FAILURE_RETRY(n, write(sd, raw + written, len - written));
+ if (n == -1) {
+ close(sd);
+ HANDLE_ERROR("write() failed");
+ }
+ written += (size_t) n;
+ }
+}
+
+static inline size_t true_sun_len(const struct sockaddr_un *ptr) {
+#ifdef __linux__
+ /* Because SUN_LEN uses strlen and abstract namespace paths begin
+ * with a null byte, SUN_LEN is broken for these. Passing the full
+ * struct size also fails on Linux, so compute manually. The
+ * abstract namespace is Linux-only. */
+ if (ptr->sun_path[0] == '\0') {
+ return sizeof(ptr->sun_family) + strlen(ptr->sun_path + 1) + 1;
+ }
+#endif
+#ifdef SUN_LEN
+ /* If the vendor provided SUN_LEN, we may as well use it. */
+ return SUN_LEN(ptr);
+#else
+ /* SUN_LEN is not POSIX, so if it was not provided, use the struct
+ * size as a fallback. */
+ return sizeof(struct sockaddr_un);
+#endif
+}
+
+#ifdef __linux__
+# define ADDRESS_TEMPLATE "powerline-ipc-%d"
+# define A +1
+#else
+# define ADDRESS_TEMPLATE "/tmp/powerline-ipc-%d"
+# define A
+#endif
+
+#define ADDRESS_SIZE sizeof(ADDRESS_TEMPLATE) + (sizeof(uid_t) * 4)
+#define NUM_ARGS_SIZE (sizeof(int) * 2 + 1)
+#define BUF_SIZE 4096
+#define NEW_ARGV_SIZE 200
+
+int main(int argc, char *argv[]) {
+ int sd = -1;
+ int i;
+ ptrdiff_t read_size;
+ struct sockaddr_un server;
+ char address_buf[ADDRESS_SIZE];
+ const char eof[2] = "\0\0";
+ char num_args[NUM_ARGS_SIZE];
+ char buf[BUF_SIZE];
+ char *newargv[NEW_ARGV_SIZE];
+ char *wd = NULL;
+ char **envp;
+ const char *address;
+ int len;
+
+ if (argc < 2) {
+ printf("Must provide at least one argument.\n");
+ return EXIT_FAILURE;
+ }
+
+ if (argc > 3 && strcmp(argv[1], "--socket") == 0) {
+ address = argv[2];
+ argv += 2;
+ argc -= 2;
+ } else {
+ snprintf(address_buf, ADDRESS_SIZE, ADDRESS_TEMPLATE, getuid());
+ address = &(address_buf[0]);
+ }
+
+ sd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sd == -1)
+ HANDLE_ERROR("socket() failed");
+
+ memset(&server, 0, sizeof(struct sockaddr_un));
+ server.sun_family = AF_UNIX;
+ strncpy(server.sun_path A, address, strlen(address));
+
+ if (connect(sd, (struct sockaddr *) &server, true_sun_len(&server)) < 0) {
+ close(sd);
+ /* We failed to connect to the daemon, execute powerline instead */
+ argc = (argc < NEW_ARGV_SIZE - 1) ? argc : NEW_ARGV_SIZE - 1;
+ for (i = 1; i < argc; i++)
+ newargv[i] = argv[i];
+ newargv[0] = "powerline-render";
+ newargv[argc] = NULL;
+ execvp("powerline-render", newargv);
+ }
+
+ len = snprintf(num_args, NUM_ARGS_SIZE, "%x", argc - 1);
+ do_write(sd, num_args, len);
+ do_write(sd, eof, 1);
+
+ for (i = 1; i < argc; i++) {
+ do_write(sd, argv[i], strlen(argv[i]));
+ do_write(sd, eof, 1);
+ }
+
+ wd = getcwd(NULL, 0);
+ if (wd != NULL) {
+ do_write(sd, wd, strlen(wd));
+ free(wd);
+ wd = NULL;
+ }
+ do_write(sd, eof, 1);
+
+ for(envp=environ; *envp; envp++) {
+ do_write(sd, *envp, strlen(*envp));
+ do_write(sd, eof, 1);
+ }
+
+ do_write(sd, eof, 2);
+
+ read_size = -1;
+ while (read_size != 0) {
+ TEMP_FAILURE_RETRY(read_size, read(sd, buf, BUF_SIZE));
+ if (read_size == -1) {
+ close(sd);
+ HANDLE_ERROR("read() failed");
+ } else if (read_size > 0) {
+ do_write(STDOUT_FILENO, buf, (size_t) read_size);
+ }
+ }
+
+ close(sd);
+
+ return 0;
+}
diff --git a/client/powerline.py b/client/powerline.py
new file mode 100755
index 0000000..28492c1
--- /dev/null
+++ b/client/powerline.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+# vim:fileencoding=utf-8:noet
+from __future__ import (unicode_literals, division, absolute_import, print_function)
+
+import sys
+import socket
+import errno
+import os
+
+try:
+ from posix import environ
+except ImportError:
+ from os import environ
+
+# XXX Hack for importing powerline modules to work.
+sys.path.pop(0)
+
+try:
+ from powerline.lib.encoding import get_preferred_output_encoding
+except ImportError:
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(os.path.realpath(__file__)))))
+ from powerline.lib.encoding import get_preferred_output_encoding
+
+
+if len(sys.argv) < 2:
+ print('Must provide at least one argument.', file=sys.stderr)
+ raise SystemExit(1)
+
+use_filesystem = not sys.platform.lower().startswith('linux')
+
+if sys.argv[1] == '--socket':
+ address = sys.argv[2]
+ if not use_filesystem:
+ address = '\0' + address
+ del sys.argv[1:3]
+else:
+ address = ('/tmp/powerline-ipc-%d' if use_filesystem else '\0powerline-ipc-%d') % os.getuid()
+
+sock = socket.socket(family=socket.AF_UNIX)
+
+
+def eintr_retry_call(func, *args, **kwargs):
+ while True:
+ try:
+ return func(*args, **kwargs)
+ except EnvironmentError as e:
+ if getattr(e, 'errno', None) == errno.EINTR:
+ continue
+ raise
+
+
+try:
+ eintr_retry_call(sock.connect, address)
+except Exception:
+ # Run the powerline renderer
+ args = ['powerline-render'] + sys.argv[1:]
+ os.execvp('powerline-render', args)
+
+fenc = get_preferred_output_encoding()
+
+
+def tobytes(s):
+ if isinstance(s, bytes):
+ return s
+ else:
+ return s.encode(fenc)
+
+
+args = [tobytes('%x' % (len(sys.argv) - 1))]
+args.extend((tobytes(s) for s in sys.argv[1:]))
+
+
+try:
+ cwd = os.getcwd()
+except EnvironmentError:
+ pass
+else:
+ if not isinstance(cwd, bytes):
+ cwd = cwd.encode(fenc)
+ args.append(cwd)
+
+
+args.extend((tobytes(k) + b'=' + tobytes(v) for k, v in environ.items()))
+
+EOF = b'\0\0'
+
+for a in args:
+ eintr_retry_call(sock.sendall, a + b'\0')
+
+eintr_retry_call(sock.sendall, EOF)
+
+received = []
+while True:
+ r = sock.recv(4096)
+ if not r:
+ break
+ received.append(r)
+
+sock.close()
+
+if sys.version_info < (3,):
+ sys.stdout.write(b''.join(received))
+else:
+ sys.stdout.buffer.write(b''.join(received))
diff --git a/client/powerline.sh b/client/powerline.sh
new file mode 100755
index 0000000..ad278c2
--- /dev/null
+++ b/client/powerline.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+use_filesystem=1
+darwin=
+if test -n "$OSTYPE" ; then
+ # OSTYPE variable is a shell feature. supported by bash and zsh, but not
+ # dash, busybox or (m)ksh.
+ if test "${OSTYPE#linux}" '!=' "${OSTYPE}" ; then
+ use_filesystem=
+ elif test "${OSTYPE#darwin}" ; then
+ darwin=1
+ fi
+elif command -v uname >/dev/null ; then
+ if uname -o | grep -iqF linux ; then
+ use_filesystem=
+ elif uname -o | grep -iqF darwin ; then
+ darwin=1
+ fi
+fi
+
+if test "$1" = "--socket" ; then
+ shift
+ ADDRESS="$1"
+ shift
+else
+ ADDRESS="powerline-ipc-${UID:-`id -u`}"
+ test -n "$use_filesystem" && ADDRESS="/tmp/$ADDRESS"
+fi
+
+if test -n "$darwin" ; then
+ ENV=genv
+else
+ ENV=env
+fi
+
+if test -z "$use_filesystem" ; then
+ ADDRESS="abstract-client:$ADDRESS"
+fi
+
+# Warning: env -0 does not work in busybox. Consider switching to parsing
+# `set` output in this case
+(
+ printf '%x\0' "$#"
+ for argv in "$@" ; do
+ printf '%s\0' "$argv"
+ done
+ printf '%s\0' "$PWD"
+ $ENV -0
+) 2>/dev/null | socat -lf/dev/null -t 10 - "$ADDRESS"
+
+if test $? -ne 0 ; then
+ powerline-render "$@"
+fi