summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2024-08-05 02:20:15 +0000
committerCoprDistGit <infra@openeuler.org>2024-08-05 02:20:15 +0000
commitcf1faf8e3ccdcfd410f1f6ce6a4542e03989771e (patch)
tree9ca4f2d2cd51ec2acc0757ff42fd12a845b091f2
parent9630dbd14b88cf311874c298100a97311a5efdaa (diff)
automatic import of gpsd-minimalopeneuler24.03_LTS
-rw-r--r--.gitignore2
-rw-r--r--gpsd-busywait.patch84
-rw-r--r--gpsd-ipv6.patch356
-rw-r--r--gpsd-minimal.spec233
-rw-r--r--gpsd-scanfixes.patch188
-rw-r--r--gpsd.sysconfig4
-rw-r--r--sources2
7 files changed, 869 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..e91772d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/gpsd-3.25.tar.gz
+/scons-4.5.2.tar.gz
diff --git a/gpsd-busywait.patch b/gpsd-busywait.patch
new file mode 100644
index 0000000..784cfd3
--- /dev/null
+++ b/gpsd-busywait.patch
@@ -0,0 +1,84 @@
+commit e5ba7aa2af74fd22ebbd5c4a6624edcf983863de
+Author: Michal Schmidt <mschmidt@redhat.com>
+Date: Fri Aug 4 16:53:01 2023 +0200
+
+ gps/gps.py.in: no busy-waiting when reading from gpsd socket
+
+ ubxtool keeps one CPU 100% busy while it waits for data to read from the
+ gpsd socket. Running it under strace showed that it calls select() with
+ zero timeout in a loop:
+
+ ...
+ 11:02:34.049629 pselect6(4, [3], [], [], {tv_sec=0, tv_nsec=0}, NULL) = 0 (Timeout)
+ 11:02:34.049649 pselect6(4, [3], [], [], {tv_sec=0, tv_nsec=0}, NULL) = 0 (Timeout)
+ 11:02:34.049670 pselect6(4, [3], [], [], {tv_sec=0, tv_nsec=0}, NULL) = 0 (Timeout)
+ ...
+
+ The busy waiting can be eliminated by passing the actual timeout value
+ to select(). In the reading loop in gps.py, the remaining time can be
+ easily calculated and passed as the argument to the self.ser.waiting()
+ function (which is basically a select() wrapper).
+
+ Fixing this problem exposed a bug in how the received bytes are decoded.
+ decode_func may not consume all input at once. Consumable input may be
+ left in self.out until decode_func returns zero, indicating that it
+ could not process any more input. So decode_func must be called in a
+ loop each time a buffer is received from the socket. The busy waiting
+ was hiding this issue, because decode_func was being called all the
+ time.
+
+ The "elif self.input_is_device:" branch probably needs similar
+ treatment, but I am testing only the gpsd usecase.
+
+diff --git a/gps/gps.py.in b/gps/gps.py.in
+index 623a750a0..14d7707ab 100644
+--- a/gps/gps.py.in
++++ b/gps/gps.py.in
+@@ -384,10 +384,11 @@ class gps_io(object):
+ if self.gpsd_host is not None:
+ # gpsd input
+ start = monotonic()
+- while (monotonic() - start) < input_wait:
++ remaining_time = input_wait
++ while remaining_time > 0:
+ # First priority is to be sure the input buffer is read.
+ # This is to prevent input buffer overuns
+- if 0 < self.ser.waiting():
++ if 0 < self.ser.waiting(remaining_time):
+ # We have serial input waiting, get it
+ # No timeout possible
+ # RTCM3 JSON can be over 4.4k long, so go big
+@@ -397,17 +398,22 @@ class gps_io(object):
+ raw_fd.write(polybytes(new_out))
+ self.out += new_out
+
+- consumed = decode_func(self.out)
+- # TODO: the decoder shall return a some current
+- # statement_identifier # to fill last_statement_identifier
+- last_statement_identifier = None
+- #
+- self.out = self.out[consumed:]
+- if ((expect_statement_identifier and
+- (expect_statement_identifier ==
+- last_statement_identifier))):
+- # Got what we were waiting for. Done?
+- ret_code = 0
++ while True:
++ consumed = decode_func(self.out)
++ if consumed == 0:
++ break
++ # TODO: the decoder shall return a some current
++ # statement_identifier # to fill last_statement_identifier
++ last_statement_identifier = None
++ #
++ self.out = self.out[consumed:]
++ if ((expect_statement_identifier and
++ (expect_statement_identifier ==
++ last_statement_identifier))):
++ # Got what we were waiting for. Done?
++ ret_code = 0
++
++ remaining_time = start + input_wait - monotonic()
+
+ elif self.input_is_device:
+ # input is a serial device
diff --git a/gpsd-ipv6.patch b/gpsd-ipv6.patch
new file mode 100644
index 0000000..ade8abb
--- /dev/null
+++ b/gpsd-ipv6.patch
@@ -0,0 +1,356 @@
+commit 5c080c35fc3d981172a5e4af34d0d92854a5433a
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date: Tue Jul 25 11:01:14 2023 +0200
+
+ libgps/netlib.c: Rework enabling non-block and make binding configurable.
+
+ Instead of accepting SOCK_NONBLOCK as flags in netlib_connectsock1()
+ specify if the non-blocking mode should be enabled after or before
+ connect().
+
+ Also add a boolean parameter to the function to select between connect()
+ and bind() instead of hardcoding it for TCP vs UDP, which will allow
+ connecting to UDP ports in gps2udp.
+
+diff --git a/gpsd/libgpsd_core.c b/gpsd/libgpsd_core.c
+index 47ee5d57e..341e8b80c 100644
+--- a/gpsd/libgpsd_core.c
++++ b/gpsd/libgpsd_core.c
+@@ -561,7 +561,6 @@ int gpsd_open(struct gps_device_t *session)
+ char server[GPS_PATH_MAX], *host, *port, *device;
+ socket_t dsock;
+ char addrbuf[50]; // INET6_ADDRSTRLEN
+- int sock_opt;
+
+ session->sourcetype = SOURCE_TCP;
+ (void)strlcpy(server, session->gpsdata.dev.path + 6, sizeof(server));
+@@ -576,15 +575,9 @@ int gpsd_open(struct gps_device_t *session)
+ GPSD_LOG(LOG_PROG, &session->context->errout,
+ "CORE: opening TCP feed at %s, port %s.\n", host,
+ port);
+-#if defined(SOCK_NONBLOCK)
+- sock_opt = SOCK_NONBLOCK;
+-#else
+- // macOS has no SOCK_NONBLOCK
+- sock_opt = 0;
+-#endif
+ // open non-blocking
+ dsock = netlib_connectsock1(AF_UNSPEC, host, port, "tcp",
+- sock_opt, addrbuf, sizeof(addrbuf));
++ 1, false, addrbuf, sizeof(addrbuf));
+ if (0 > dsock) {
+ GPSD_LOG(LOG_ERROR, &session->context->errout,
+ "CORE: TCP %s IP %s, open error %s(%d).\n",
+@@ -614,7 +607,8 @@ int gpsd_open(struct gps_device_t *session)
+ GPSD_LOG(LOG_PROG, &session->context->errout,
+ "CORE: opening UDP feed at %s, port %s.\n", host,
+ port);
+- if (0 > (dsock = netlib_connectsock(AF_UNSPEC, host, port, "udp"))) {
++ if (0 > (dsock = netlib_connectsock1(AF_UNSPEC, host, port, "udp",
++ 0, true, NULL, 0))) {
+ GPSD_LOG(LOG_ERROR, &session->context->errout,
+ "CORE: UDP device open error %s(%d).\n",
+ netlib_errstr(dsock), dsock);
+diff --git a/gpsd/net_ntrip.c b/gpsd/net_ntrip.c
+index 8241995ae..d89bdc1f9 100644
+--- a/gpsd/net_ntrip.c
++++ b/gpsd/net_ntrip.c
+@@ -856,7 +856,8 @@ static int ntrip_reconnect(struct gps_device_t *device)
+ device->gpsdata.dev.path);
+ dsock = netlib_connectsock1(AF_UNSPEC, device->ntrip.stream.host,
+ device->ntrip.stream.port,
+- "tcp", SOCK_NONBLOCK, addrbuf, sizeof(addrbuf));
++ "tcp", 1, false,
++ addrbuf, sizeof(addrbuf));
+ device->gpsdata.gps_fd = dsock;
+ // nonblocking means we have the fd, but the connection is not
+ // finished yet. Connection may fail, later.
+diff --git a/include/gpsd.h b/include/gpsd.h
+index 0f6b731eb..2f3260c1e 100644
+--- a/include/gpsd.h
++++ b/include/gpsd.h
+@@ -1002,7 +1002,7 @@ extern void gpsd_clear_data(struct gps_device_t *);
+ extern socket_t netlib_connectsock(int, const char *, const char *,
+ const char *);
+ extern socket_t netlib_connectsock1(int, const char *, const char *,
+- const char *, int,
++ const char *, int, bool,
+ char *, size_t);
+ // end FIXME
+ extern socket_t netlib_localsocket(const char *, int);
+diff --git a/libgps/netlib.c b/libgps/netlib.c
+index e4e763025..5f553fe10 100644
+--- a/libgps/netlib.c
++++ b/libgps/netlib.c
+@@ -55,8 +55,10 @@
+ * host - host to connect to
+ * service -- aka port
+ * protocol
+- * flags -- can be SOCK_NONBLOCK for non-blocking connect
+- * Note: macOS does not have SOCK_NONBLOCK
++ * nonblock -- 1 sets the socket as non-blocking before connect() if
++ * SOCK_NONBLOCK is supported,
++ * >1 sets the socket as non-blocking after connect()
++ * bind_me -- call bind() on the socket instead of connect()
+ * addrbuf -- 50 char buf to put string of IP address conencting
+ * INET6_ADDRSTRLEN
+ * addrbuf_sz -- sizeof(adddrbuf)
+@@ -70,16 +72,15 @@
+ * less than zero on error (NL_*)
+ */
+ socket_t netlib_connectsock1(int af, const char *host, const char *service,
+- const char *protocol, int flags,
++ const char *protocol, int nonblock, bool bind_me,
+ char *addrbuf, size_t addrbuf_sz)
+ {
+ struct protoent *ppe;
+ struct addrinfo hints;
+ struct addrinfo *result = NULL;
+ struct addrinfo *rp;
+- int ret, type, proto, one;
++ int ret, flags, type, proto, one;
+ socket_t s;
+- bool bind_me;
+
+ if (NULL != addrbuf) {
+ addrbuf[0] = '\0';
+@@ -97,9 +98,6 @@ socket_t netlib_connectsock1(int af, const char *host, const char *service,
+ return NL_NOPROTO;
+ }
+
+- /* we probably ought to pass this in as an explicit flag argument */
+- bind_me = (SOCK_DGRAM == type);
+-
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = af;
+ hints.ai_socktype = type;
+@@ -107,6 +105,15 @@ socket_t netlib_connectsock1(int af, const char *host, const char *service,
+ if (bind_me) {
+ hints.ai_flags = AI_PASSIVE;
+ }
++#if defined(SOCK_NONBLOCK)
++ flags = nonblock == 1 ? SOCK_NONBLOCK : 0;
++#else
++ // macOS has no SOCK_NONBLOCK
++ flags = 0;
++ if (nonblock == 1)
++ nonblock = 2;
++#endif
++
+ // FIXME: need a way to bypass these DNS calls if host is an IP.
+ if ((ret = getaddrinfo(host, service, &hints, &result))) {
+ // result is unchanged on error, so we need to have set it to NULL
+@@ -219,13 +226,15 @@ socket_t netlib_connectsock1(int af, const char *host, const char *service,
+ sizeof(one));
+ }
+
+- // set socket to noblocking
++ if (nonblock > 1) {
++ // set socket to noblocking
+ #ifdef HAVE_FCNTL
+- (void)fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
++ (void)fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
+ #elif defined(HAVE_WINSOCK2_H)
+- u_long one1 = 1;
+- (void)ioctlsocket(s, FIONBIO, &one1);
++ u_long one1 = 1;
++ (void)ioctlsocket(s, FIONBIO, &one1);
+ #endif
++ }
+ return s;
+ }
+
+@@ -235,7 +244,7 @@ socket_t netlib_connectsock1(int af, const char *host, const char *service,
+ socket_t netlib_connectsock(int af, const char *host, const char *service,
+ const char *protocol)
+ {
+- return netlib_connectsock1(af, host, service, protocol, 0, NULL, 0);
++ return netlib_connectsock1(af, host, service, protocol, 2, false, NULL, 0);
+ }
+
+ // Convert NL_* error code to a string
+
+commit fd6682a6ffd0a5d4d640839422274b582ba38e72
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date: Tue Jul 25 11:08:19 2023 +0200
+
+ clients/gps2udp.c: Switch to netlib_connectsock1().
+
+ Use netlib_connectsock1() to avoid using obsolete gethostbyname() and
+ support IPv6.
+
+diff --git a/clients/gps2udp.c b/clients/gps2udp.c
+index 2d9c6033d..541054d8f 100644
+--- a/clients/gps2udp.c
++++ b/clients/gps2udp.c
+@@ -21,7 +21,6 @@
+ #ifdef HAVE_GETOPT_LONG
+ #include <getopt.h> // for getopt_long()
+ #endif
+-#include <netdb.h> /* for gethostbyname() */
+ #include <netinet/in.h>
+ #include <stdbool.h>
+ #include <stdio.h>
+@@ -50,7 +49,6 @@ static struct gps_data_t gpsdata;
+
+ /* UDP socket variables */
+ #define MAX_UDP_DEST 5
+-static struct sockaddr_in remote[MAX_UDP_DEST];
+ static int sock[MAX_UDP_DEST];
+ static int udpchannel;
+
+@@ -128,12 +126,10 @@ static int send_udp(char *nmeastring, size_t ind)
+
+ // send message on udp channel
+ for (channel=0; channel < udpchannel; channel ++) {
+- ssize_t status = sendto(sock[channel],
+- buffer,
+- ind,
+- 0,
+- (struct sockaddr *)&remote[channel],
+- (int)sizeof(remote));
++ ssize_t status = send(sock[channel],
++ buffer,
++ ind,
++ 0);
+ if (status < (ssize_t)ind) {
+ (void)fprintf(stderr, "gps2udp: failed to send [%s] \n",
+ buffer);
+@@ -152,9 +148,6 @@ static int open_udp(char **hostport)
+ for (channel = 0; channel < udpchannel; channel++) {
+ char *hostname = NULL;
+ char *portname = NULL;
+- char *endptr = NULL;
+- int portnum;
+- struct hostent *hp;
+
+ if (NULL == hostport[channel]) {
+ // pacify coverity
+@@ -171,32 +164,13 @@ static int open_udp(char **hostport)
+ return -1;
+ }
+
+- errno = 0;
+- portnum = (int)strtol(portname, &endptr, 10);
+- if (1 > portnum || 65535 < portnum || '\0' != *endptr || 0 != errno) {
+- (void)fprintf(stderr, "gps2udp: syntax is [-u hostname:port] "
+- "[%s] is not a valid port number\n", portname);
+- return -1;
+- }
+-
+- sock[channel]= socket(AF_INET, SOCK_DGRAM, 0);
++ sock[channel] = netlib_connectsock1(AF_UNSPEC, hostname, portname, "udp",
++ 0, false, NULL, 0);
+ if (0 > sock[channel]) {
+- (void)fprintf(stderr, "gps2udp: error creating UDP socket\n");
++ (void)fprintf(stderr, "gps2udp: error creating UDP socket: %s\n",
++ netlib_errstr(sock[channel]));
+ return -1;
+ }
+-
+- remote[channel].sin_family = (sa_family_t)AF_INET;
+- hp = gethostbyname(hostname);
+- if (NULL == hp) {
+- (void)fprintf(stderr,
+- "gps2udp: syntax is [-u hostname:port] [%s]"
+- " is not a valid hostname\n",
+- hostname);
+- return -1;
+- }
+-
+- memcpy( &remote[channel].sin_addr, hp->h_addr_list[0], hp->h_length);
+- remote[channel].sin_port = htons((in_port_t)portnum);
+ }
+ return 0;
+ }
+
+commit 749be8acce27f16d74ba727f4819f3e49602882a
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date: Tue Jul 25 11:10:39 2023 +0200
+
+ clients/lcdgps.c: Switch to netlib_connectsock1().
+
+ Use netlib_connectsock1() to avoid using obsolete gethostbyname() and
+ support IPv6.
+
+diff --git a/clients/lcdgps.c b/clients/lcdgps.c
+index 7d0ee6bc8..b311882b0 100644
+--- a/clients/lcdgps.c
++++ b/clients/lcdgps.c
+@@ -21,11 +21,12 @@
+ */
+
+ #define LCDDHOST "localhost"
+-#define LCDDPORT 13666
++#define LCDDPORT "13666"
+
+ #define CLIMB 3
+
+ #include "../include/gpsd_config.h" /* must be before all includes */
++#include "../include/gpsd.h"
+
+ #include <arpa/inet.h>
+ #include <errno.h>
+@@ -33,7 +34,6 @@
+ #include <getopt.h> // for getopt_long()
+ #endif
+ #include <math.h>
+-#include <netdb.h> /* for gethostbyname() */
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -259,9 +259,6 @@ static void usage( char *prog)
+
+ int main(int argc, char *argv[])
+ {
+- int rc;
+- struct sockaddr_in localAddr, servAddr;
+- struct hostent *h;
+ const char *optstring = "?hl:su:V";
+ int n;
+ #ifdef HAVE_GETOPT_LONG
+@@ -390,41 +387,10 @@ int main(int argc, char *argv[])
+ }
+
+ /* Connect to LCDd */
+- h = gethostbyname(LCDDHOST);
+- if (h==NULL) {
+- printf("%s: unknown host '%s'\n",argv[0],LCDDHOST);
+- exit(EXIT_FAILURE);
+- }
+-
+- servAddr.sin_family = h->h_addrtype;
+- memcpy((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
+- servAddr.sin_port = htons(LCDDPORT);
+-
+- /* create socket */
+- sd = socket(AF_INET, SOCK_STREAM, 0);
+- if (BAD_SOCKET(sd)) {
+- perror("cannot open socket ");
+- exit(EXIT_FAILURE);
+- }
+-
+- /* bind any port number */
+- localAddr.sin_family = AF_INET;
+- localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+- localAddr.sin_port = htons(0);
+-
+- /* coverity[uninit_use_in_call] */
+- rc = bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr));
+- if (rc == -1) {
+- printf("%s: cannot bind port TCP %d\n",argv[0],LCDDPORT);
+- perror("error ");
+- exit(EXIT_FAILURE);
+- }
++ sd = netlib_connectsock1(AF_UNSPEC, LCDDHOST, LCDDPORT, "tcp", 0, false, NULL, 0);
++ if (0 > sd) {
+
+- /* connect to server */
+- /* coverity[uninit_use_in_call] */
+- rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
+- if (rc == -1) {
+- perror("cannot connect ");
++ (void)fprintf(stderr, "lcdgps: cannot connect: %s\n", netlib_errstr(sd));
+ exit(EXIT_FAILURE);
+ }
+
diff --git a/gpsd-minimal.spec b/gpsd-minimal.spec
new file mode 100644
index 0000000..488130e
--- /dev/null
+++ b/gpsd-minimal.spec
@@ -0,0 +1,233 @@
+%global scons_ver 4.5.2
+%global scons python3 scons-%{scons_ver}/scripts/scons.py
+%global note1 The Red Hat support for this package is limited. See
+%global note2 https://access.redhat.com/support/policy/gpsd-support for more details.
+
+Name: gpsd-minimal
+Version: 3.25
+Release: 4%{?dist}
+Epoch: 1
+Summary: Service daemon for mediating access to a GPS
+
+License: BSD
+URL: https://gpsd.gitlab.io/gpsd/index.html
+Source0: https://download-mirror.savannah.gnu.org/releases/gpsd/gpsd-%{version}.tar.gz
+# used only for building
+Source1: https://github.com/SCons/scons/archive/%{scons_ver}/scons-%{scons_ver}.tar.gz
+Source11: gpsd.sysconfig
+
+# add missing IPv6 support
+Patch1: gpsd-ipv6.patch
+# fix some issues reported by coverity and shellcheck
+Patch2: gpsd-scanfixes.patch
+# fix busy wait when reading from gpsd socket
+Patch3: gpsd-busywait.patch
+
+BuildRequires: gcc
+BuildRequires: dbus-devel
+BuildRequires: ncurses-devel
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pyserial
+BuildRequires: bluez-libs-devel
+BuildRequires: pps-tools-devel
+BuildRequires: systemd-rpm-macros
+BuildRequires: libusb1-devel
+
+Requires: udev
+%{?systemd_requires}
+
+Conflicts: gpsd < %{epoch}:%{version}-%{release}
+
+%description
+gpsd is a service daemon that mediates access to a GPS sensor
+connected to the host computer by serial or USB interface, making its
+data on the location/course/velocity of the sensor available to be
+queried on TCP port 2947 of the host computer.
+
+%{note1}
+%{note2}
+
+%package clients
+Summary: Clients for gpsd
+Requires: python3-pyserial
+Conflicts: gpsd-clients < %{epoch}:%{version}-%{release}
+
+%description clients
+This package contains various clients using gpsd.
+
+%{note1}
+%{note2}
+
+%prep
+%setup -q -n gpsd-%{version} -a 1
+%patch -P 1 -p1 -b .ipv6
+%patch -P 2 -p1 -b .scanfixes
+%patch -P 3 -p1 -b .busywait
+
+# add note to man pages about limited support
+sed -i ':a;$!{N;ba};s|\(\.SH "[^"]*"\)|.SH "NOTE"\n%{note1}\n%{note2}\n\1|3' \
+ man/*.{1,8}
+
+# add path to the private python gps module
+sed -i 's|\( *\)\(import gps\)$|\1sys.path.insert(1, "%{_libdir}/gpsd%{version}")\n\1\2|' \
+ *.py.in clients/*.py.in
+
+# don't try reloading systemd when installing in the build root
+sed -i 's|systemctl daemon-reload|true|' SConscript
+
+iconv -f iso8859-1 -t utf8 NEWS > NEWS_ && mv NEWS_ NEWS
+
+%build
+export CCFLAGS="%{optflags}"
+# scons ignores LDFLAGS. LINKFLAGS partially work (some flags like
+# -spec=... are filtered)
+export LINKFLAGS="%{__global_ldflags}"
+
+# breaks with %%{_smp_mflags}
+%{scons} \
+ dbus_export=yes \
+ systemd=yes \
+ qt=no \
+ xgps=no \
+ debug=yes \
+ leapfetch=no \
+ manbuild=no \
+ prefix="" \
+ sysconfdif=%{_sysconfdir} \
+ bindir=%{_bindir} \
+ includedir=%{_includedir} \
+ libdir=%{_libdir}/gpsd%{version} \
+ sbindir=%{_sbindir} \
+ mandir=%{_mandir} \
+ mibdir=%{_docdir}/gpsd \
+ docdir=%{_docdir}/gpsd \
+ pkgconfigdir=%{_libdir}/pkgconfig \
+ icondir=%{_datadir}/gpsd \
+ udevdir=$(dirname %{_udevrulesdir}) \
+ unitdir=%{_unitdir} \
+ target_python=python3 \
+ python_shebang=%{python3} \
+ python_libdir=%{_libdir}/gpsd%{version} \
+ build
+
+%install
+# avoid rebuilding
+export CCFLAGS="%{optflags}"
+export LINKFLAGS="%{__global_ldflags}"
+
+DESTDIR=%{buildroot} %{scons} install systemd_install udev-install
+
+# use the old name for udev rules
+mv %{buildroot}%{_udevrulesdir}/{25,99}-gpsd.rules
+
+install -d -m 0755 %{buildroot}%{_sysconfdir}/sysconfig
+install -p -m 0644 %{SOURCE11} \
+ %{buildroot}%{_sysconfdir}/sysconfig/gpsd
+
+# Missed in scons install
+install -p -m 0755 gpsinit %{buildroot}%{_sbindir}
+
+# Remove shebang and fix permissions
+sed -i '/^#!.*python/d' %{buildroot}%{_libdir}/gpsd%{version}/gps/{aio,}gps.py
+chmod 644 %{buildroot}%{_libdir}/gpsd%{version}/gps/gps.py
+
+# Remove unpackaged files
+rm -f %{buildroot}%{_libdir}/gpsd%{version}/lib{gps*.so,gps.so.*}
+rm -f %{buildroot}%{_libdir}/gpsd%{version}/*.egg-info
+rm -rf %{buildroot}%{_libdir}/gpsd%{version}/pkgconfig
+rm -rf %{buildroot}%{_includedir}
+rm -rf %{buildroot}%{_mandir}/man{3,5}
+rm -r %{buildroot}%{_mandir}/man1/xgps*
+rm -rf %{buildroot}%{_datadir}/gpsd
+
+rm -rf %{buildroot}%{_docdir}/gpsd
+
+%post
+%systemd_post gpsd.service gpsd.socket
+
+%preun
+%systemd_preun gpsd.service gpsd.socket
+
+%postun
+# Don't restart the service
+%systemd_postun gpsd.service gpsd.socket
+
+%files
+%doc README.adoc NEWS
+%license COPYING
+%config(noreplace) %{_sysconfdir}/sysconfig/gpsd
+%{_sbindir}/gpsd
+%{_sbindir}/gpsdctl
+%{_sbindir}/gpsinit
+%{_bindir}/gpsmon
+%{_bindir}/gpsctl
+%{_bindir}/ntpshmmon
+%{_bindir}/ppscheck
+%{_unitdir}/gpsd.service
+%{_unitdir}/gpsd.socket
+%{_unitdir}/gpsdctl@.service
+%{_udevrulesdir}/*.rules
+%{_mandir}/man8/gpsd.8*
+%{_mandir}/man8/gpsdctl.8*
+%{_mandir}/man8/gpsinit.8*
+%{_mandir}/man8/ppscheck.8*
+%{_mandir}/man1/gpsmon.1*
+%{_mandir}/man1/gpsctl.1*
+%{_mandir}/man1/ntpshmmon.1*
+
+%files clients
+%license COPYING
+%{_libdir}/gpsd%{version}/libgpsdpacket.so.*
+%{_libdir}/gpsd%{version}/gps
+%{_bindir}/cgps
+%{_bindir}/gegps
+%{_bindir}/gps2udp
+%{_bindir}/gpscat
+%{_bindir}/gpscsv
+%{_bindir}/gpsdebuginfo
+%{_bindir}/gpsdecode
+%{_bindir}/gpspipe
+%{_bindir}/gpsplot
+%{_bindir}/gpsprof
+%{_bindir}/gpsrinex
+%{_bindir}/gpssnmp
+%{_bindir}/gpssubframe
+%{_bindir}/gpxlogger
+%{_bindir}/lcdgps
+%{_bindir}/gpsfake
+%{_bindir}/ubxtool
+%{_bindir}/zerk
+%{_mandir}/man1/gegps.1*
+%{_mandir}/man1/gps.1*
+%{_mandir}/man1/gps2udp.1*
+%{_mandir}/man1/gpscsv.1*
+%{_mandir}/man1/gpsdebuginfo.1*
+%{_mandir}/man1/gpsdecode.1*
+%{_mandir}/man1/gpspipe.1*
+%{_mandir}/man1/gpsplot.1*
+%{_mandir}/man1/gpsprof.1*
+%{_mandir}/man1/gpsrinex.1*
+%{_mandir}/man1/gpssnmp.1*
+%{_mandir}/man1/gpssubframe.1*
+%{_mandir}/man1/gpxlogger.1*
+%{_mandir}/man1/lcdgps.1*
+%{_mandir}/man1/cgps.1*
+%{_mandir}/man1/gpscat.1*
+%{_mandir}/man1/gpsfake.1*
+%{_mandir}/man1/ubxtool.1*
+%{_mandir}/man1/zerk.1*
+
+%changelog
+* Tue Aug 08 2023 Miroslav Lichvar <mlichvar@redhat.com> - 1:3.25-4
+- fix busy wait when reading from gpsd socket
+
+* Tue Aug 08 2023 Miroslav Lichvar <mlichvar@redhat.com> - 1:3.25-3
+- fix gpsfake to load python gps module
+
+* Tue Aug 01 2023 Miroslav Lichvar <mlichvar@redhat.com> - 1:3.25-2
+- add missing IPv6 support
+- fix some issues reported by coverity and shellcheck
+
+* Mon Jul 24 2023 Miroslav Lichvar <mlichvar@redhat.com> - 1:3.25-1
+- initial release based on Fedora gpsd package
diff --git a/gpsd-scanfixes.patch b/gpsd-scanfixes.patch
new file mode 100644
index 0000000..67cca18
--- /dev/null
+++ b/gpsd-scanfixes.patch
@@ -0,0 +1,188 @@
+commit 651d505d2b075b9bd87729d2d5d155c29c03fbc1
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date: Mon Jul 31 15:46:16 2023 +0200
+
+ devtools/tablegen.py: Fix typo in structname.
+
+diff --git a/devtools/tablegen.py b/devtools/tablegen.py
+index 7851fceca..3feb64b9e 100755
+--- a/devtools/tablegen.py
++++ b/devtools/tablegen.py
+@@ -129,7 +129,7 @@ def make_driver_code(wfp):
+ continue
+ offset = offsets[i].split('-')[0]
+ if arrayname:
+- target = "%s.%s[i].%s" % (structnme, arrayname, name)
++ target = "%s.%s[i].%s" % (structname, arrayname, name)
+ offset = "a + " + offset
+ else:
+ target = "%s.%s" % (structname, name)
+
+commit db2a00f7ee4e66ee57ff66e84cec664444c26d8f
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date: Mon Jul 31 15:47:10 2023 +0200
+
+ gpsd/net_dgpsip.c: Fix socket check.
+
+diff --git a/gpsd/net_dgpsip.c b/gpsd/net_dgpsip.c
+index d6e123b67..8e218ba41 100644
+--- a/gpsd/net_dgpsip.c
++++ b/gpsd/net_dgpsip.c
+@@ -42,7 +42,7 @@ socket_t dgpsip_open(struct gps_device_t *device, const char *dgpsserver)
+ }
+
+ dsock = netlib_connectsock(AF_UNSPEC, dgpsserver, dgpsport, "tcp");
+- if (0 <= dsock) {
++ if (0 > dsock) {
+ GPSD_LOG(LOG_ERROR, &device->context->errout,
+ "DGPS: can't connect to DGPS server %s, netlib error %s(%d).\n",
+ dgpsserver, netlib_errstr(dsock), dsock);
+
+commit 60bc3595dbb74f8904037ad64b2a0820c408996b
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date: Mon Jul 31 15:50:32 2023 +0200
+
+ clients/gpsdebuginfo: Fix issues reported by shellcheck.
+
+diff --git a/clients/gpsdebuginfo b/clients/gpsdebuginfo
+index fa970dad9..38a1540b2 100755
+--- a/clients/gpsdebuginfo
++++ b/clients/gpsdebuginfo
+@@ -7,7 +7,7 @@ exec 2>&1
+
+ # print what we do
+ set -x
+-if [ 0 != $(id -u) ]; then
++if [ 0 != "$(id -u)" ]; then
+ echo "Please run as root"
+ exit 1
+ fi
+@@ -63,9 +63,9 @@ ls -l /dev/pps* /dev/tty[ASTU]* /dev/gps*
+ if command -v lsusb; then
+ lsusb
+ fi
+-echo PYTHONPATH $PYTHONPATH
++echo PYTHONPATH "$PYTHONPATH"
+ if command -v gpscat; then
+- head -n 1 `command -v gpscat`
++ head -n 1 "$(command -v gpscat)"
+ fi
+ if command -v python; then
+ python -V
+
+commit e12265d591f07a50d6de54af83ae6246326460ef
+Author: Miroslav Lichvar <mlichvar@redhat.com>
+Date: Mon Jul 31 15:50:58 2023 +0200
+
+ gpsinit: Fix issues reported by shellcheck.
+
+diff --git a/gpsinit b/gpsinit
+index 5c14f3374..8fc6c92ec 100755
+--- a/gpsinit
++++ b/gpsinit
+@@ -6,26 +6,23 @@
+ # SPDX-License-Identifier: BSD-2-clause
+ #
+
+-speed=38400
+ net=0
+
+ version()
+ {
+- echo `basename $0`" : Version v0.21";
++ echo "$(basename "$0") : Version v0.21";
+ }
+
+ usage()
+ {
+ version; echo;
+- echo "usage :" `basename $0` "[-n <netnumber>] [-s <serial speed>] <can_module_name> [<interface_name>]";
+- echo " :" `basename $0` "-V";
+- echo " :" `basename $0` "-h";
++ echo "usage : $(basename "$0") [-n <netnumber>] <can_module_name> [<interface_name>]";
++ echo " : $(basename "$0") -V";
++ echo " : $(basename "$0") -h";
+ echo " Options include:";
+ echo " -? = Print this help message and exit.";
+ echo " -h = Print this help message and exit.";
+ echo " -n = CAN network number, 0 if not given.";
+- echo " -s = Speed of the slcan hardware port, 38400 if not given.";
+- echo " = Needed for some slcan modules only.";
+ echo " -V = Print version of this script and exit.";
+ echo " can_module_name = One out of plx_pci, esd_usb2, usb_8dev, vcan, slcan, beaglebone.";
+ echo " interface_name = The interface, the SLCAN module is connected to, i.e. /dev/ttyS0 or /dev/ttyUSB0.";
+@@ -34,19 +31,19 @@ usage()
+ }
+
+ # -v for version is deprecated 2020
+-while getopts :n:s:vh opt
++while getopts :n:s:vVh opt
+ do
+ case ${opt} in
+ h) usage; exit 0;;
+ n) net=${OPTARG};;
+- s) speed=${OPTARG};;
++ s) ;; # unused
+ \?) usage; exit 1;;
+ v) version; exit 0;;
+ V) version; exit 0;;
+ esac
+ done
+
+-shift $((${OPTIND} - 1))
++shift $((OPTIND - 1))
+
+ candevice=$1
+
+@@ -54,38 +51,38 @@ case ${candevice} in
+ plx_pci)
+ # For the SJA1000 based PCI or PCI-Express CAN interface
+ modprobe plx_pci;
+- ip link set can${net} type can tq 250 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1;
+- ip link set can${net} up;;
++ ip link set "can${net}" type can tq 250 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1;
++ ip link set "can${net}" up;;
+ esd_usb2)
+ # For an esd usb/2 CAN interface
+ modprobe esd_usb2;
+- ip link set can${net} type can tq 250 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1;
+- ip link set can${net} up;;
++ ip link set "can${net}" type can tq 250 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1;
++ ip link set "can${net}" up;;
+ usb_8dev)
+ # For an 8devices usb2can CAN interface
+ modprobe usb_8dev;
+- ip link set can${net} type can tq 250 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1;
+- ip link set can${net} up;;
++ ip link set "can${net}" type can tq 250 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1;
++ ip link set "can${net}" up;;
+ vcan)
+ # With this setup, CAN frames can be injected into vcan0 by a test
+ modprobe vcan;
+ ip link add type vcan;
+- ip link set vcan${net} up;;
++ ip link set "vcan${net}" up;;
+ slcan)
+ # For a serial line CAN device
+ # No support for devices, that need a setup of the baudrate yet
+ device=${2:-/dev/ttyUSB0};
+ modprobe slcan;
+- slcan_attach -f -s5 -o ${device};
+- slcand `basename ${device}`;
+- ip link set slcan${net} up;;
++ slcan_attach -f -s5 -o "${device}";
++ slcand "$(basename "${device}")";
++ ip link set "slcan${net}" up;;
+ beaglebone)
+ # For CAN interface on a BeagleBone
+ # The d_can driver is part of the kernel
+- ip link set can${net} type can bitrate 250000 sjw 1;
+- ip link set can${net} up;;
++ ip link set "can${net}" type can bitrate 250000 sjw 1;
++ ip link set "can${net}" up;;
+ *)
+- echo `basename ${0}` ": invalid CAN interface ${1} net${net} device ${2:-(none)}"
++ echo "$(basename "$0") : invalid CAN interface ${1} net${net} device ${2:-(none)}"
+ echo;
+ usage;
+ exit 1
diff --git a/gpsd.sysconfig b/gpsd.sysconfig
new file mode 100644
index 0000000..2d840c0
--- /dev/null
+++ b/gpsd.sysconfig
@@ -0,0 +1,4 @@
+# Options for gpsd, including serial devices
+OPTIONS=""
+# Set to 'true' to add USB devices automatically via udev
+USBAUTO="true"
diff --git a/sources b/sources
new file mode 100644
index 0000000..9cd424c
--- /dev/null
+++ b/sources
@@ -0,0 +1,2 @@
+e8903e7af2d56445b82a4c3be6ec8e26 gpsd-3.25.tar.gz
+33178bed59fc16f13a53d22597a550ec scons-4.5.2.tar.gz