Merge "add c version of http_bouncer"
diff --git a/Makefile b/Makefile
index e22fd32..2c82d1e 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@
# via buildroot/packages/google/google_platform/google_platform.mk
DIRS=libstacktrace ginstall cmds \
antirollback tvstat gpio-mailbox spectralanalyzer wifi wifiblaster \
- sysvar py_mtd
+ sysvar py_mtd devcert
ifeq ($(BUILD_SYSMGR),y)
DIRS+=sysmgr
diff --git a/devcert/Makefile b/devcert/Makefile
new file mode 100644
index 0000000..cd01a96
--- /dev/null
+++ b/devcert/Makefile
@@ -0,0 +1,17 @@
+default: all
+
+all:
+
+tests: all
+
+install:
+ @echo "Nothing to install."
+
+install-libs:
+ @echo "No libs to install."
+
+test: tests
+ wvtest/wvtestrun ./gfiber-device-cert.test
+
+clean:
+ rm -f *~ .*~
diff --git a/devcert/debian/.gitignore b/devcert/debian/.gitignore
new file mode 100644
index 0000000..8ff0706
--- /dev/null
+++ b/devcert/debian/.gitignore
@@ -0,0 +1,6 @@
+/files
+/changelog
+/*.debhelper
+/gfiber-device-cert.debhelper.log
+/gfiber-device-cert.substvars
+/gfiber-device-cert
diff --git a/devcert/debian/README.Debian b/devcert/debian/README.Debian
new file mode 100644
index 0000000..0085961
--- /dev/null
+++ b/devcert/debian/README.Debian
@@ -0,0 +1,13 @@
+GFiber device certificates
+--------------------------
+
+This package ensures that there's a GFiber client certificate in
+/etc/ssl/certs/device.pem (and associated private key in
+/etc/ssl/private/device.key). If one isn't already there, it will self-sign
+a certificate and install it for you.
+
+You can dump the contents of the certificate by running gfiber-device-cert
+with no parameters, or add -f to force regeneration of the cert.
+
+Find the source here:
+https://gfiber.googlesource.com/vendor/google/platform/+/master/devcert/
diff --git a/devcert/debian/clean b/devcert/debian/clean
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/devcert/debian/clean
diff --git a/devcert/debian/compat b/devcert/debian/compat
new file mode 100644
index 0000000..7f8f011
--- /dev/null
+++ b/devcert/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/devcert/debian/control b/devcert/debian/control
new file mode 100644
index 0000000..95cd824
--- /dev/null
+++ b/devcert/debian/control
@@ -0,0 +1,14 @@
+Source: gfiber-device-cert
+Section: net
+Priority: extra
+Maintainer: Avery Pennarun <apenwarr@google.com>
+Build-Depends: debhelper (>= 7.0.50~)
+Standards-Version: 3.9.2
+Homepage: https://gfiber.googlesource.com/vendor/google/platform/+/master/devcert/
+Vcs-Git: https://gfiber.googlesource.com/vendor/google/platform
+Vcs-Browser: https://gfiber.googlesource.com/vendor/google/platform
+
+Package: gfiber-device-cert
+Architecture: all
+Depends: openssl (>= 1.0.1)
+Description: Tool for managing GFiber client device certificates
diff --git a/devcert/debian/copyright b/devcert/debian/copyright
new file mode 100644
index 0000000..ce04a83
--- /dev/null
+++ b/devcert/debian/copyright
@@ -0,0 +1,23 @@
+Format: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=173
+Upstream-Name: gfiber-device-cert
+Upstream-Contact: Avery Pennarun <apenwarr@google.com>
+Source: https://gfiber.googlesource.com/vendor/google/platform/+/master/devcert/
+
+Files: *
+Copyright: © 2015 Avery Pennarun <apenwarr@google.com>
+License: Apache
+ *
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
diff --git a/devcert/debian/gen-changelog b/devcert/debian/gen-changelog
new file mode 120000
index 0000000..240869a
--- /dev/null
+++ b/devcert/debian/gen-changelog
@@ -0,0 +1 @@
+../../logupload/client/debian/gen-changelog
\ No newline at end of file
diff --git a/devcert/debian/install b/devcert/debian/install
new file mode 100644
index 0000000..9b5b49d
--- /dev/null
+++ b/devcert/debian/install
@@ -0,0 +1,2 @@
+gfiber-device-cert /usr/bin
+openssl.conf /usr/share/gfiber-device-cert
diff --git a/devcert/debian/postinst b/devcert/debian/postinst
new file mode 100755
index 0000000..20dbd92
--- /dev/null
+++ b/devcert/debian/postinst
@@ -0,0 +1,3 @@
+#DEBHELPER#
+
+gfiber-device-cert
diff --git a/devcert/debian/rules b/devcert/debian/rules
new file mode 100755
index 0000000..02843c4
--- /dev/null
+++ b/devcert/debian/rules
@@ -0,0 +1,13 @@
+#!/usr/bin/make -f
+
+override_dh_auto_test:
+override_dh_auto_install:
+
+%:
+ dh $@
+
+binary: debian/changelog
+
+.PHONY: debian/changelog
+debian/changelog:
+ debian/gen-changelog >$@
diff --git a/devcert/gfiber-device-cert b/devcert/gfiber-device-cert
new file mode 100755
index 0000000..10e259a
--- /dev/null
+++ b/devcert/gfiber-device-cert
@@ -0,0 +1,60 @@
+#!/bin/sh
+[ -n "$KEYFILE" ] || KEYFILE=/etc/ssl/private/device.key
+[ -n "$CERTFILE" ] || CERTFILE=/etc/ssl/certs/device.pem
+[ -n "$SSLCONF" ] || SSLCONF=/usr/share/gfiber-device-cert/openssl.conf
+
+
+fatal() {
+ echo "$0:" "$@" >&2
+ exit 99
+}
+
+
+host=$(
+ hostname -f |
+ sed -e 's/\([^.]*\.[^.]*\).*/\1/' \
+ -e 's/\./_/g'
+)
+full_cn="f88fca-Linux-$host"
+
+if [ "$1" = "-f" ] || [ ! -e "$CERTFILE" ]; then
+ echo "Generating cert for '$full_cn'" >&2
+ touch "$CERTFILE.new" 2>/dev/null ||
+ fatal "can't write '$CERTFILE.new'. run as root?"
+ touch "$KEYFILE.new" 2>/dev/null ||
+ fatal "can't write '$KEYFILE.new'. run as root?"
+ openssl req \
+ -config "$SSLCONF" \
+ -batch \
+ -new \
+ -x509 \
+ -newkey rsa:2048 \
+ -nodes \
+ -keyout "$KEYFILE.new" \
+ -out "$CERTFILE.new" \
+ -days 36500 \
+ -subj "/CN=$full_cn" || fatal "failed to generate key"
+ chmod a+r "$CERTFILE.new"
+ mv "$KEYFILE.new" "$KEYFILE"
+ mv "$CERTFILE.new" "$CERTFILE"
+fi
+
+[ -r "$CERTFILE" ] || fatal "'$CERTFILE' is not readable. run as root?"
+
+real_cn=$(
+ openssl x509 -in "$CERTFILE" -text -noout |
+ perl -ne '/Subject: CN=(.*)/ && { print $1 }'
+)
+
+openssl x509 -in "$CERTFILE" -text || fatal "error dumping certificate"
+
+if [ "$real_cn" != "$full_cn" ]; then
+ echo >&2
+ echo "Warning: expected 'CN=$full_cn'" >&2
+ echo " got 'CN=$real_cn'" >&2
+ echo "Warning: this cert might not be accepted by servers." >&2
+ echo "Warning: to regenerate it, run: $0 -f" >&2
+ exit 10
+fi
+
+exit 0
diff --git a/devcert/gfiber-device-cert.test b/devcert/gfiber-device-cert.test
new file mode 100755
index 0000000..33f29d3
--- /dev/null
+++ b/devcert/gfiber-device-cert.test
@@ -0,0 +1,25 @@
+#!/bin/sh
+. ./wvtest/wvtest.sh
+
+WVSTART "gfiber-device-cert"
+
+export CERTFILE=cert.tmp KEYFILE=key.tmp SSLCONF=openssl.conf
+
+# Generate an initial certificate
+rm -f "$CERTFILE" "$KEYFILE"
+WVFAIL [ -r "$CERTFILE" ]
+WVFAIL [ -r "$KEYFILE" ]
+WVPASS ./gfiber-device-cert
+WVPASS [ -r "$CERTFILE" ]
+WVPASS [ -r "$KEYFILE" ]
+sum1=$(sha1sum "$CERTFILE" "$KEYFILE")
+
+# should not replace the cert
+WVPASS ./gfiber-device-cert
+sum2=$(sha1sum "$CERTFILE" "$KEYFILE")
+WVPASSEQ "$sum1" "$sum2"
+
+# -f should cause the cert to be replaced
+WVPASS ./gfiber-device-cert -f
+sum2=$(sha1sum "$CERTFILE" "$KEYFILE")
+WVPASSNE "$sum1" "$sum2"
diff --git a/devcert/openssl.conf b/devcert/openssl.conf
new file mode 100644
index 0000000..a11a653
--- /dev/null
+++ b/devcert/openssl.conf
@@ -0,0 +1,5 @@
+
+[req]
+distinguished_name = req_distinguished_name
+
+[req_distinguished_name]
diff --git a/devcert/wvtest b/devcert/wvtest
new file mode 120000
index 0000000..75927a5
--- /dev/null
+++ b/devcert/wvtest
@@ -0,0 +1 @@
+../cmds/wvtest
\ No newline at end of file
diff --git a/diags/common/Makefile b/diags/common/Makefile
index 1d19579..cf9801b 100644
--- a/diags/common/Makefile
+++ b/diags/common/Makefile
@@ -1,7 +1,5 @@
default: all
-BINARY = common_diags
-
TARGETS=$(BINARY)
INSTALL=install
PREFIX=$(DESTDIR)/usr
@@ -12,56 +10,27 @@
CC=$(CROSS_COMPILE)gcc
CXX=$(CROSS_COMPILE)g++
RM=rm -f
-CFLAGS = -Wall -Wimplicit -Wno-unknown-pragmas -W -std=c99 -D_GNU_SOURCE
+CFLAGS = -Wall -Werror -Wimplicit -Wno-unknown-pragmas -D_GNU_SOURCE
CFLAGS += $(EXTRA_CFLAGS)
LDFLAGS += $(EXTRA_LDFLAGS)
-# enable the platform we're supporting
-ifeq ($(BR2_PACKAGE_BCM_NEXUS),y)
- CFLAGS += -DBROADCOM
- NOSTUB=1
-endif
-ifeq ($(BR2_PACKAGE_MINDSPEED_DRIVERS),y)
- CFLAGS += -DMINDSPEED
- NOSTUB=1
-endif
-
-ifeq ($(BR2_TARGET_GOOGLE_PLATFORM),gfiberlt)
- CFLAGS += -DGFIBER_LT
- NOSTUB=1
-endif
-
-ifndef NOSTUB
- CFLAGS += -DSTUB
- LDFLAGS += -lm
-endif
-
CFLAGS += -g
IFLAGS += $(patsubst %,-I%,$(INC_DIRS))
-
-CFILES = $(wildcard *.c ../common/*.c)
+CFILES = $(wildcard *.c)
OFILES = $(patsubst %.c,%.o,$(CFILES))
-ifndef BRUNO_ARCH
-$(warning BRUNO_ARCH is undefined. Set it to arm or mips or i386)
-endif
-
all: $(OFILES)
install:
-
install-libs:
@:
test:
@:
-$(BINARY): $(OFILES)
- $(CC) $^ $(LDFLAGS) -o $@
-
%.o: %.c
$(CC) $(CFLAGS) $(IFLAGS) -c $^ -c
diff --git a/diags/spacecast/Makefile b/diags/spacecast/Makefile
index aba5353..24f7c7b 100644
--- a/diags/spacecast/Makefile
+++ b/diags/spacecast/Makefile
@@ -12,42 +12,15 @@
CC=$(CROSS_COMPILE)gcc
CXX=$(CROSS_COMPILE)g++
RM=rm -f
-CFLAGS = -Wall -Wimplicit -Wno-unknown-pragmas -W -std=c99 -D_GNU_SOURCE
+CFLAGS = -Wall -Werror -Wimplicit -Wno-unknown-pragmas -D_GNU_SOURCE -g
CFLAGS += $(EXTRA_CFLAGS)
LDFLAGS += $(EXTRA_LDFLAGS)
-# enable the platform we're supporting
-ifeq ($(BR2_PACKAGE_BCM_NEXUS),y)
- CFLAGS += -DBROADCOM
- NOSTUB=1
-endif
-ifeq ($(BR2_PACKAGE_MINDSPEED_DRIVERS),y)
- CFLAGS += -DMINDSPEED
- NOSTUB=1
-endif
-
-ifeq ($(BR2_TARGET_GOOGLE_PLATFORM),gfiberlt)
- CFLAGS += -DGFIBER_LT
- NOSTUB=1
-endif
-
-ifndef NOSTUB
- CFLAGS += -DSTUB
- LDFLAGS += -lm
-endif
-
-CFLAGS += -g
-
IFLAGS += $(patsubst %,-I%,$(INC_DIRS))
-
CFILES = $(wildcard *.c ../common/*.c)
OFILES = $(patsubst %.c,%.o,$(CFILES))
-ifndef BRUNO_ARCH
-$(warning BRUNO_ARCH is undefined. Set it to arm or mips or i386)
-endif
-
all: $(TARGETS)
install:
diff --git a/diags/spacecast/ge_test.c b/diags/spacecast/ge_test.c
index 8a4b0bf..4ec8c7c 100644
--- a/diags/spacecast/ge_test.c
+++ b/diags/spacecast/ge_test.c
@@ -971,7 +971,7 @@
/* This is for Marvell 88E1512 only */
int lan_lpbk(int argc, char *argv[]) {
- int reg, data;
+ int data;
bool loopback_on = false;
if (argc != 2) {
diff --git a/diags/windcharger/Makefile b/diags/windcharger/Makefile
index 748b6d4..e1f40ed 100644
--- a/diags/windcharger/Makefile
+++ b/diags/windcharger/Makefile
@@ -12,42 +12,15 @@
CC=$(CROSS_COMPILE)gcc
CXX=$(CROSS_COMPILE)g++
RM=rm -f
-CFLAGS = -Wall -Wimplicit -Wno-unknown-pragmas -W -std=c99 -D_GNU_SOURCE
+CFLAGS = -Wall -Werror -Wimplicit -Wno-unknown-pragmas -D_GNU_SOURC -g
CFLAGS += $(EXTRA_CFLAGS)
LDFLAGS += $(EXTRA_LDFLAGS)
-# enable the platform we're supporting
-ifeq ($(BR2_PACKAGE_BCM_NEXUS),y)
- CFLAGS += -DBROADCOM
- NOSTUB=1
-endif
-ifeq ($(BR2_PACKAGE_MINDSPEED_DRIVERS),y)
- CFLAGS += -DMINDSPEED
- NOSTUB=1
-endif
-
-ifeq ($(BR2_TARGET_GOOGLE_PLATFORM),gfiberlt)
- CFLAGS += -DGFIBER_LT
- NOSTUB=1
-endif
-
-ifndef NOSTUB
- CFLAGS += -DSTUB
- LDFLAGS += -lm
-endif
-
-CFLAGS += -g
-
IFLAGS += $(patsubst %,-I%,$(INC_DIRS))
-
CFILES = $(wildcard ../common/*.c *.c)
OFILES = $(patsubst %.c,%.o,$(CFILES))
-ifndef BRUNO_ARCH
-$(warning BRUNO_ARCH is undefined. Set it to arm or mips or i386)
-endif
-
all: $(TARGETS)
install:
diff --git a/ginstall/Makefile b/ginstall/Makefile
index 84278af..2d63246 100644
--- a/ginstall/Makefile
+++ b/ginstall/Makefile
@@ -9,7 +9,7 @@
install:
mkdir -p $(BINDIR)
cp ginstall.py $(BINDIR)
- ln -sf ginstall.py $(BINDIR)/ginstall
+ ln -sf ginstall.py $(BINDIR)/ginstall.real
install-libs:
@echo "No libs to install."
diff --git a/ginstall/ginstall.py b/ginstall/ginstall.py
index 8443209..c53f1af 100755
--- a/ginstall/ginstall.py
+++ b/ginstall/ginstall.py
@@ -50,7 +50,6 @@
# Error codes.
HNVRAM_ERR = 1
-GINSTALL_RUNNING_ERR = 2
# unit tests can override these with fake versions
BUFSIZE = 4 * 1024 # 64k causes b/14299411
@@ -59,14 +58,6 @@
NANDDUMP = ['nanddump']
SGDISK = 'sgdisk'
-# Lock prefix is used for process locking. The full file will be saved with
-# ".lock" appended to the end.
-LOCK_PREFIX = '/tmp/ginstall'
-
-# Status file for informing a potential second ginstall that an installation has
-# already run to completion.
-GINSTALL_COMPLETED_FILE = '/tmp/ginstall_complete'
-
F = {
'ETCPLATFORM': '/etc/platform',
'ETCVERSION': '/etc/version',
@@ -108,36 +99,6 @@
pass
-class PidLock(object):
- """A class meant to handle process mutual exclusion through a lock file.
-
- Usage: create the lock, then use in a `with' statement.
-
- ex:
- with PidLock(prefix):
- # Lock is now acquired.
- ... do atomic things ...
-
- # Lock is now released.
- ... do other things ...
- """
-
- def __init__(self, lock_path):
- self.lock_path = lock_path
-
- def __enter__(self):
- # Returns immediately if lockfile is already taken.
- cmd = ['lockfile-create', '--use-pid', '--retry', '0', self.lock_path]
- res = subprocess.call(cmd)
- if res != 0:
- raise LockException('Unable to acquire lock')
- return self
-
- def __exit__(self, *err):
- cmd = ['lockfile-remove', self.lock_path]
- subprocess.call(cmd)
-
-
class Fatal(Exception):
"""An exception that we print as just an error, with no backtrace."""
pass
@@ -962,35 +923,29 @@
if not (opt.drm or opt.tar or opt.partition):
o.fatal('Expected at least one of --partition, --tar, or --drm')
- try:
- with PidLock(LOCK_PREFIX):
- quiet = opt.quiet
+ quiet = opt.quiet
- if opt.basepath:
- # Standalone test harness can pass in a fake root path.
- AddBasePath(opt.basepath)
+ if opt.basepath:
+ # Standalone test harness can pass in a fake root path.
+ AddBasePath(opt.basepath)
- if opt.drm:
- WriteDrm(opt)
+ if opt.drm:
+ WriteDrm(opt)
- if opt.tar and not opt.partition:
- # default to the safe option if not given
- opt.partition = 'other'
+ if opt.tar and not opt.partition:
+ # default to the safe option if not given
+ opt.partition = 'other'
- partition = GetPartition(opt)
- if opt.tar:
- f = OpenPathOrUrl(opt.tar)
- InstallImage(f, partition, skiploader=opt.skiploader,
- skiploadersig=opt.skiploadersig)
+ partition = GetPartition(opt)
+ if opt.tar:
+ f = OpenPathOrUrl(opt.tar)
+ InstallImage(f, partition, skiploader=opt.skiploader,
+ skiploadersig=opt.skiploadersig)
- if partition is not None and SetBootPartition(partition) != 0:
- VerbosePrint('Unable to set boot partition\n')
- return HNVRAM_ERR
+ if partition is not None and SetBootPartition(partition) != 0:
+ VerbosePrint('Unable to set boot partition\n')
+ return HNVRAM_ERR
- open(GINSTALL_COMPLETED_FILE, 'w').close()
- except LockException:
- VerbosePrint('Another instance of ginstall is running\n')
- return GINSTALL_RUNNING_ERR
return 0
diff --git a/ginstall/ginstall_test.py b/ginstall/ginstall_test.py
index 9c6b945..928cf58 100755
--- a/ginstall/ginstall_test.py
+++ b/ginstall/ginstall_test.py
@@ -112,18 +112,6 @@
self.assertFalse(ginstall.IsIdentical(
'loader', loader, open('testdata/img/loader1.bin')))
- def testLockExceptions(self):
- lock_prefix = '/tmp/ginstall_test_lock'
- lock = ginstall.PidLock(lock_prefix)
- def LockFailure():
- with lock:
- with ginstall.PidLock(lock_prefix):
- pass
- self.assertRaises(ginstall.LockException, LockFailure)
- # Asserts no exceptions happen during normal usage.
- with lock:
- pass
-
def testIsMtdNand(self):
mtd = ginstall.F['MTD_PREFIX']
self.assertFalse(ginstall.IsMtdNand(mtd + '6'))
diff --git a/logupload/client/.gitignore b/logupload/client/.gitignore
index 7ba05e9..6f2ca86 100644
--- a/logupload/client/.gitignore
+++ b/logupload/client/.gitignore
@@ -1 +1,2 @@
upload-crash-log2
+upload-logs
diff --git a/logupload/client/Makefile b/logupload/client/Makefile
index 8b51206..f7a56d3 100644
--- a/logupload/client/Makefile
+++ b/logupload/client/Makefile
@@ -1,34 +1,51 @@
+default: all
+
CC:=$(CROSS_COMPILE)gcc
-CPP:=$(CROSS_COMPILE)g++
+CXX:=$(CROSS_COMPILE)g++
LD:=$(CROSS_COMPILE)ld
AR:=$(CROSS_COMPILE)ar
RANLIB:=$(CROSS_COMPILE)ranlib
STRIP:=$(CROSS_COMPILE)strip
USRBINDIR=$(DESTDIR)/usr/bin
-CFLAGS += -Wall -Werror $(EXTRACFLAGS)
-LDFLAGS += -lrt -lcurl -lz -lm $(EXTRALDFLAGS)
+CFLAGS+=-Wall -Werror $(EXTRACFLAGS)
+LDFLAGS+=$(EXTRALDFLAGS)
+LIBS=-lrt -lcurl -lz -lm
# Test Flags
-TEST_LDFLAGS=$(LDFLAGS) -lgtest -pthread
+TEST_LDFLAGS=$(LDFLAGS)
+TEST_LIBS=$(LIBS) -lgtest -pthread
-all: upload-crash-log2
-tests: kvextract_test
-SRCS = log_uploader.c kvextract.c upload.c utils.c
+OBJS = log_uploader.o kvextract.o upload.o utils.o
INCS = kvextract.h upload.h utils.h
-MAIN_SRC = log_uploader_main.c
+MAIN_OBJ = log_uploader_main.o
+TESTS = kvextract_test utils_test log_uploader_test
-upload-crash-log2: $(SRCS) $(INCS) $(MAIN_SRC)
- $(CC) $(CFLAGS) $(SRCS) $(MAIN_SRC) -o $@ $(LDFLAGS)
+all: upload-crash-log2 upload-logs
-kvextract_test: $(SRCS) $(INCS) kvextract_test.c
- $(CPP) $(CFLAGS) kvextract_test.c $(SRCS) -o $@ $(TEST_LDFLAGS)
+tests: all $(TESTS)
-utils_test: $(SRCS) $(INCS) utils_test.c
- $(CPP) $(CFLAGS) utils_test.c $(SRCS) -o $@ $(TEST_LDFLAGS)
+kvextract_test: kvextract_test.o
+utils_test: utils_test.o
+log_uploader_test: log_uploader_test.o
-log_uploader_test: $(SRCS) $(INCS) log_uploader_test.c
- $(CPP) $(CFLAGS) log_uploader_test.c $(SRCS) -o $@ $(TEST_LDFLAGS)
+# an alias the Debian package can use, since upload-crash-log2 is kind of
+# a weird name, present mainly for backward compatibility with the old
+# loguploader on GFiber CPE devices (for now).
+upload-logs: upload-crash-log2
+ ln -f $< $@
+
+%.o: %.c $(INCS)
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+%.o: %.cc $(INCS)
+ $(CXX) $(CFLAGS) -c -o $@ $<
+
+upload-crash-log2: $(OBJS) $(MAIN_OBJ)
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+%_test: %_test.o $(OBJS)
+ $(CXX) $(TEST_LDFLAGS) -o $@ $^ $(TEST_LIBS)
install:
mkdir -p $(USRBINDIR)
@@ -37,10 +54,14 @@
install-libs:
@echo "No libs to install."
-test: kvextract_test utils_test log_uploader_test
- ./kvextract_test
- ./utils_test
- ./log_uploader_test
+test: tests
+ set -e; for d in $(TESTS); do ./$$d; done
+ # Ensure proper handling of binary files
+ rm -f test.tmp
+ ./upload-crash-log2 --stdin=test --stdout <upload-crash-log2 >test.tmp
+ cmp upload-crash-log2 test.tmp
+ rm -f test.tmp
+ wvtest/wvtestrun ./prefix-logs.test
clean:
- rm -f upload-crash-log2 *.o
+ rm -f upload-crash-log2 upload-logs $(TESTS) *~ *.o
diff --git a/logupload/client/debian/.gitignore b/logupload/client/debian/.gitignore
new file mode 100644
index 0000000..e0137c3
--- /dev/null
+++ b/logupload/client/debian/.gitignore
@@ -0,0 +1,6 @@
+/files
+/changelog
+/*.debhelper
+/gfiber-loguploader.debhelper.log
+/gfiber-loguploader.substvars
+/gfiber-loguploader
diff --git a/logupload/client/debian/70-gfiber-loguploader.conf b/logupload/client/debian/70-gfiber-loguploader.conf
new file mode 100644
index 0000000..8c63b39
--- /dev/null
+++ b/logupload/client/debian/70-gfiber-loguploader.conf
@@ -0,0 +1,3 @@
+# rsyslog config for writing to gfiber-loguploader named pipe.
+
+*.* |/var/log/gfiber-loguploader/pipe
diff --git a/logupload/client/debian/README.Debian b/logupload/client/debian/README.Debian
new file mode 100644
index 0000000..2cf7e88
--- /dev/null
+++ b/logupload/client/debian/README.Debian
@@ -0,0 +1,5 @@
+GFiber loguploader
+------------------
+
+Find the source here:
+https://gfiber.googlesource.com/vendor/google/platform/+/master/logupload/client/
diff --git a/logupload/client/debian/clean b/logupload/client/debian/clean
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/logupload/client/debian/clean
diff --git a/logupload/client/debian/compat b/logupload/client/debian/compat
new file mode 100644
index 0000000..7f8f011
--- /dev/null
+++ b/logupload/client/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/logupload/client/debian/control b/logupload/client/debian/control
new file mode 100644
index 0000000..b7455d4
--- /dev/null
+++ b/logupload/client/debian/control
@@ -0,0 +1,14 @@
+Source: gfiber-loguploader
+Section: net
+Priority: extra
+Maintainer: Avery Pennarun <apenwarr@google.com>
+Build-Depends: debhelper (>= 7.0.50~)
+Standards-Version: 3.9.2
+Homepage: https://gfiber.googlesource.com/vendor/google/platform/+/master/logupload/client/
+Vcs-Git: https://gfiber.googlesource.com/vendor/google/platform
+Vcs-Browser: https://gfiber.googlesource.com/vendor/google/platform
+
+Package: gfiber-loguploader
+Architecture: any
+Depends: rsyslog (>= 5.8), gfiber-device-cert (>= 0.0)
+Description: Tool for uploading syslogs to GFiber log servers.
diff --git a/logupload/client/debian/copyright b/logupload/client/debian/copyright
new file mode 100644
index 0000000..d2bdd00
--- /dev/null
+++ b/logupload/client/debian/copyright
@@ -0,0 +1,23 @@
+Format: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=173
+Upstream-Name: gfiber-loguploader
+Upstream-Contact: Avery Pennarun <apenwarr@google.com>
+Source: https://gfiber.googlesource.com/vendor/google/platform/+/master/logupload/client/
+
+Files: *
+Copyright: © 2015 Jeffrey Kardatzke <jkardatzke@google.com>
+License: Apache
+ *
+ * Copyright 2015 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
diff --git a/logupload/client/debian/dirs b/logupload/client/debian/dirs
new file mode 100644
index 0000000..7f3dd46
--- /dev/null
+++ b/logupload/client/debian/dirs
@@ -0,0 +1 @@
+/var/log/gfiber-loguploader
diff --git a/logupload/client/debian/gen-changelog b/logupload/client/debian/gen-changelog
new file mode 100755
index 0000000..c5c830d
--- /dev/null
+++ b/logupload/client/debian/gen-changelog
@@ -0,0 +1,17 @@
+#!/bin/sh
+read junk pkgname <debian/control
+git log --pretty='format:'"$pkgname"' (SHA:%H) unstable; urgency=low
+
+ * %s
+
+ -- %aN <%aE> %aD
+' . |
+python -Sc '
+import os, re, subprocess, sys
+
+def Describe(g):
+ s = subprocess.check_output(["git", "describe", "--", g.group(1)]).strip()
+ return re.sub(r"^\D*", "", s)
+
+print re.sub(r"SHA:([0-9a-f]+)", Describe, sys.stdin.read())
+'
diff --git a/logupload/client/debian/init b/logupload/client/debian/init
new file mode 100755
index 0000000..593270e
--- /dev/null
+++ b/logupload/client/debian/init
@@ -0,0 +1,68 @@
+#!/bin/sh
+#
+### BEGIN INIT INFO
+# Provides: gfiber-loguploader
+# Required-Start: $syslog $remote_fs
+# Required-Stop: $syslog $remote_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: GFiber loguploader client
+### END INIT INFO
+
+[ -x /usr/bin/upload-logs ] || exit 0
+. /lib/lsb/init-functions
+
+atomic_stdin() {
+ rm -f "$1" "$1.new"
+ cat >"$1.new"
+ mv "$1.new" "$1"
+}
+
+case "$1" in
+ start)
+ log_daemon_msg "Starting GFiber log uploader" "upload-logs"
+ if ! [ -e /etc/ssl/certs/device.pem -a \
+ -e /etc/ssl/private/device.key ]; then
+ echo >&2
+ echo "Cert missing: /etc/ssl/certs/device.pem and /etc/ssl/private/device.key." >&2
+ echo >&2
+ log_end_msg 1
+ exit 1
+ fi
+ rm -f /tmp/ssl
+ ln -sf /etc/ssl/. /tmp/ssl
+ uname -r | sed 's/ /-/g' | atomic_stdin /etc/version
+ uname | atomic_stdin /tmp/platform
+ # Our hostnames are something like hostname.cluster.whatever.com.
+ # We want the hostname.cluster part to be part of the certname, but
+ # sadly the name field in our certs isn't super happy about that, so
+ # let's use _ instead of dot, where relevant.
+ hostname -f |
+ sed -e 's/\.googlefiber\.net$//' \
+ -e 's/\.nyc\.corp\.google\.com$//' \
+ -e 's/\./_/g' |
+ atomic_stdin /tmp/serial
+ cd /
+ upload-logs-loop </dev/null &
+ log_end_msg 0
+ exit 0
+ ;;
+ stop)
+ log_daemon_msg "Stopping GFiber log uploader" "upload-logs"
+ pkill upload-logs-loop
+ pkill upload-logs
+ pkill -f prefix-logs
+ log_end_msg 0
+ exit 0
+ ;;
+ reload|force-reload|restart)
+ $0 stop; $0 start
+ ;;
+ status)
+ pgrep upload-logs >/dev/null
+ exit $?
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|restart|reload|force-reload|status}"
+ exit 1
+esac
diff --git a/logupload/client/debian/install b/logupload/client/debian/install
new file mode 100644
index 0000000..2f83d49
--- /dev/null
+++ b/logupload/client/debian/install
@@ -0,0 +1,4 @@
+upload-logs /usr/bin
+prefix-logs /usr/bin
+debian/upload-logs-loop /usr/bin
+debian/70-gfiber-loguploader.conf /etc/rsyslog.d
diff --git a/logupload/client/debian/postinst b/logupload/client/debian/postinst
new file mode 100644
index 0000000..bca62bc
--- /dev/null
+++ b/logupload/client/debian/postinst
@@ -0,0 +1,9 @@
+#DEBHELPER#
+
+umask 007
+PNAME=/var/log/gfiber-loguploader/pipe
+if ! [ -p "$PNAME" ]; then
+ rm -f "$PNAME"
+ mkfifo "$PNAME"
+fi
+service rsyslog restart
diff --git a/logupload/client/debian/rules b/logupload/client/debian/rules
new file mode 100755
index 0000000..02843c4
--- /dev/null
+++ b/logupload/client/debian/rules
@@ -0,0 +1,13 @@
+#!/usr/bin/make -f
+
+override_dh_auto_test:
+override_dh_auto_install:
+
+%:
+ dh $@
+
+binary: debian/changelog
+
+.PHONY: debian/changelog
+debian/changelog:
+ debian/gen-changelog >$@
diff --git a/logupload/client/debian/upload-logs-loop b/logupload/client/debian/upload-logs-loop
new file mode 100755
index 0000000..2f657f2
--- /dev/null
+++ b/logupload/client/debian/upload-logs-loop
@@ -0,0 +1,7 @@
+#!/bin/sh
+while :; do
+ # TODO(apenwarr): register a new logtype and change the --logtype here.
+ prefix-logs </var/log/gfiber-loguploader/pipe |
+ upload-logs --logtype server --freq 60 --stdin dmesg
+ sleep 1
+done 2>&1 | logger -t upload-logs-loop
diff --git a/logupload/client/kvextract.c b/logupload/client/kvextract.c
index 9d0c426..bcfd84a 100644
--- a/logupload/client/kvextract.c
+++ b/logupload/client/kvextract.c
@@ -34,6 +34,7 @@
len = read_file_as_string(filepath, (*pair)->value, sizeof((*pair)->value));
if (len < 0) {
free(*pair);
+ *pair = NULL;
return KV_NOTHING;
}
rstrip((*pair)->value);
@@ -90,7 +91,7 @@
sizeof(struct sockaddr_in6), pair_tail->value,
sizeof(pair_tail->value), NULL, 0, NI_NUMERICHOST);
if (rv != 0) {
- fprintf(stderr, "getnameinfo() failed: %s\n", gai_strerror(rv));
+ fprintf(stderr, "getnameinfo(): %s\n", gai_strerror(rv));
free_kv_pairs(pair_head);
return NULL;
}
diff --git a/logupload/client/kvextract.h b/logupload/client/kvextract.h
index a6df5af..3c5bb56 100644
--- a/logupload/client/kvextract.h
+++ b/logupload/client/kvextract.h
@@ -1,6 +1,10 @@
#ifndef _H_LOGUPLOAD_CLIENT_KVEXTRACT_H_
#define _H_LOGUPLOAD_CLIENT_KVEXTRACT_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <sys/socket.h>
#include <ifaddrs.h>
@@ -44,4 +48,8 @@
struct kvpair* extract_kv_pairs(struct kvextractparams* params);
void free_kv_pairs(struct kvpair* pairs);
+#ifdef __cplusplus
+}
+#endif
+
#endif // _H_LOGUPLOAD_CLIENT_KVEXTRACT_H_
diff --git a/logupload/client/kvextract_test.c b/logupload/client/kvextract_test.cc
similarity index 100%
rename from logupload/client/kvextract_test.c
rename to logupload/client/kvextract_test.cc
diff --git a/logupload/client/log_uploader.c b/logupload/client/log_uploader.c
index 983bfb8..5b63174 100644
--- a/logupload/client/log_uploader.c
+++ b/logupload/client/log_uploader.c
@@ -17,8 +17,7 @@
struct tm timeinfo;
struct timespec curr_time;
if (read_file_as_string(version_path, version, sizeof(version)) < 0) {
- fprintf(stderr, "failed reading %s\n", version_path);
- return -1;
+ strcpy(version, "unknown-version");
}
rstrip(version);
memset(&timeinfo, 0, sizeof(timeinfo));
@@ -30,7 +29,12 @@
version, (int)curr_time.tv_sec, (int)(curr_time.tv_nsec/1000000L),
timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min,
timeinfo.tm_sec, path_exists(ntp_sync_path));
- return write_to_file(output_path, buf) < 0;
+ int rv = write_to_file(output_path, buf);
+ if (rv < 0) {
+ perror(output_path);
+ return -1;
+ }
+ return 0;
}
char* parse_and_consume_log_data(struct log_parse_params* params) {
@@ -69,11 +73,11 @@
if (!wrote_start_marker) {
// Write out the start marker.
if (write_to_file(params->dev_kmsg_path, LOG_MARKER_START_LINE) < 0) {
- fprintf(stderr, "failed to write out start marker\n");
+ perror("start marker");
return NULL;
}
if (logmark_once(params->dev_kmsg_path, params->version_path,
- params->ntp_synced_path)) {
+ params->ntp_synced_path) < 0) {
fprintf(stderr, "failed to execute logmark-once properly\n");
return NULL;
}
@@ -99,7 +103,7 @@
perror("kernel memory possibly corrupted, devkmsg_read");
continue;
} else {
- fprintf(stderr, "failed reading from /dev/kmsg: %s\n", strerror(errno));
+ perror("/dev/kmsg");
return NULL;
}
}
diff --git a/logupload/client/log_uploader.h b/logupload/client/log_uploader.h
index 75fcac5..bb6011c 100644
--- a/logupload/client/log_uploader.h
+++ b/logupload/client/log_uploader.h
@@ -1,6 +1,10 @@
#ifndef _H_LOGUPLOAD_CLIENT_LOG_UPLOADER_H_
#define _H_LOGUPLOAD_CLIENT_LOG_UPLOADER_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "kvextract.h"
#define LOG_MARKER_START "*LOG_UPLOAD_START*"
@@ -14,6 +18,7 @@
int upload_all;
int use_stdout;
int use_stdin;
+ int freq;
char upload_target[1024];
};
@@ -44,4 +49,8 @@
int logmark_once(const char* output_path, const char* version_path,
const char* ntp_sync_path);
+#ifdef __cplusplus
+}
+#endif
+
#endif // _H_LOGUPLOAD_CLIENT_LOG_UPLOADER_H_
diff --git a/logupload/client/log_uploader_main.c b/logupload/client/log_uploader_main.c
index 1dc925a..8d3afc4 100644
--- a/logupload/client/log_uploader_main.c
+++ b/logupload/client/log_uploader_main.c
@@ -26,12 +26,13 @@
#define COUNTER_MARKER_FILE "/tmp/loguploadcounter"
#define LOGS_UPLOADED_MARKER_FILE "/tmp/logs-uploaded"
#define DEFAULT_UPLOAD_TARGET "dmesg"
-#define MAX_LOG_SIZE 8*1024*1024 // 8 MB
+#define MAX_LOG_SIZE 8*1024*1024 // max bytes to upload in one run
+#define LOG_BUF_EXTRA 65536 // extra bytes for extra compression slop
#define DEV_KMSG_PATH "/dev/kmsg"
#define NTP_SYNCED_PATH "/tmp/ntp.synced"
#define VERSION_PATH "/etc/version"
-#define SERIAL_PATH "/etc/serial"
-#define PLATFORM_PATH "/etc/platform"
+#define SERIAL_PATH "/tmp/serial"
+#define PLATFORM_PATH "/tmp/platform"
// 8192 is the size of the buffer used in printk.c to store a line read from
// /dev/kmsg before copying it into our userspace buffer
#define LOG_LINE_BUFFER_SIZE 8192
@@ -45,6 +46,12 @@
static int num_interfaces = sizeof(interfaces_to_check) /
sizeof(interfaces_to_check[0]);
+volatile static int interrupted = 0;
+
+static void got_alarm(int sig) {
+ interrupted = 1;
+}
+
// To allow overriding for testing.
int getnameinfo_resolver(const struct sockaddr* sa, socklen_t salen, char* host,
size_t hostlen, char* serv, size_t servlen, int flags) {
@@ -81,13 +88,15 @@
}
static void usage(const char* progname) {
- fprintf(stderr, "Usage for: %s\n", progname);
- fprintf(stderr, " --server URL Server URL (default: " DEFAULT_SERVER ")\n");
- fprintf(stderr, " --all Upload entire logs, not just new data\n");
- fprintf(stderr, " --stdout Print to stdout instead of uploading\n");
- fprintf(stderr, " --stdin name Get data from stdin rather than /dev/kmsg and"
- " upload to 'name' facility rather than 'dmesg', also disables "
- "looping\n");
+ fprintf(stderr, "\nUsage: %s [options...]\n", progname);
+ fprintf(stderr, " --server URL Server URL [" DEFAULT_SERVER "]\n");
+ fprintf(stderr, " --all Upload entire logs, not just new data\n");
+ fprintf(stderr, " --logtype TYPE Tell server which log category this is\n");
+ fprintf(stderr, " --freq SECS Upload logs every SECS seconds [60]\n");
+ fprintf(stderr, " --stdout Print to stdout instead of uploading\n");
+ fprintf(stderr,
+ " --stdin NAME Get data from stdin, not /dev/kmsg, and\n"
+ " name uploaded file NAME rather than 'dmesg'\n");
exit(EXIT_SUCCESS);
}
@@ -97,9 +106,10 @@
static struct option long_options[] = {
{ "server", required_argument, 0, 's' },
{ "all", no_argument, 0, 'a' },
+ { "logtype", required_argument, 0, 'l' },
+ { "freq", required_argument, 0, 'f' },
{ "stdout", no_argument, 0, 'd' },
{ "stdin", required_argument, 0, 'i' },
- { "logtype", required_argument, 0 , 'l' },
{ 0, 0, 0, 0}
};
@@ -126,8 +136,15 @@
case 'l':
snprintf(config->logtype, sizeof(config->logtype), "%s", optarg);
break;
- default:
- return -1;
+ case 'f':
+ config->freq = atoi(optarg);
+ if (config->freq < 0) {
+ fprintf(stderr, "fatal: freq must be >= 0\n");
+ return -1;
+ }
+ break;
+ default:
+ return -1;
}
}
if (optind < argc)
@@ -135,6 +152,14 @@
return 0;
}
+static int pick_delay(struct upload_config* config) {
+ // Randomize the sleep time to be near the specified amount, +/- 1/12th.
+ // (1/12th is weird, but it means +/- 5 for 60 seconds, which is nice).
+ int variance = config->freq / 12;
+ return ((config->freq - variance) +
+ (random() % (variance * 2 + 1)));
+}
+
int main(int argc, char* const argv[]) {
setvbuf(stdout, (char *) NULL, _IOLBF, 0);
@@ -148,18 +173,22 @@
if (argc > 1) {
if (parse_args(&config, argc, argv) < 0) {
usage(argv[0]);
- return 1;
+ return 99;
}
}
- // Initiliaze the random number generator
+ struct sigaction sa = {};
+ sa.sa_handler = got_alarm;
+ sigaction(SIGALRM, &sa, NULL);
+
+ // Initialize the random number generator
srandom(getpid() ^ time(NULL));
- // Allocate this once and re-use it very time
- char* log_buffer = (char*) malloc(MAX_LOG_SIZE);
+ // Allocate this once and re-use it every time
+ char* log_buffer = (char*) malloc(MAX_LOG_SIZE + LOG_BUF_EXTRA);
if (!log_buffer) {
fprintf(stderr, "Failed to allocate log_buffer!\n");
- return 1;
+ return 98;
}
int kmsg_read_fd = 0;
@@ -168,8 +197,7 @@
// Use nonblocking mode so we know when we're consumed all the recent data.
kmsg_read_fd = open("/dev/kmsg", O_RDONLY | O_NONBLOCK);
if (kmsg_read_fd < 0) {
- fprintf(stderr, "failed to open /dev/kmsg for reading: %s\n",
- strerror(errno));
+ perror("/dev/kmsg");
return 1;
}
}
@@ -202,15 +230,20 @@
// Read in all the data from stdin
int num_read;
total_read = num_read = 0;
+ interrupted = 0;
+ alarm(pick_delay(&config));
while ((num_read = read(STDIN_FILENO, log_buffer + total_read,
- MAX_LOG_SIZE - total_read)) > 0) {
+ MAX_LOG_SIZE - total_read)) > 0 && !interrupted) {
total_read += num_read;
}
- if (num_read < 0) {
- fprintf(stderr, "failed reading from stdin: %s\n", strerror(errno));
- return 1;
+ if (num_read < 0 && errno != EINTR) {
+ perror("stdin");
+ return 2;
}
- log_buffer[total_read] = '\0';
+ if (num_read == 0 && total_read == 0) {
+ fprintf(stderr, "stdin: end of input. done.\n");
+ return 0;
+ }
log_data_to_use = log_buffer;
} else {
// Remove the marker file to indicate we've completed the upload process.
@@ -223,14 +256,14 @@
logmark_once(DEV_KMSG_PATH, VERSION_PATH,
NTP_SYNCED_PATH)) {
fprintf(stderr, "failed to execute logmark-once properly\n");
- return 1;
+ return 3;
}
parse_params.total_read = MAX_LOG_SIZE;
log_data_to_use = parse_and_consume_log_data(&parse_params);
if (!log_data_to_use) {
fprintf(stderr, "failed with logs parsing, abort!\n");
- return 1;
+ return 4;
}
total_read = parse_params.total_read;
}
@@ -238,14 +271,15 @@
// Now we've read all of the log data into our buffer, proceed
// with uploading or outputting it.
+ fprintf(stderr, "uploading %lu bytes of logs.\n", total_read);
if (config.use_stdout) {
- // Just print the whole thing to stdout
- printf("%s", log_data_to_use);
+ // Just print the whole thing to stdout. Note: might be binary.
+ fwrite(log_data_to_use, total_read, 1, stdout);
} else {
struct ifaddrs* ifaddr;
if (getifaddrs(&ifaddr)) {
- fprintf(stderr, "failed calling getifaddrs: %s\n", strerror(errno));
- return 1;
+ perror("getifaddrs");
+ return 5;
}
struct kvextractparams kvparams;
@@ -262,28 +296,30 @@
freeifaddrs(ifaddr);
if (!kvpairs) {
fprintf(stderr, "failure extracting kv pairs, abort\n");
- return 1;
+ return 6;
}
// Adjust this if we moved the pointer.
- unsigned long compressed_size = MAX_LOG_SIZE -
+ unsigned long compressed_size = MAX_LOG_SIZE + LOG_BUF_EXTRA -
(log_data_to_use - log_buffer);
int comp_result = deflate_inplace(&zstrm, (unsigned char*)log_data_to_use,
total_read, &compressed_size);
if (comp_result != Z_OK) {
- return 1;
+ fprintf(stderr, "fatal: deflate_inplace failed\n");
+ return 7;
}
int upload_res = upload_file(config.server, config.upload_target,
log_data_to_use, compressed_size, kvpairs);
free_kv_pairs(kvpairs);
if (upload_res) {
- return 1;
+ fprintf(stderr, "upload_file failed\n");
+ return 8;
}
if (write_file_as_uint64(COUNTER_MARKER_FILE,
parse_params.last_log_counter)) {
fprintf(stderr, "unable to write out last log counter\n");
- return 1;
+ return 9;
}
// Write the marker file to indicate we finished the upload.
int marker_fd = open(LOGS_UPLOADED_MARKER_FILE, O_CREAT | O_WRONLY,
@@ -292,18 +328,19 @@
close(marker_fd);
}
- if (write_to_file(DEV_KMSG_PATH, LOG_MARKER_END_LINE) < 0) {
- fprintf(stderr, "failed to write out end marker\n");
- return 1;
+ if (!config.use_stdin) {
+ if (write_to_file(DEV_KMSG_PATH, LOG_MARKER_END_LINE) < 0) {
+ perror("end marker");
+ return 10;
+ }
}
- if (!config.use_stdin) {
- // Randomize the sleep time between 55 and 65 seconds which matches
- // what is done in the log-delay script.
- int sleep_dur = 55 + (random() % 11);
- sleep(sleep_dur);
- } else
+ if (!config.freq) {
break;
+ } else if (!config.use_stdin) {
+ // if using stdin, we want to read incrementally instead.
+ sleep(pick_delay(&config));
+ }
}
free(log_buffer);
return 0;
diff --git a/logupload/client/log_uploader_test.c b/logupload/client/log_uploader_test.cc
similarity index 100%
rename from logupload/client/log_uploader_test.c
rename to logupload/client/log_uploader_test.cc
diff --git a/logupload/client/prefix-logs b/logupload/client/prefix-logs
new file mode 100755
index 0000000..5d7acd0
--- /dev/null
+++ b/logupload/client/prefix-logs
@@ -0,0 +1,42 @@
+#!/usr/bin/python -S
+"""Fix prefixes in rsyslog lines to make them look like /dev/kmsg."""
+import os
+import sys
+import time
+
+uptimef = open('/proc/uptime')
+versionfile = os.getenv('VERSIONFILE', '/etc/version')
+version = open(versionfile).read().strip().replace(' ', '-')
+
+
+def Log(service, msg):
+ uptimef.seek(0)
+ uptime = float(uptimef.read().split(' ', 1)[0])
+ sys.stdout.write('<7>[%13.6f] %s: %s' % (uptime, service, msg))
+
+
+def main():
+ last_mark = 0
+ while True:
+ line = sys.stdin.readline()
+ if not line: break
+ # sigh, different rsyslog installs log the date in a different format.
+ # for robustness, parse backwards from the colon.
+ # Input format:
+ # this is a date hostname service[pid]: msg\n
+ pre, msg = line.split(': ', 1)
+ servicepid = pre.split(' ')[-1]
+ service = servicepid.split('[', 1)[0]
+ now = time.time()
+ if now - last_mark >= 30:
+ Log('T', '%s %d %s ntp=1\n' % (
+ version,
+ time.time(),
+ time.strftime('%m/%d %H:%M:%S', time.localtime())))
+ last_mark = now
+ Log(service, msg)
+ sys.stdout.flush()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/logupload/client/prefix-logs.test b/logupload/client/prefix-logs.test
new file mode 100755
index 0000000..983edc8
--- /dev/null
+++ b/logupload/client/prefix-logs.test
@@ -0,0 +1,41 @@
+#!/bin/sh
+. ./wvtest/wvtest.sh
+
+export VERSIONFILE='./testdata/version'
+WVSTART "prefix-logs"
+
+contains() {
+ [ "$1" != "${1%$2*}" ]
+}
+
+WVPASS contains foible ib
+WVPASS contains 'big deal' ' '
+WVFAIL contains foible ' '
+
+echo "time stamp crap silly whatever hostname foo: blue message ☺
+2015-09-30T22:37:34.207817-04:00 whatever.xxx.corp.google.com CRON[1734]: pam_unix(cron:session): session closed for user root
+Sep 30 19:42:10 blob102 apenwarr: hello world
+" |
+./prefix-logs | {
+ # prefix-logs always prepends an initial T: line as well as printing
+ # additional ones on a schedule. Test the initial one.
+ read ts fac version timeval date time ntp junk
+ WVPASSEQ "$fac" "T:"
+ WVFAIL contains "$version" ' '
+ WVPASS [ "$timeval" -gt 0 ]
+ WVPASSEQ "$ntp" "ntp=1"
+ WVPASSEQ "$junk" ""
+
+ # our actual log messages from above.
+ read ts fac msg
+ WVPASSEQ "$fac" "foo:"
+ WVPASSEQ "$msg" "blue message ☺"
+
+ read ts fac msg
+ WVPASSEQ "$fac" "CRON:"
+ WVPASSEQ "$msg" "pam_unix(cron:session): session closed for user root"
+
+ read ts fac msg
+ WVPASSEQ "$fac" "apenwarr:"
+ WVPASSEQ "$msg" "hello world"
+}
diff --git a/logupload/client/testdata/version b/logupload/client/testdata/version
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/logupload/client/testdata/version
@@ -0,0 +1 @@
+foo
diff --git a/logupload/client/upload.c b/logupload/client/upload.c
index e629060..c72d640 100644
--- a/logupload/client/upload.c
+++ b/logupload/client/upload.c
@@ -9,8 +9,8 @@
#include "kvextract.h"
#include "utils.h"
-#define DEVICE_KEY_PATH "/etc/ssl/private/device.key"
-#define DEVICE_CERT_PATH "/etc/ssl/certs/device.pem"
+#define DEVICE_KEY_PATH "/tmp/ssl/private/device.key"
+#define DEVICE_CERT_PATH "/tmp/ssl/certs/device.pem"
#define FORM_DATA_SPLITTER_PREFIX "foo-splitter-"
diff --git a/logupload/client/upload.h b/logupload/client/upload.h
index dbbc89a..5e9052d 100644
--- a/logupload/client/upload.h
+++ b/logupload/client/upload.h
@@ -1,9 +1,17 @@
#ifndef _H_LOGUPLOAD_CLIENT_UPLOAD_H_
#define _H_LOGUPLOAD_CLIENT_UPLOAD_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include "kvextract.h"
int upload_file(const char* server_url, const char* target_name, char* data,
ssize_t len, struct kvpair* kvpairs);
+#ifdef __cplusplus
+}
+#endif
+
#endif // _H_LOGUPLOAD_CLIENT_UPLOAD_H_
diff --git a/logupload/client/utils.c b/logupload/client/utils.c
index f508960..6ce3e6b 100644
--- a/logupload/client/utils.c
+++ b/logupload/client/utils.c
@@ -10,15 +10,23 @@
#include "utils.h"
ssize_t read_file_as_string(const char* file_path, char* data, int length) {
- if (!file_path || !data)
+ if (!file_path || !data) {
+ errno = EINVAL;
return -1;
+ }
int fd = open(file_path, O_RDONLY);
- if (fd < 0)
+ if (fd < 0) {
+ perror(file_path);
return -1;
+ }
ssize_t num_read = read(fd, data, length - 1);
+ if (num_read < 0) {
+ perror(file_path);
+ }
close(fd);
- if (num_read < 0)
+ if (num_read < 0) {
return -1;
+ }
data[num_read] = '\0';
return num_read;
}
@@ -40,9 +48,14 @@
char buf[64];
ssize_t num_read;
int fd = open(file_path, O_RDONLY);
- if (fd < 0)
+ if (fd < 0) {
+ perror(file_path);
return 0;
+ }
num_read = read(fd, buf, sizeof(buf) -1);
+ if (num_read < 0) {
+ perror(file_path);
+ }
close(fd);
if (num_read > 0) {
buf[num_read] = '\0';
@@ -54,7 +67,7 @@
int write_file_as_uint64(const char* file_path, uint64_t counter) {
int fd = open(file_path, O_WRONLY | O_CREAT, RW_FILE_PERMISSIONS);
if (fd < 0) {
- fprintf(stderr, "could not open file %s: %s\n", file_path, strerror(errno));
+ perror(file_path);
return -1;
}
char data[64];
@@ -62,8 +75,7 @@
ssize_t num_written = write(fd, data, len);
close(fd);
if (num_written < len) {
- fprintf(stderr, "failed writing to file %s: %s\n", file_path,
- strerror(errno));
+ perror(file_path);
return -1;
}
return 0;
@@ -72,15 +84,12 @@
ssize_t write_to_file(const char* file_path, const char* data) {
int fd = open(file_path, O_WRONLY | O_CREAT | O_APPEND, RW_FILE_PERMISSIONS);
if (fd < 0) {
- fprintf(stderr, "could not open %s for writing: %s\n", file_path,
- strerror(errno));
return -1;
}
ssize_t len = strlen(data);
ssize_t num_written = write(fd, data, len);
close(fd);
if (num_written < len) {
- fprintf(stderr, "failed writing to %s: %s\n", file_path, strerror(errno));
return -1;
}
return num_written;
@@ -122,7 +131,7 @@
int deflate_inplace(z_stream *strm, unsigned char* buf,
unsigned long len, unsigned long *out_len) {
- int rv, used_out, used_in;
+ int rv;
unsigned char temp[1024]; // big enough to hold the header which is 11 bytes,
// plus more so we can eat into our data quicker
@@ -140,22 +149,15 @@
strm->avail_out = sizeof(temp);
// Do the first compression step
- rv = deflate(strm, Z_FINISH);
+ rv = deflate(strm, Z_NO_FLUSH);
if (rv == Z_STREAM_ERROR)
return rv;
- used_out = strm->next_out - temp;
- used_in = len - strm->avail_in;
- if (used_out > used_in) {
- // Our output data is larger than the input data consumed, sad panda :(
- return Z_BUF_ERROR;
- }
+ int temp_used = strm->next_out - temp;
- // Copy the data back to our buffer and use that from now on.
- memcpy(buf, temp, used_out);
- strm->next_out = buf + used_out;
+ strm->next_out = buf;
while (rv == Z_OK) {
// Update how much room we have in the output buffer, there may be a point
- // where its consumed all the input data and we just need to provide more
+ // where it's consumed all the input data and we just need to provide more
// output data as well.
if (strm->avail_in) {
strm->avail_out = strm->next_in - strm->next_out;
@@ -168,7 +170,13 @@
}
if (rv == Z_STREAM_END) {
// Successfully did the compression.
- *out_len = strm->next_out - buf;
+ if (strm->avail_out < temp_used) {
+ fprintf(stderr, "zlib problem: out is larger than in!\n");
+ return Z_BUF_ERROR;
+ }
+ memmove(buf + temp_used, buf, strm->next_out - buf);
+ memcpy(buf, temp, temp_used);
+ *out_len = strm->next_out - buf + temp_used;
return Z_OK;
}
diff --git a/logupload/client/utils.h b/logupload/client/utils.h
index 8609cce..6901634 100644
--- a/logupload/client/utils.h
+++ b/logupload/client/utils.h
@@ -1,6 +1,10 @@
#ifndef _H_LOGUPLOAD_CLIENT_UTILS_H_
#define _H_LOGUPLOAD_CLIENT_UTILS_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <fcntl.h>
#include <inttypes.h>
#include <sys/stat.h>
@@ -50,4 +54,9 @@
// called.
int deflate_inplace(z_stream *strm, unsigned char* buf,
unsigned long len, unsigned long *out_len);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif // _H_LOGUPLOAD_CLIENT_UTILS_H_
diff --git a/logupload/client/utils_test.c b/logupload/client/utils_test.cc
similarity index 70%
rename from logupload/client/utils_test.c
rename to logupload/client/utils_test.cc
index a639c7a..fbcea7f 100644
--- a/logupload/client/utils_test.c
+++ b/logupload/client/utils_test.cc
@@ -107,25 +107,55 @@
EXPECT_EQ(-1, parse_line_data(buf4, &data));
}
-TEST(Utils, deflate_in_place_test) {
- // We only test the success case because the failure cases shouldn't occur or
- // require incompressible data which we will never encounter in ASCII logs.
+
+#define RANDBUF 16384
+
+static void zlib_test(int modulus, unsigned long datalen, unsigned long maxlen,
+ int expect_ok) {
z_stream zstrm;
memset(&zstrm, 0, sizeof(zstrm));
- unsigned char random_data[16384];
- // Use only 7 bits of data so its closer to ASCII chars and will compress.
+ unsigned char random_data[RANDBUF];
for (unsigned int i = 0; i < sizeof(random_data); i++) {
- random_data[i] = random() % 128;
+ random_data[i] = random() % modulus;
}
- unsigned char backup_data[16384];
+ unsigned char backup_data[RANDBUF];
memcpy(backup_data, random_data, sizeof(random_data));
- unsigned long comp_size = sizeof(random_data);
- EXPECT_EQ(Z_OK, deflate_inplace(&zstrm, random_data, sizeof(random_data),
- &comp_size));
- unsigned char decompressed[16384];
- unsigned long full_size = sizeof(decompressed);
- EXPECT_EQ(Z_OK, uncompress(decompressed, &full_size, random_data,
- comp_size));
- EXPECT_EQ(full_size, sizeof(random_data));
- EXPECT_EQ(0, memcmp(decompressed, backup_data, sizeof(backup_data)));
+ unsigned long comp_size = maxlen;
+ int rv = deflate_inplace(&zstrm, random_data, datalen, &comp_size);
+ if (expect_ok) {
+ EXPECT_EQ(Z_OK, rv);
+ unsigned char decompressed[RANDBUF];
+ unsigned long full_size = sizeof(decompressed);
+ EXPECT_EQ(Z_OK, uncompress(decompressed, &full_size, random_data,
+ comp_size));
+ EXPECT_EQ(full_size, datalen);
+ EXPECT_EQ(0, memcmp(decompressed, backup_data, datalen));
+ } else {
+ EXPECT_NE(Z_OK, rv);
+ }
+}
+
+TEST(Utils, deflate_in_place1_test) {
+ // 7-bit compressible data
+ zlib_test(128, RANDBUF, RANDBUF, 1);
+}
+
+TEST(Utils, deflate_in_place2_test) {
+ // 8-bit uncompressible data
+ zlib_test(256, RANDBUF, RANDBUF, 0);
+}
+
+TEST(Utils, deflate_in_place3_test) {
+ // 8-bit, but room for *only* 11-byte zlib header.
+ // zlib should choose to "store" the data directly (with header) rather
+ // than ever making it larger, so this should always fit.
+ zlib_test(256, RANDBUF-11, RANDBUF, 1);
+}
+
+TEST(Utils, deflate_in_place4_test) {
+ zlib_test(256, 0, RANDBUF, 1);
+}
+
+TEST(Utils, deflate_in_place5_test) {
+ zlib_test(256, 1, RANDBUF, 1);
}
diff --git a/logupload/client/wvtest b/logupload/client/wvtest
new file mode 120000
index 0000000..f86b784
--- /dev/null
+++ b/logupload/client/wvtest
@@ -0,0 +1 @@
+../../cmds/wvtest
\ No newline at end of file
diff --git a/signing/repack.py b/signing/repack.py
index 879f61b..4e06fc1 100755
--- a/signing/repack.py
+++ b/signing/repack.py
@@ -4,7 +4,19 @@
"""Repackage image for signing check.
The image is packaged as follows
-Signing will add 8 bytes header (header size and signature offset).
+Signing will add 16 bytes header (header size and signature offset) plus
+8 bytes of padding.
+
+There are two cases:
+ if signature_offset == FAKE_SIGN_OFFSET
+ header_size contains the length of the file after the 16 byte header
+ (or file_size = 16 + header_size)
+
+ if signature_offset != FAKE_SIGN_OFFSET
+ header_size = signature_offset - 16 (not needed/used)
+ signature_offset = filesize - 256 - 16 (means the signature is 256 bytes)
+
+
The info is free format. Now it is only a string to hold verity table.
|-------------------| <=== Byte 0
| header size | (integer)
diff --git a/taxonomy/Makefile b/taxonomy/Makefile
index 6a04a8b..6c20ed6 100644
--- a/taxonomy/Makefile
+++ b/taxonomy/Makefile
@@ -4,7 +4,7 @@
test:
set -e; \
- for d in $(wildcard *_test.py); do \
+ for d in $(wildcard tests/*_test.py); do \
PYTHONPATH=. $(PYTHON) $$d; \
done
diff --git a/taxonomy/ethernet.py b/taxonomy/ethernet.py
index 9b994e7..eee8057 100644
--- a/taxonomy/ethernet.py
+++ b/taxonomy/ethernet.py
@@ -63,6 +63,7 @@
'90:b6:86': 'samsung',
'90:e7:c4': 'samsung',
'a0:0b:ba': 'samsung',
+ 'b0:df:3a': 'samsung',
'c0:bd:d1': 'samsung',
'c4:42:02': 'samsung',
'cc:3a:61': 'samsung',
diff --git a/taxonomy/dhcp_test.py b/taxonomy/tests/dhcp_test.py
similarity index 100%
rename from taxonomy/dhcp_test.py
rename to taxonomy/tests/dhcp_test.py
diff --git a/taxonomy/ethernet_test.py b/taxonomy/tests/ethernet_test.py
similarity index 100%
rename from taxonomy/ethernet_test.py
rename to taxonomy/tests/ethernet_test.py
diff --git a/taxonomy/ssdp_test.py b/taxonomy/tests/ssdp_test.py
similarity index 100%
rename from taxonomy/ssdp_test.py
rename to taxonomy/tests/ssdp_test.py
diff --git a/taxonomy/wifi_test.py b/taxonomy/tests/wifi_test.py
similarity index 100%
rename from taxonomy/wifi_test.py
rename to taxonomy/tests/wifi_test.py
diff --git a/taxonomy/wifi.py b/taxonomy/wifi.py
index b2c0651..2509685 100644
--- a/taxonomy/wifi.py
+++ b/taxonomy/wifi.py
@@ -348,11 +348,14 @@
'wifi|probe:0,1,50,45,221(0050f2,8),htcap:012c,htagg:03,htmcs:000000ff|assoc:0,1,50,48,45,221(0050f2,2),127,htcap:012c,htagg:03,htmcs:000000ff,extcap:020a0000|oui:asus':
('QCA_WCN3660', 'Nexus 7 (2013)', '2.4GHz'),
- 'wifi|probe:0,1,50,3,45,127,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,wps:Nexus_9|assoc:0,1,50,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:002d':
+ 'wifi|probe:0,1,50,3,45,127,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,wps:Nexus_9|assoc:0,1,50,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:002d|oui:htc':
('BCM4354', 'Nexus 9', '5GHz'),
- 'wifi|probe:0,1,50,3,45,127,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,wps:Nexus_9|assoc:0,1,50,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:002d':
+ 'wifi|probe:0,1,50,3,45,127,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,wps:Nexus_9|assoc:0,1,50,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:002d|oui:htc':
('BCM4354', 'Nexus 9', '2.4GHz'),
+ 'wifi|probe:0,1,45,221(001018,2),221(00904c,51),htcap:01fe,htagg:1b,htmcs:0000ffff|assoc:0,1,48,45,221(001018,2),221(00904c,51),221(0050f2,2),htcap:01fe,htagg:1b,htmcs:0000ffff|oui:samsung':
+ ('', 'Nexus 10', '5GHz'),
+
'wifi|probe:0,1,45,127,191,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:006f,vhtcap:0f815832,wps:Nexus_Player|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),htcap:006f,vhtcap:0f815832':
('BCM4356', 'Nexus Player', '5GHz'),
'wifi|probe:0,1,50,3,45,127,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,wps:Nexus_Player|assoc:0,1,50,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:002d':
diff --git a/waveguide/Makefile b/waveguide/Makefile
index 62c875e..c75da49 100644
--- a/waveguide/Makefile
+++ b/waveguide/Makefile
@@ -39,7 +39,7 @@
install:
mkdir -p $(LIBDIR) $(BINDIR)
- $(INSTALL) -m 0644 *.py $(LIBDIR)/
+ $(INSTALL) -m 0644 $(filter-out %_test.py, $(wildcard *.py)) $(LIBDIR)/
$(INSTALL) -m 0755 waveguide.py $(LIBDIR)/
$(INSTALL) -m 0755 waveguide $(BINDIR)/
diff --git a/wifi/Makefile b/wifi/Makefile
index 120d541..c6aa330 100644
--- a/wifi/Makefile
+++ b/wifi/Makefile
@@ -13,7 +13,7 @@
all:
%.test: %_test.py
- ./$<
+ PYTHONPATH=..:$(PYTHONPATH) ./$<
runtests: \
$(patsubst %_test.py,%.test,$(wildcard *_test.py))
@@ -22,7 +22,7 @@
$(GPYLINT) $^
test_only: all
- $(MAKE) runtests
+ ./wvtest/wvtestrun $(MAKE) runtests
# Use a submake here, only because otherwise GNU make (3.81) will not print
# an error about 'test' itself failing if one of the two sub-targets fails.
@@ -34,7 +34,7 @@
install:
mkdir -p $(LIBDIR) $(BINDIR)
- $(INSTALL) -m 0644 *.py $(LIBDIR)/
+ $(INSTALL) -m 0644 $(filter-out %_test.py, $(wildcard *.py)) $(LIBDIR)/
$(INSTALL) -m 0755 wifi.py $(LIBDIR)/
rm -f $(BINDIR)/wifi
ln -s /usr/wifi/wifi.py $(BINDIR)/wifi
diff --git a/wifi/iw.py b/wifi/iw.py
index 6f70806..a8ffdb4 100644
--- a/wifi/iw.py
+++ b/wifi/iw.py
@@ -65,7 +65,8 @@
**kwargs: Passed to the underlying subprocess call.
Returns:
- A dict of the the form: {'phyX': 'frequency_and_channel': [(F, C), ...]}
+ A dict of the the form: {'phyX': {'frequency_and_channel': [(F, C), ...],
+ 'bands': set(band1, ...)}, ...}
"""
result = {}
phy = None
@@ -74,12 +75,18 @@
match = _WIPHY_RE.match(line)
if match:
phy = match.group('phy')
- result[phy] = {'frequency_and_channel': []}
+ result[phy] = {'frequency_and_channel': [], 'bands': set()}
else:
match = _FREQUENCY_AND_CHANNEL_RE.match(line)
if match:
- result[phy]['frequency_and_channel'].append(
- (match.group('frequency'), match.group('channel')))
+ frequency, channel = match.group('frequency'), match.group('channel')
+ result[phy]['frequency_and_channel'].append((frequency, channel))
+ if frequency.startswith('2'):
+ result[phy]['bands'].add('2.4')
+ elif frequency.startswith('5'):
+ result[phy]['bands'].add('5')
+ else:
+ utils.log('Unrecognized frequency %s', frequency)
return result
@@ -310,3 +317,32 @@
"""
return utils.subprocess_output_or_none(
['iw', 'dev', interface, 'station', 'dump'])
+
+
+def phy_bands(which_phy):
+ """Returns the bands supported by the given phy.
+
+ If a phy P supports more than one band, and another phy Q supports only one of
+ those bands, P is not said to support that band.
+
+ Args:
+ which_phy: The phy for which to get bands.
+
+ Returns:
+ The bands supported by the given phy.
+ """
+
+ band_phys = {}
+ for phy, info in phy_parsed().iteritems():
+ bands = info['bands']
+ for band in bands:
+ band_phys.setdefault(band, phy)
+ if len(bands) == 1:
+ band_phys[list(bands)[0]] = phy
+
+ result = set()
+ for band, phy in band_phys.iteritems():
+ if which_phy == phy:
+ result.add(band)
+
+ return result
diff --git a/wifi/iw_test.py b/wifi/iw_test.py
index f2ddc02..4a7ef4c 100755
--- a/wifi/iw_test.py
+++ b/wifi/iw_test.py
@@ -553,5 +553,20 @@
INTERFACE_INFO_OUTPUT = hold
+@wvtest.wvtest
+def phy_bands_test():
+ # phy0 claims to support 5 GHz, but phy1 only supports 5 GHz and so it
+ # supercedes it.
+ wvtest.WVPASSEQ(set(['2.4']), iw.phy_bands('phy0'))
+ wvtest.WVPASSEQ(set(['5']), iw.phy_bands('phy1'))
+
+ # Now remove phy1 from the 'iw phy' output and see that phy0 gets both bands.
+ global PHY_OUTPUT
+ hold = PHY_OUTPUT
+ PHY_OUTPUT = PHY_OUTPUT[PHY_OUTPUT.find('Wiphy phy0'):]
+ wvtest.WVPASSEQ(set(['2.4', '5']), iw.phy_bands('phy0'))
+ PHY_OUTPUT = hold
+
+
if __name__ == '__main__':
wvtest.wvtest_main()
diff --git a/wifi/wifi.py b/wifi/wifi.py
index 37621d3..73b717d 100755
--- a/wifi/wifi.py
+++ b/wifi/wifi.py
@@ -923,6 +923,10 @@
if success:
if extra[0] == 'set':
if opt.persist:
+ phy = iw.find_phy(opt.band, opt.channel)
+ for band in iw.phy_bands(phy):
+ if band != opt.band:
+ persist.delete_options('hostapd', band)
persist.save_options('hostapd', opt.band, argv)
persist.save_options('hostapd', opt.band, argv, tmp=True)