Re: OpenBSD 7.2 on Oracle Cloud

2023-05-02 Thread Aaron Mason
On Tue, May 2, 2023 at 11:30 AM Aaron Mason  wrote:
>
> On Tue, May 2, 2023 at 9:29 AM Aaron Mason  wrote:
> > [REDACTED]
> > >
> > > The actual problem is here. One request times out, but the driver does
> > > not tell qemu that it should abort the request. The queue entry then
> > > gets reused and the two responses from qemu overwrite each other. You
> > > could try if increasing the timeout here to e.g. 1 helps:
> > >
> > >  if (ISSET(xs->flags, SCSI_POLL)) {
> > >  DPRINTF("vioscsi_scsi_cmd: polling...\n");
> > >  int timeout = 1000;
> > >  do {
> > >  virtio_poll_intr(vsc);
> > >  if (vr->vr_xs != xs)
> > >  break;
> > >  delay(1000);
> > >  } while (--timeout > 0);
> > >  if (vr->vr_xs == xs) {
> > >  // TODO(matthew): Abort the request.
> > >  xs->error = XS_TIMEOUT;
> > >  xs->resid = xs->datalen;
> > >  DPRINTF("vioscsi_scsi_cmd: polling timeout\n");
> > >  scsi_done(xs);
> > >  }
> > >
> > > Unfortunately, it order to properly abort the request, quite a bit of
> > > infrastructure related to the control queue is still missing in the 
> > > driver.
> >
> > I'll give it a go and report back, thanks!
> >
>
> No dice, it only takes longer to generate a page fault.
>
> --
> Aaron Mason - Programmer, open source addict
> I've taken my software vows - for beta or for worse

Increasing it to 4 has the same effect, only longer.

-- 
Aaron Mason - Programmer, open source addict
I've taken my software vows - for beta or for worse



Re: usr.bin/mail: cmd3.c:bangexp(): "borked"?, and BSD fails POSIX compat

2023-05-02 Thread Steffen Nurpmeso
Steffen Nurpmeso wrote in
 <20230502214014._ziz6%stef...@sdaoden.eu>:
 |Hallo, and sorry for the cross-post, but so all in one (maybe) go.
 |
 |This is about a niche "feature" of mail, the shell command "bang"
 |(! / ~! in compose mode):
 ...
 |POSIX now says / will say
 |
 |  If the bang variable is set, each unescaped occurrence of '!' in
 |  command shall be replaced with the command executed by the
 |  previous ! command or ˜! command escape.
 |
 |thus
 |
 |  - All commands entered for ! and ~! shall be stored.
 |
 |  - If "bang" is set, an unquoted ! shall be replaced by that
 |storage.
 ...
 |It will fail to properly "bang" a second time[.]

Eh, forget this please.  Of course not, one simply inserts the old
string without expansion.
Since vim(1) offers the same "bang"ing, and merges \! to ! (source
comment speaks of vi-compat) i keep it.  (It actually requires
'\!' or \\! ro avoid its expansion in ":echo BLA".)

Ciao.



static struct str last_bang;

struct n_string xbang, *bang;
char c;
char const *cp_orig;
boole bangit, changed;
NYD_IN;

bangit = ok_blook(bang);
changed = FAL0;
cp_orig = cp;

for(bang = n_string_creat(); (c = *cp++) != '\0';){
if(bangit && c == '!'){
changed = TRU1;
if(last_bang.l > 0)
bang = n_string_push_buf(bang, last_bang.s, 
last_bang.l);
}else{
if(c == '\\' && *cp == '!'){
changed = TRU1;
++cp;
c = '!';
}
bang = n_string_push_c(bang, c);
}
}

if(last_bang.s != NIL)
su_FREE(last_bang.s);

last_bang.s = n_string_cp(bang);
last_bang.l = bang->s_len;
bang = n_string_drop_ownership(bang);
n_string_gut(bang);

if(bangit){
cp = last_bang.s;
if(changed && (n_psonce & n_PSO_INTERACTIVE))
fprintf(n_stdout, "!%s\n", cp);
}else
cp = cp_orig;

NYD_OU;
return cp;

--steffen
|
|Der Kragenbaer,The moon bear,
|der holt sich munter   he cheerfully and one by one
|einen nach dem anderen runter  wa.ks himself off
|(By Robert Gernhardt)
|~~
|..and in spring, hear David Leonard sing..
|
|The black bear,  The black bear,
|blithely holds his own   holds himself at leisure
|beating it, up and down  tossing over his ups and downs with pleasure
|~~
|Farewell, dear collar bear



nd6 less kernel lock

2023-05-02 Thread Alexander Bluhm
Hi,

Some checks in nd6_resolve() do not require kernel lock.  The analog
code for ARP has been unlocked in if_ether.c revision 1.250 since
2022/06/27 20:47:10.

ok?

bluhm

Index: netinet6/nd6.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.273
diff -u -p -r1.273 nd6.c
--- netinet6/nd6.c  2 May 2023 06:06:13 -   1.273
+++ netinet6/nd6.c  2 May 2023 18:44:23 -
@@ -1260,15 +1260,12 @@ nd6_resolve(struct ifnet *ifp, struct rt
return (0);
}
 
-   /* XXXSMP there is a MP race in nd6_resolve() */
-   KERNEL_LOCK();
uptime = getuptime();
rt = rt_getll(rt0);
 
if (ISSET(rt->rt_flags, RTF_REJECT) &&
(rt->rt_expire == 0 || rt->rt_expire > uptime)) {
m_freem(m);
-   KERNEL_UNLOCK();
return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
}
 
@@ -1291,6 +1288,11 @@ nd6_resolve(struct ifnet *ifp, struct rt
goto bad;
}
 
+   KERNEL_LOCK();
+   if (!ISSET(rt->rt_flags, RTF_LLINFO)) {
+   KERNEL_UNLOCK();
+   goto bad;
+   }
ln = (struct llinfo_nd6 *)rt->rt_llinfo;
KASSERT(ln != NULL);
 
@@ -1321,6 +1323,8 @@ nd6_resolve(struct ifnet *ifp, struct rt
 * send the packet.
 */
if (ln->ln_state > ND6_LLINFO_INCOMPLETE) {
+   KERNEL_UNLOCK();
+
sdl = satosdl(rt->rt_gateway);
if (sdl->sdl_alen != ETHER_ADDR_LEN) {
char addr[INET6_ADDRSTRLEN];
@@ -1332,7 +1336,6 @@ nd6_resolve(struct ifnet *ifp, struct rt
}
 
bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
-   KERNEL_UNLOCK();
return (0);
}
 
@@ -1374,7 +1377,6 @@ nd6_resolve(struct ifnet *ifp, struct rt
 
 bad:
m_freem(m);
-   KERNEL_UNLOCK();
return (EINVAL);
 }
 



usr.bin/mail: cmd3.c:bangexp(): "borked"?, and BSD fails POSIX compat

2023-05-02 Thread Steffen Nurpmeso
Hallo, and sorry for the cross-post, but so all in one (maybe) go.

This is about a niche "feature" of mail, the shell command "bang"
(! / ~! in compose mode):

  ? !echo no!bang
  no!bang
  !
  ? set bang
  ? ! echo no!bang
  !echo nobang
  nobang
  !
  ? ! !
  !echo nobang
  nobang
  !
  ? ! echo no!bang
  !echo noecho nobangbang
  noecho nobangbang
  !
  ?

In short: they all do it differently, and they all do it "wrong".

- Apple mail simply does not act unless "bang" is set: bangexp()
  simply returns.

- Free-, Net- and OpenBSD do not look for a "bang" variable at
  all, they simply do bang-style expansion whether that is set or
  not.

- V10 mailx (and the code i maintain) do some mix (expand the
  "last bang" only if "bang" is set, but know about \! escapes and
  such.

POSIX now says / will say

  If the bang variable is set, each unescaped occurrence of '!' in
  command shall be replaced with the command executed by the
  previous ! command or ˜! command escape.

thus

  - All commands entered for ! and ~! shall be stored.

  - If "bang" is set, an unquoted ! shall be replaced by that
storage.

The code everywhere is more or less what Kurt A. Shoens wrote as

  commit ae3dba0da2068b0de91ef163ea95fe774196a501
  Author: Kurt A. Schoens 
  AuthorDate: 1980-10-09 02:48:47 -0800
  Commit: Kurt A. Schoens 
  CommitDate: 1980-10-09 02:48:47 -0800

  Made shell escapes expand !'s to previous command

  SCCS-vsn: usr.bin/mail/cmd3.c 1.2

It will fail to properly "bang" a second time if some escaped
question mark was present in the first round,

while(*cp){
  ...
  if (*cp == '!') {
BANGEXP
...
continue;
  }
  ...
  if (*cp == '\\' && cp[1] == '!') {
  ...
  *cp2++ = '!';
  cp += 2;
  changed++;
[fallthru]
  }
  ...
  *cp2++ = *cp++;

and it stores and pushes through the second escape for "\!\!".

I am thinking of dropping this entirely, as it can properly work
only once if some escape took place, and i do not know how to fix
this the right way.  (And the line editor has history.)

--steffen
|
|Der Kragenbaer,The moon bear,
|der holt sich munter   he cheerfully and one by one
|einen nach dem anderen runter  wa.ks himself off
|(By Robert Gernhardt)
|~~
|..and in spring, hear David Leonard sing..
|
|The black bear,  The black bear,
|blithely holds his own   holds himself at leisure
|beating it, up and down  tossing over his ups and downs with pleasure
|~~
|Farewell, dear collar bear



rpki-client 8.4 released

2023-05-02 Thread Sebastian Benoit
rpki-client 8.4 has just been released and will be available in the
rpki-client directory of any OpenBSD mirror soon.

rpki-client is a FREE, easy-to-use implementation of the Resource
Public Key Infrastructure (RPKI) for Relying Parties (RP) to
facilitate validation of BGP announcements. The program queries the
global RPKI repository system and validates untrusted network inputs.
The program outputs validated ROA payloads, BGPsec Router keys, and
ASPA payloads in configuration formats suitable for OpenBGPD and BIRD,
and supports emitting CSV and JSON for consumption by other routing
stacks.

See RFC 6480 and RFC 6811 for a description of how RPKI and BGP Prefix
Origin Validation help secure the global Internet routing system.

rpki-client was primarily developed by Kristaps Dzonsons, Claudio
Jeker, Job Snijders, Theo Buehler, Theo de Raadt and Sebastian Benoit
as part of the OpenBSD Project.

This release includes the following changes to the previous release:

- The synchronisation protocol used to sync the repository is now
  included in the OpenMetrics output.

- In filemode (-f option) the applicable manifests are now shown as
  part of the signature path.

- A new -P option was added to manually specify a moment in time
  to use when parsing the validity window of certificates. Useful
  for regression testing. Default is invocation time of rpki-client.

- The -A option will now also exclude ASPA data from the JSON output.

- Improved accounting by tracking objects both by repo and tal.

- For consistency, emit an explicit 'AS 0' Provider entry for ASPAs
  containing implicit information for one AFI.

- Fix missing whitespace in ASPA-set output for OpenBGPD.
  (This bugfix was also released as OpenBSD 7.3 errata 001.)

- Disallow X.509 v2 issuer and subject unique identifiers in certs.
  RPKI CAs will never issue certificates with V2 unique identifiers.

- Check whether products listed on a manifest were issued by the same
  authority as the manifest itself.

rpki-client works on all operating systems with a libcrypto library
based on OpenSSL 1.1 or LibreSSL 3.5, and a libtls library compatible
with LibreSSL 3.5 or later.

rpki-client is known to compile and run on at least the following
operating systems: Alpine, CentOS, Debian, Fedora, FreeBSD, Red Hat,
Rocky, Ubuntu, macOS, and of course OpenBSD!

It is our hope that packagers take interest and help adapt
rpki-client-portable to more distributions.

The mirrors where rpki-client can be found are on
https://www.rpki-client.org/portable.html

Reporting Bugs:
===

General bugs may be reported to tech@openbsd.org

Portable bugs may be filed at
https://github.com/rpki-client/rpki-client-portable

We welcome feedback and improvements from the broader community.
Thanks to all of the contributors who helped make this release
possible.

Assistance to coordinate security issues is available via
secur...@openbsd.org.



nd6 mutex

2023-05-02 Thread Alexander Bluhm
Hi,

I would like to introduce an neighbor discovery mutex like ARP uses
it.  Note that this does not unlock nd6 form kernel lock yet, this
will be done in some follow up diffs.

Lockless lookup in the hot path for ND6 will be harder than ARP as
ln_state is always checked.  Anyway let's get closer to that goal
in small steps.

ok?

bluhm

Index: netinet6/nd6.c
===
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.273
diff -u -p -r1.273 nd6.c
--- netinet6/nd6.c  2 May 2023 06:06:13 -   1.273
+++ netinet6/nd6.c  2 May 2023 14:41:14 -
@@ -62,6 +62,15 @@
 #include 
 #include 
 
+/*
+ * Locks used to protect struct members in this file:
+ * a   atomic operations
+ * I   immutable after creation
+ * K   kernel lock
+ * m   nd6 mutex, needed when net lock is shared
+ * N   net lock
+ */
+
 #define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */
 #define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */
 
@@ -84,9 +93,13 @@ int nd6_debug = 1;
 int nd6_debug = 0;
 #endif
 
-TAILQ_HEAD(llinfo_nd6_head, llinfo_nd6) nd6_list;
-struct pool nd6_pool;  /* pool for llinfo_nd6 structures */
-intnd6_inuse;
+/* llinfo_nd6 live time, rt_llinfo and RTF_LLINFO are protected by nd6_mtx */
+struct mutex nd6_mtx = MUTEX_INITIALIZER(IPL_SOFTNET);
+
+TAILQ_HEAD(llinfo_nd6_head, llinfo_nd6) nd6_list =
+TAILQ_HEAD_INITIALIZER(nd6_list);  /* [mN] list of llinfo_nd6 structures */
+struct pool nd6_pool;  /* [I] pool for llinfo_nd6 structures */
+intnd6_inuse;  /* [m] limit neigbor discovery routes */
 unsigned int   ln_hold_total;  /* [a] packets currently in the nd6 queue */
 
 void nd6_timer(void *);
@@ -105,7 +118,6 @@ struct task nd6_expire_task;
 void
 nd6_init(void)
 {
-   TAILQ_INIT(_list);
pool_init(_pool, sizeof(struct llinfo_nd6), 0,
IPL_SOFTNET, 0, "nd6", NULL);
 
@@ -259,6 +271,7 @@ nd6_timer(void *unused)
uptime = getuptime();
expire = uptime + nd6_gctimer;
 
+   /* Net lock is exclusive, no nd6 mutex needed for nd6_list here. */
TAILQ_FOREACH_SAFE(ln, _list, ln_list, nln) {
struct rtentry *rt = ln->ln_rt;
 
@@ -465,7 +478,7 @@ nd6_purge(struct ifnet *ifp)
 {
struct llinfo_nd6 *ln, *nln;
 
-   NET_ASSERT_LOCKED();
+   NET_ASSERT_LOCKED_EXCLUSIVE();
 
/*
 * Nuke neighbor cache entries for the ifp.
@@ -627,13 +640,20 @@ nd6_is_addr_neighbor(const struct sockad
 void
 nd6_invalidate(struct rtentry *rt)
 {
-   struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo;
+   struct llinfo_nd6 *ln;
struct sockaddr_dl *sdl = satosdl(rt->rt_gateway);
 
+   mtx_enter(_mtx);
+   ln = (struct llinfo_nd6 *)rt->rt_llinfo;
+   if (ln == NULL) {
+   mtx_leave(_mtx);
+   return;
+   }
atomic_sub_int(_hold_total, mq_purge(>ln_mq));
sdl->sdl_alen = 0;
ln->ln_state = ND6_LLINFO_INCOMPLETE;
ln->ln_asked = 0;
+   mtx_leave(_mtx);
 }
 
 /*
@@ -804,20 +824,26 @@ nd6_rtrequest(struct ifnet *ifp, int req
}
satosdl(gate)->sdl_type = ifp->if_type;
satosdl(gate)->sdl_index = ifp->if_index;
-   if (ln != NULL)
-   break;  /* This happens on a route change */
/*
 * Case 2: This route may come from cloning, or a manual route
 * add with a LL address.
 */
ln = pool_get(_pool, PR_NOWAIT | PR_ZERO);
-   rt->rt_llinfo = (caddr_t)ln;
if (ln == NULL) {
log(LOG_DEBUG, "%s: pool get failed\n", __func__);
break;
}
-   mq_init(>ln_mq, LN_HOLD_QUEUE, IPL_SOFTNET);
+
+   mtx_enter(_mtx);
+   if (rt->rt_llinfo != NULL) {
+   /* we lost the race, another thread has entered it */
+   mtx_leave(_mtx);
+   pool_put(_pool, ln);
+   break;
+   }
nd6_inuse++;
+   mq_init(>ln_mq, LN_HOLD_QUEUE, IPL_SOFTNET);
+   rt->rt_llinfo = (caddr_t)ln;
ln->ln_rt = rt;
/* this is required for "ndp" command. - shin */
if (req == RTM_ADD) {
@@ -838,6 +864,7 @@ nd6_rtrequest(struct ifnet *ifp, int req
}
rt->rt_flags |= RTF_LLINFO;
TAILQ_INSERT_HEAD(_list, ln, ln_list);
+   mtx_leave(_mtx);
 
/*
 * If we have too many cache entries, initiate immediate
@@ -850,6 +877,7 @@ nd6_rtrequest(struct ifnet *ifp, int req
nd6_inuse >= ip6_neighborgcthresh) {
int i;
 
+   mtx_enter(_mtx);
   

Re: rpki-client json.c add json_do_string()

2023-05-02 Thread Claudio Jeker
On Tue, May 02, 2023 at 09:34:43AM -0600, Todd C. Miller wrote:
> On Tue, 02 May 2023 14:13:27 +0200, Claudio Jeker wrote:
> 
> > Add a json_do_string() a function to print a JSON string.
> > This function does the needed encoding of control chars and escape chars.
> > I skipped the optional encoding of the forward slash (/) since this is
> > only needed if the json output is embedded in HTML/SGML/XML.
> > People putting JSON into such documents need to pass this through an extra
> > step.
> 
> Unless you can guarantee that other control characters cannot occur
> you probably want to output them in unicode hex form.  For example,
> something like:
> 
> default:
>   const char hex[] = "0123456789abcdef";
>   if (iscntrl(c)) {
>   /* Escape control characters like \u */
>   if (!eb)
>   eb = fprintf(jsonfh, "\\u00%c%c", hex[c >> 4],
>   hex[c & 0x0f]) < 0;
>   }

I think this is not really needed. All strings are previously checked for
any bad characters. In general I think covering more than \n, \r and \t makes
little sense (but I added the other ones just for completeness).
Maybe the best is to check but error out for iscntrl(c).
 
> In this case you probably want to assign c as an unsigned char.
> E.g.
> 
> while ((c = (unsigned char)*v++) != '\0') {
>   ...
> }
> 
> Or better yet just declare c as unsigned char instead of int.

Good point. I guess it is better to use unsigned char here.

-- 
:wq Claudio



Re: rpki-client json.c add json_do_string()

2023-05-02 Thread Todd C . Miller
On Tue, 02 May 2023 14:13:27 +0200, Claudio Jeker wrote:

> Add a json_do_string() a function to print a JSON string.
> This function does the needed encoding of control chars and escape chars.
> I skipped the optional encoding of the forward slash (/) since this is
> only needed if the json output is embedded in HTML/SGML/XML.
> People putting JSON into such documents need to pass this through an extra
> step.

Unless you can guarantee that other control characters cannot occur
you probably want to output them in unicode hex form.  For example,
something like:

default:
const char hex[] = "0123456789abcdef";
if (iscntrl(c)) {
/* Escape control characters like \u */
if (!eb)
eb = fprintf(jsonfh, "\\u00%c%c", hex[c >> 4],
hex[c & 0x0f]) < 0;
}

In this case you probably want to assign c as an unsigned char.
E.g.

while ((c = (unsigned char)*v++) != '\0') {
...
}

Or better yet just declare c as unsigned char instead of int.

 - todd



Re: rpki-client json.c add json_do_string()

2023-05-02 Thread Theo Buehler
On Tue, May 02, 2023 at 02:41:52PM +0200, Claudio Jeker wrote:
> On Tue, May 02, 2023 at 02:29:20PM +0200, Theo Buehler wrote:
> > On Tue, May 02, 2023 at 02:13:27PM +0200, Claudio Jeker wrote:
> > > Add a json_do_string() a function to print a JSON string.
> > > This function does the needed encoding of control chars and escape chars.
> > > I skipped the optional encoding of the forward slash (/) since this is
> > > only needed if the json output is embedded in HTML/SGML/XML.
> > > People putting JSON into such documents need to pass this through an extra
> > > step.
> > > 
> > > This implements json_do_printf() now as a wrapper around json_do_string().
> > > All users of json_do_printf(name, "%s", value) can be converted to
> > > json_do_string(). I will do this is a subsequent step.
> > 
> > I'm ok with this. Some comments below.
> 
> How about this version? By moving the !eb check into the while loop the
> if checks fall away and so it is just one fprintf() per case. I think
> trying to optimize this further is not that benefitial. I wonder if the
> compiler wont do that better anyway.

Agreed. ok



Re: rpki-client json.c add json_do_string()

2023-05-02 Thread Claudio Jeker
On Tue, May 02, 2023 at 02:29:20PM +0200, Theo Buehler wrote:
> On Tue, May 02, 2023 at 02:13:27PM +0200, Claudio Jeker wrote:
> > Add a json_do_string() a function to print a JSON string.
> > This function does the needed encoding of control chars and escape chars.
> > I skipped the optional encoding of the forward slash (/) since this is
> > only needed if the json output is embedded in HTML/SGML/XML.
> > People putting JSON into such documents need to pass this through an extra
> > step.
> > 
> > This implements json_do_printf() now as a wrapper around json_do_string().
> > All users of json_do_printf(name, "%s", value) can be converted to
> > json_do_string(). I will do this is a subsequent step.
> 
> I'm ok with this. Some comments below.

How about this version? By moving the !eb check into the while loop the
if checks fall away and so it is just one fprintf() per case. I think
trying to optimize this further is not that benefitial. I wonder if the
compiler wont do that better anyway.

-- 
:wq Claudio

Index: json.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/json.c,v
retrieving revision 1.1
diff -u -p -r1.1 json.c
--- json.c  27 Apr 2023 07:57:25 -  1.1
+++ json.c  2 May 2023 12:39:36 -
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "json.h"
@@ -179,16 +180,56 @@ void
 json_do_printf(const char *name, const char *fmt, ...)
 {
va_list ap;
+   char *str;
 
-   do_comma_indent();
+   va_start(ap, fmt);
+   if (!eb) {
+   if (vasprintf(, fmt, ap) == -1)
+   errx(1, "json printf failed");
+   json_do_string(name, str);
+   free(str);
+   }
+   va_end(ap);
+}
 
+void
+json_do_string(const char *name, const char *v)
+{
+   int c;
+
+   do_comma_indent();
do_name(name);
if (!eb)
eb = fprintf(jsonfh, "\"") < 0;
-   va_start(ap, fmt);
-   if (!eb)
-   eb = vfprintf(jsonfh, fmt, ap) < 0;
-   va_end(ap);
+   while ((c = *v++) != '\0' && !eb) {
+   /* skip escaping '/' since our use case does not require it */
+   switch(c) {
+   case '"':
+   eb = fprintf(jsonfh, "\\\"") < 0;
+   break;
+   case '\\':
+   eb = fprintf(jsonfh, "") < 0;
+   break;
+   case '\b':
+   eb = fprintf(jsonfh, "\\b") < 0;
+   break;
+   case '\f':
+   eb = fprintf(jsonfh, "\\f") < 0;
+   break;
+   case '\n':
+   eb = fprintf(jsonfh, "\\n") < 0;
+   break;
+   case '\r':
+   eb = fprintf(jsonfh, "\\r") < 0;
+   break;
+   case '\t':
+   eb = fprintf(jsonfh, "\\t") < 0;
+   break;
+   default:
+   eb = putc(c, jsonfh) == EOF;
+   break;
+   }
+   }
if (!eb)
eb = fprintf(jsonfh, "\"") < 0;
 }
Index: json.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/json.h,v
retrieving revision 1.1
diff -u -p -r1.1 json.h
--- json.h  27 Apr 2023 07:57:25 -  1.1
+++ json.h  30 Apr 2023 15:11:36 -
@@ -26,6 +26,7 @@ void  json_do_object(const char *);
 void   json_do_end(void);
 void   json_do_printf(const char *, const char *, ...)
__attribute__((__format__ (printf, 2, 3)));
+void   json_do_string(const char *, const char *);
 void   json_do_hexdump(const char *, void *, size_t);
 void   json_do_bool(const char *, int);
 void   json_do_uint(const char *, unsigned long long);



Re: rpki-client json.c add json_do_string()

2023-05-02 Thread Theo Buehler
On Tue, May 02, 2023 at 02:13:27PM +0200, Claudio Jeker wrote:
> Add a json_do_string() a function to print a JSON string.
> This function does the needed encoding of control chars and escape chars.
> I skipped the optional encoding of the forward slash (/) since this is
> only needed if the json output is embedded in HTML/SGML/XML.
> People putting JSON into such documents need to pass this through an extra
> step.
> 
> This implements json_do_printf() now as a wrapper around json_do_string().
> All users of json_do_printf(name, "%s", value) can be converted to
> json_do_string(). I will do this is a subsequent step.

I'm ok with this. Some comments below.

> -- 
> :wq Claudio
> 
> Index: json.c
> ===
> RCS file: /cvs/src/usr.sbin/rpki-client/json.c,v
> retrieving revision 1.1
> diff -u -p -r1.1 json.c
> --- json.c27 Apr 2023 07:57:25 -  1.1
> +++ json.c1 May 2023 20:07:26 -
> @@ -19,6 +19,7 @@
>  #include 
>  #include 
>  #include 
> +#include 

I'd move this below stdio.h

>  #include 
>  #include 
>  
> @@ -179,16 +180,64 @@ void
>  json_do_printf(const char *name, const char *fmt, ...)
>  {
>   va_list ap;
> + char *str;
>  
> - do_comma_indent();
> + va_start(ap, fmt);
> + if (!eb) {
> + if (vasprintf(, fmt, ap) == -1)
> + errx(1, "json printf failed");
> + json_do_string(name, str);
> + free(str);
> + }
> + va_end(ap);
> +}
>  
> +void
> +json_do_string(const char *name, const char *v)
> +{
> + int c;
> +
> + do_comma_indent();
>   do_name(name);
>   if (!eb)
>   eb = fprintf(jsonfh, "\"") < 0;
> - va_start(ap, fmt);
> - if (!eb)
> - eb = vfprintf(jsonfh, fmt, ap) < 0;
> - va_end(ap);
> + while ((c = *v++) != '\0') {

Should this include && !eb?


> + /* skip escaping '/' since our use case does not require it */
> + switch(c) {
> + case '"':
> + if (!eb)
> + eb = fprintf(jsonfh, "\\\"") < 0;

It's fine as it is, but the repetition could be avoided by assigning the
escaped string or c to a temporary variable and do the printing after
the switch. Your call.

> + break;
> + case '\\':
> + if (!eb)
> + eb = fprintf(jsonfh, "") < 0;
> + break;
> + case '\b':
> + if (!eb)
> + eb = fprintf(jsonfh, "\\b") < 0;
> + break;
> + case '\f':
> + if (!eb)
> + eb = fprintf(jsonfh, "\\f") < 0;
> + break;
> + case '\n':
> + if (!eb)
> + eb = fprintf(jsonfh, "\\n") < 0;
> + break;
> + case '\r':
> + if (!eb)
> + eb = fprintf(jsonfh, "\\r") < 0;
> + break;
> + case '\t':
> + if (!eb)
> + eb = fprintf(jsonfh, "\\t") < 0;
> + break;
> + default:
> + if (!eb)
> + eb = putc(c, jsonfh) == EOF;
> + break;
> + }
> + }
>   if (!eb)
>   eb = fprintf(jsonfh, "\"") < 0;
>  }
> Index: json.h
> ===
> RCS file: /cvs/src/usr.sbin/rpki-client/json.h,v
> retrieving revision 1.1
> diff -u -p -r1.1 json.h
> --- json.h27 Apr 2023 07:57:25 -  1.1
> +++ json.h30 Apr 2023 15:11:36 -
> @@ -26,6 +26,7 @@ voidjson_do_object(const char *);
>  void json_do_end(void);
>  void json_do_printf(const char *, const char *, ...)
>   __attribute__((__format__ (printf, 2, 3)));
> +void json_do_string(const char *, const char *);
>  void json_do_hexdump(const char *, void *, size_t);
>  void json_do_bool(const char *, int);
>  void json_do_uint(const char *, unsigned long long);
> 



rpki-client json.c add json_do_string()

2023-05-02 Thread Claudio Jeker
Add a json_do_string() a function to print a JSON string.
This function does the needed encoding of control chars and escape chars.
I skipped the optional encoding of the forward slash (/) since this is
only needed if the json output is embedded in HTML/SGML/XML.
People putting JSON into such documents need to pass this through an extra
step.

This implements json_do_printf() now as a wrapper around json_do_string().
All users of json_do_printf(name, "%s", value) can be converted to
json_do_string(). I will do this is a subsequent step.

-- 
:wq Claudio

Index: json.c
===
RCS file: /cvs/src/usr.sbin/rpki-client/json.c,v
retrieving revision 1.1
diff -u -p -r1.1 json.c
--- json.c  27 Apr 2023 07:57:25 -  1.1
+++ json.c  1 May 2023 20:07:26 -
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -179,16 +180,64 @@ void
 json_do_printf(const char *name, const char *fmt, ...)
 {
va_list ap;
+   char *str;
 
-   do_comma_indent();
+   va_start(ap, fmt);
+   if (!eb) {
+   if (vasprintf(, fmt, ap) == -1)
+   errx(1, "json printf failed");
+   json_do_string(name, str);
+   free(str);
+   }
+   va_end(ap);
+}
 
+void
+json_do_string(const char *name, const char *v)
+{
+   int c;
+
+   do_comma_indent();
do_name(name);
if (!eb)
eb = fprintf(jsonfh, "\"") < 0;
-   va_start(ap, fmt);
-   if (!eb)
-   eb = vfprintf(jsonfh, fmt, ap) < 0;
-   va_end(ap);
+   while ((c = *v++) != '\0') {
+   /* skip escaping '/' since our use case does not require it */
+   switch(c) {
+   case '"':
+   if (!eb)
+   eb = fprintf(jsonfh, "\\\"") < 0;
+   break;
+   case '\\':
+   if (!eb)
+   eb = fprintf(jsonfh, "") < 0;
+   break;
+   case '\b':
+   if (!eb)
+   eb = fprintf(jsonfh, "\\b") < 0;
+   break;
+   case '\f':
+   if (!eb)
+   eb = fprintf(jsonfh, "\\f") < 0;
+   break;
+   case '\n':
+   if (!eb)
+   eb = fprintf(jsonfh, "\\n") < 0;
+   break;
+   case '\r':
+   if (!eb)
+   eb = fprintf(jsonfh, "\\r") < 0;
+   break;
+   case '\t':
+   if (!eb)
+   eb = fprintf(jsonfh, "\\t") < 0;
+   break;
+   default:
+   if (!eb)
+   eb = putc(c, jsonfh) == EOF;
+   break;
+   }
+   }
if (!eb)
eb = fprintf(jsonfh, "\"") < 0;
 }
Index: json.h
===
RCS file: /cvs/src/usr.sbin/rpki-client/json.h,v
retrieving revision 1.1
diff -u -p -r1.1 json.h
--- json.h  27 Apr 2023 07:57:25 -  1.1
+++ json.h  30 Apr 2023 15:11:36 -
@@ -26,6 +26,7 @@ void  json_do_object(const char *);
 void   json_do_end(void);
 void   json_do_printf(const char *, const char *, ...)
__attribute__((__format__ (printf, 2, 3)));
+void   json_do_string(const char *, const char *);
 void   json_do_hexdump(const char *, void *, size_t);
 void   json_do_bool(const char *, int);
 void   json_do_uint(const char *, unsigned long long);