On 2022/02/10 08:42, Marc Espie wrote:
> On Wed, Feb 09, 2022 at 07:30:46PM -0800, Andrew Hewus Fresh wrote:
> > I was reminded that fw_update(8) updates the package database without
> > locking currently.  That can cause issues when running it concurrently
> > with pkg_add, for example starting `pkg_add -u` in one terminal and
> > `sysupgrade` in another.
> > 
> > This diff checks to see if perl is available and if so starts a perl
> > co-process that locks the database and then kills it when exiting.
> > 
> > (Figuring out how to wait for the lock to be acquired and find out the
> > pid of the co-process was a bit of a challenge, so if someone has a
> > suggestion on improving that, I'm open to suggestions)
> > 
> > Comments, OK?
> > 
> > 
> > Index: usr.sbin/fw_update/fw_update.sh
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/fw_update/fw_update.sh,v
> > retrieving revision 1.36
> > diff -u -p -r1.36 fw_update.sh
> > --- usr.sbin/fw_update/fw_update.sh 10 Feb 2022 00:29:32 -0000      1.36
> > +++ usr.sbin/fw_update/fw_update.sh 10 Feb 2022 03:22:20 -0000
> > @@ -42,11 +42,13 @@ INSTALL=true
> >  LOCALSRC=
> >  
> >  unset FTPPID
> > +unset LOCKPID
> >  unset FWPKGTMP
> >  REMOVE_LOCALSRC=false
> >  cleanup() {
> >     set +o errexit # ignore errors from killing ftp
> >     [ "${FTPPID:-}" ] && kill -TERM -"$FTPPID" 2>/dev/null
> > +   [ "${LOCKPID:-}" ] && kill -TERM -"$LOCKPID" 2>/dev/null
> >     [ "${FWPKGTMP:-}" ] && rm -rf "$FWPKGTMP"
> >     "$REMOVE_LOCALSRC" && rm -rf "$LOCALSRC"
> >     [ -e "${CFILE}" ] && [ ! -s "$CFILE" ] && rm -f "$CFILE"
> > @@ -194,6 +196,36 @@ firmware_devicename() {
> >     echo "$_d"
> >  }
> >  
> > +lock_db() {
> > +   [ "${LOCKPID:-}" ] && return 0
> > +
> > +   # The installer doesn't have perl, so we can't lock there
> > +   [ -e /usr/bin/perl ] || return 0
> > +
> > +   set -o monitor
> > +   perl <<'EOL' |&
> > +           use v5.16;
> > +           use warnings;
> > +           use OpenBSD::PackageInfo qw< lock_db unlock_db >;
> > +           use OpenBSD::State;
> > +
> > +           $|=1;
> > +
> > +           lock_db(0, OpenBSD::State->new);
> > +           END { unlock_db }
> > +           $SIG{TERM} = sub { exit };
> > +   
> > +           say $$;
> > +           sleep;
> > +EOL
> > +   set +o monitor
> > +
> > +   read -rp LOCKPID
> > +
> > +   return 0
> > +}
> > +
> > +
> >  installed_firmware() {
> >     local _pre="$1" _match="$2" _post="$3" _firmware _fw
> >     set -sA _firmware -- $(
> > @@ -401,6 +433,7 @@ set -sA devices -- "$@"
> >  
> >  if "$DELETE"; then
> >     [ "$OPT_F" ] && echo "Cannot use -F and -d" >&2 && usage
> > +   lock_db
> >  
> >     # Show the "Uninstall" message when just deleting not upgrading
> >     ((VERBOSE)) && VERBOSE=3
> > @@ -463,6 +496,8 @@ else
> >  fi
> >  
> >  [ "${devices[*]:-}" ] || exit
> > +
> > +lock_db
> >  
> >  added=''
> >  updated=''
> > 
> It's one of the cases where you can actually use the newer OpenBSD::BaseState
> where I explicitly split the printing and system functions.
> 
> e.g.,
> use OpenBSD::BaseState;
> 
> lock_db(0, 'OpenBSD::BaseState');
> should work just as well
> 

That also works for me.

Reply via email to