Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use "rm" instead of "unlink" to delete old config file #2504

Merged
merged 1 commit into from
Dec 9, 2023

Conversation

oe7drt
Copy link
Contributor

@oe7drt oe7drt commented Dec 8, 2023

this actually let me run the p10k configure script on OpenBSD which aborts with generate_config:250: command not found: unlink otherwise.

tested on PopOS/Ubuntu but rm should also be available on any linux distribution?

@romkatv
Copy link
Owner

romkatv commented Dec 8, 2023

Wow. OpenBSD is missing a mandatory POSIX utility? Do you know why and since when?

@romkatv
Copy link
Owner

romkatv commented Dec 8, 2023

I think I've found the answer: unlink is marked as an XSI extension in POSIX and OpenBSD does not claim to implement XSI.

I'll take a closer look at the suggested change (and merge it if possible) when I get back to my dev machine. Thanks for sending the PR!

@romkatv romkatv merged commit 3cc18b5 into romkatv:master Dec 9, 2023
romkatv added a commit that referenced this pull request Dec 9, 2023
@romkatv
Copy link
Owner

romkatv commented Dec 9, 2023

Merged. Thanks again!

@oe7drt
Copy link
Contributor Author

oe7drt commented Dec 9, 2023

Wow. OpenBSD is missing a mandatory POSIX utility? Do you know why and since when?

I'm no expert and I only looked into the base72 and base73 file sets additionally to the running base74 file sets but none included an unlink binary, but we have a manpage about the system call unlink(2) on the system.

Also some manual steps are needed to make it work as the prompt usually prints

[ERROR]: gitstatus failed to initialize.

There is no prebuilt gitstatusd for openbsd amd64.

See: https://github.com/romkatv/gitstatus#compiling

I will leave this comment here, if someone should encounter the same problems as I did, this is how I finally got this working on my box:

First I cloned the gitstatus repo into a fresh directory. I then went to your libgit2 repository and downloaded the latest tar.gz archive into gitstatus/deps and in the gitstatus repository I ran bash ./build because it quits with ./build[441]: formula: parameter not set when run from zsh with ./build

$ git clone --depth=1 https://github.com/romkatv/gitstatus.git

$ cd gitstatus

$ cp ~/Downloads/libgit2-tag-* deps/

$ bash ./build

$ cp usrbin/gitstatusd ~/.zprezto/modules/prompt/external/powerlevel10k/gitstatus/usrbin/

I bet there is an easier way to obtain these results, but I wasn't able to get this thing running...

bash is also not in base, needs to be installed first doas pkg_add bash.

Sorry for the late reply, you answered yourself a few times meanwhile, I had a longer night today :)

@romkatv
Copy link
Owner

romkatv commented Dec 9, 2023

./build fails on your system because of a bug in sh. See romkatv/gitstatus#208 (comment). If you are feeling generous, perhaps you could verify that the bug indeed reproduces with the script from the linked comment (please read that comment and the ones below), reduce it to the shortest possible script and submit a bug against OpenBSD. If you do, please post a link to the bug report here.

Given that you already have zsh, you could use that instead of sh to run ./build. Does the following work?

cd ~/.zprezto/modules/prompt/external/powerlevel10k/gitstatus
rm usrbin/gitstatusd
zsh ./build -w

You can also use bash instead of zsh in there. Any POSIX-compliant interpreter will do.

@romkatv
Copy link
Owner

romkatv commented Dec 9, 2023

I've found another relevant issue: romkatv/gitstatus#282. I think it's better than what I've linked before.

The person filing that issue told me that /bin/sh is ksh on OpenBSD, so I added a clause to build to use an alternative interpreter if someone attempt to use ksh. Apparently, it didn't work for you. What is the output of the following command?

/bin/sh -c 'printf "%s\n" "${KSH_VERSION-unset}"'

If it says "unset", can you try to figure out what /bin/sh is?

@oe7drt
Copy link
Contributor Author

oe7drt commented Dec 9, 2023

Given that you already have zsh, you could use that instead of sh to run ./build. Does the following work?

cd ~/.zprezto/modules/prompt/external/powerlevel10k/gitstatus
rm usrbin/gitstatusd
zsh ./build -w

You can also use bash instead of zsh in there. Any POSIX-compliant interpreter will do.

zsh ./build -w works. I've not used ksh before, my default shell is zsh usually with prezto, so the ./build was done with zsh -- but this also happens when I try with ksh -l; ./build.; same error message.

I've found another relevant issue: romkatv/gitstatus#282. I think it's better than what I've linked before.

The person filing that issue told me that /bin/sh is ksh on OpenBSD, so I added a clause to build to use an alternative interpreter if someone attempt to use ksh. Apparently, it didn't work for you. What is the output of the following command?

/bin/sh -c 'printf "%s\n" "${KSH_VERSION-unset}"'

If it says "unset", can you try to figure out what /bin/sh is?

It says unset, right. The manual of sh(1) shows:

 This version of sh is actually ksh in disguise.  As such, it also
 supports the features described in ksh(1).  This manual page describes
 only the parts relevant to a POSIX compliant sh.  If portability is a
 concern, use only those features described in this page.

I've also looked at the sources but cannot find files similar to sh.c or kind of. Finally the Makefile of ksh makes me think they are "linked", at least this looks like it to me.
https://github.com/openbsd/src/blob/master/bin/ksh/Makefile

The script you mentioned above (lines 1-329) do return 0 with zsh and bash. They return 1 with sh and ksh.

$ /bin/sh -c 'printf "%s\n" "${KSH_VERSION-unset}"'
unset

$ /bin/ksh -c 'printf "%s\n" "${KSH_VERSION-unset}"'
@(#)PD KSH v5.2.14 99/07/13.2

The smaller script from above

#!/bin/sh

set -u

cat <<\END
$formula
END

prints $formula all the time, if run via ./script or sh ./script or bash ./script or ksh script or zsh script (with or without leading ./).

Hope that helps

@romkatv
Copy link
Owner

romkatv commented Dec 9, 2023

my default shell is zsh usually with prezto, so the ./build was done with zsh

When you run ./build in zsh, it looks at the top of the file, finds #!/bin/sh in there and executes /bin/sh ./build for you. It does not attempt to interpret the file with zsh. ./build fails for you and zsh ./build succeeds because /bin/sh has a particular bug that zsh does not have.

The script you mentioned above (lines 1-329) do return 0 with zsh and bash. They return 1 with sh and ksh.

Thanks. This confirms that both sh and ksh have this particular bug. Could you reduce the 329-line script to the shortest possible and submit a bug against OpenBSD? It should not take you long to reduce the script. You can start with this:

build.txt

If sh fails on this script, you are almost done. If you look inside, you'll see the following:

#!/bin/sh

set -ue

build="$(command cat <<\END
blah
...
blah
END
)"

For a conformant sh the content that I snipped as blah ... blah is irrelevant. The only thing that matters is that none of those lines are literally END. Try to delete as many of those lines as possible while still having sh fail to interpret this file. Binary search is your friend here: delete the first half of those lines, see if sh fails, etc. If you could post the end result here for me to see before filing a bug against OpenBSD, that would be best.

This version of sh is actually ksh in disguise.

Awwww. The "disguise" apparently consists of unsetting KSH_VERSION, which prevents us from detecting this interpreter and employing a workaround.

@oe7drt
Copy link
Contributor Author

oe7drt commented Dec 9, 2023

my default shell is zsh usually with prezto, so the ./build was done with zsh

When you run ./build in zsh, it looks at the top of the file, finds #!/bin/sh in there and executes /bin/sh ./build for you. It does not attempt to interpret the file with zsh.

I just sank under the floor. Of course I know the shebang in scripts. I sometimes tend to ignore the obvious :D

The script you mentioned above (lines 1-329) do return 0 with zsh and bash. They return 1 with sh and ksh.

Thanks. This confirms that both sh and ksh have this particular bug. Could you reduce the 329-line script to the shortest possible and submit a bug against OpenBSD? It should not take you long to reduce the script. You can start with this:

build.txt

If sh fails on this script, you are almost done. If you look inside, you'll see the following:

#!/bin/sh

set -ue

build="$(command cat <<\END
blah
...
blah
END
)"

For a conformant sh the content that I snipped as blah ... blah is irrelevant. The only thing that matters is that none of those lines are literally END. Try to delete as many of those lines as possible while still having sh fail to interpret this file. Binary search is your friend here: delete the first half of those lines, see if sh fails, etc. If you could post the end result here for me to see before filing a bug against OpenBSD, that would be best.

Okay I deleted almost everything out, the resulting file is

#!/bin/sh

set -ue

build="$(command cat <<\END

case "$resp" in
  hello*0*);;
  *)
    >&2 echo 'error: invalid gitstatusd response for a non-repo'
    exit 1
  ;;
esac

END
)"

It still fails with only

#!/bin/sh

set -ue

build="$(command cat <<\END

case "$resp" in
  *)
    >&2 echo 'error: invalid gitstatusd response for a non-repo'
    exit 1
  ;;
esac

END
)"

as well as with

#!/bin/sh

set -ue

build="$(command cat <<\END

case "$resp" in
  hello*0*);;
esac

END
)"

both error messages are ./build: here document `END' unclosed

This particular/other error message appears when I reduce the blocks with the unknown variables until the script looks like this:

#!/bin/sh

set -ue

build="$(command cat <<\END
outdir="$(command pwd)"

narg() { echo $#; }

appname=gitstatusd
libgit2_tmp="$outdir"/deps/"$appname".libgit2.tmp

cleanup()
trap cleanup INT QUIT TERM ILL PIPE

cpus="$(command getconf _NPROCESSORS_ONLN 2>/dev/null)" ||
  cpus="$(command sysctl -n hw.ncpu 2>/dev/null)" ||
  cpus=8

libgit2_cmake_flags=
libgit2_cflags="$ $cflags -O3 -DNDEBUG"

for cmd in cat cmake git ld ln mkdir rm strip tar "$gitstatus_make"; do
  if ! command -v "$cmd" >/dev/null 2>&1; then
    if [ -n "$gitstatus_install_tools" ]; then
      >&2 echo "[internal error] $cmd not found"
      exit 1
    else
      >&2 echo "[error] command not found: $cmd"
      exit 1
    fi
  fi
done

. "$outdir"/build.info
if [ -z "${libgit2_version:-}" ]; then
  >&2 echo "[internal error] libgit2_version not set"
  exit 1
fi
if [ -z "${libgit2_sha256:-}" ]; then
  >&2 echo "[internal error] libgit2_sha256 not set"
  exit 1
fi
libgit2_tarball="$outdir"/deps/libgit2-"$libgit2_version".tar.gz
if [ ! -e "$libgit2_tarball" ]; then
  if [ -n "$gitstatus_download_deps" ]; then
    if ! command -v wget >/dev/null 2>&1; then
      if [ -n "$gitstatus_install_tools" ]; then
        >&2 echo "[internal error] wget not found"
        exit 1
      else
        >&2 echo "[error] command not found: wget"
        exit 1
      fi
    fi
    libgit2_url=https://github.com/romkatv/libgit2/archive/"$libgit2_version".tar.gz
    if ! >"$libgit2_tmp" command wget --no-config -qO- -- "$libgit2_url" &&
       ! >"$libgit2_tmp" command wget             -qO- -- "$libgit2_url"; then
      set -x
      >&2 command which wget
      >&2 command ls -lAd -- "$(command which wget)"
      >&2 command ls -lAd -- "$outdir"
      >&2 command ls -lA -- "$outdir"
      >&2 command ls -lAd -- "$outdir"/deps
      >&2 command ls -lA -- "$outdir"/deps
      set +x
      exit 1
    fi
    command mv -f -- "$libgit2_tmp" "$libgit2_tarball"
  else
    >&2 echo "[error] file not found: deps/libgit2-"$libgit2_version".tar.gz"
    exit 1
  fi
fi

libgit2_actual_sha256=
if command -v shasum >/dev/null 2>/dev/null; then
  libgit2_actual_sha256="$(command shasum -b -a 256 -- "$libgit2_tarball")"
  libgit2_actual_sha256="${libgit2_actual_sha256%% *}"
elif command -v sha256sum >/dev/null 2>/dev/null; then
  libgit2_actual_sha256="$(command sha256sum -b -- "$libgit2_tarball")"
  libgit2_actual_sha256="${libgit2_actual_sha256%% *}"
elif command -v sha256 >/dev/null 2>/dev/null; then
  libgit2_actual_sha256="$(command sha256 -- "$libgit2_tarball" </dev/null)"
  # Ignore sha256 output if it's from hashalot. It's incompatible.
  if [ ${#libgit2_actual_sha256} -lt 64 ]; then
    libgit2_actual_sha256=
  else
    libgit2_actual_sha256="${libgit2_actual_sha256##* }"
  fi
fi

if [ -z "$libgit2_actual_sha256" ]; then
  >&2 echo "[error] command not found: shasum or sha256sum"
  exit 1
fi

if [ "$libgit2_actual_sha256" != "$libgit2_sha256" ]; then
  >&2 echo "[error] sha256 mismatch"
  >&2 echo ""
  >&2 echo "  file    : deps/libgit2-$libgit2_version.tar.gz"
  >&2 echo "  expected: $libgit2_sha256"
  >&2 echo "  actual  : $libgit2_actual_sha256"
  exit 1
fi

CFLAGS="$libgit2_cflags" command cmake \
  -DCMAKE_BUILD_TYPE=None              \
  -DZERO_NSEC=ON                       \
  -DTHREADSAFE=ON                      \
  -DUSE_BUNDLED_ZLIB=ON                \
  -DREGEX_BACKEND=builtin              \
  -DUSE_HTTP_PARSER=builtin            \
  -DUSE_SSH=OFF                        \
  -DUSE_HTTPS=OFF                      \
  -DBUILD_CLAR=OFF                     \
  -DUSE_GSSAPI=OFF                     \
  -DUSE_NTLMCLIENT=OFF                 \
  -DBUILD_SHARED_LIBS=OFF              \
  $libgit2_cmake_flags                 \
  ..
command make -j "$cpus" VERBOSE=1

app="$outdir"/usrbin/"$appname"

command strip "$app".tmp

resp="$(printf 'hello\037\036' | "$app".tmp)"
case "$resp" in
  hello*0*);;
  *)
    >&2 echo 'error: invalid gitstatusd response for a non-repo'
    exit 1
  ;;
esac

command mv -f -- "$app".tmp "$app"

cleanup

command cat >&2 <<-END
	-------------------------------------------------
	SUCCESS: created usrbin/$appname
	END
END
)"

when I remove the case "$resp" block the script returns 0.

@romkatv
Copy link
Owner

romkatv commented Dec 9, 2023

Very nice job! Let's keep going. If you don't know how to proceed, try these:

Is set -ue really necessary?

#!/bin/sh

build="$(command cat <<\END

case "$resp" in
  hello*0*);;
esac

END
)"

Is process substitution really necessary?

#!/bin/sh

set -ue

command cat <<\END

case "$resp" in
  hello*0*);;
esac

END

Is command cat really necessary?

#!/bin/sh

set -ue

build="$(: <<\END

case "$resp" in
  hello*0*);;
esac

END
)"

Is "$resp" really necessary?

#!/bin/sh

set -ue

build="$(command cat <<\END

case x in
  hello*0*);;
esac

END
)"

Is hello*0 really necessary?

#!/bin/sh

set -ue

build="$(command cat <<\END

case "$resp" in
  *);;
esac

END
)"

You get the idea. Remove all the things that aren't necessary for triggering the error and we'll be left with a tiny script. Then there will be a chance that somebody will do something when the bug is reported.

@oe7drt
Copy link
Contributor Author

oe7drt commented Dec 9, 2023

Okay all these snippets on their own produce following output:

$ for i in build1 build2 build3 build4 build5 ; do ./$i; done
./build1: here document `END' unclosed

case "$resp" in
  hello*0*);;
esac

./build3: here document `END' unclosed
./build4: here document `END' unclosed
./build5: here document `END' unclosed

So, is this it?

With (build2) -- Is process substitution really necessary?

#!/bin/sh

# set -ue

command cat <<\END

case "$resp" in
  hello*0*);;
esac

END

the script returns 0 and outputs

$ ./build2

case "$resp" in
  hello*0*);;
esac

@romkatv
Copy link
Owner

romkatv commented Dec 9, 2023

So, what is the smallest script you've identified that exhibits the error?

@oe7drt
Copy link
Contributor Author

oe7drt commented Dec 9, 2023

I guess it is this one

#!/bin/sh

build="$(: <<\END

case x in
  *);;
esac

END
)"

@romkatv
Copy link
Owner

romkatv commented Dec 9, 2023

That looks great! One last attempt at simplification and it's done. Checking if the variable is really necessary.

#!/bin/sh

: "$(: <<\END

case x in
  *);;
esac

END
)"

@oe7drt
Copy link
Contributor Author

oe7drt commented Dec 9, 2023

that also prints the error

@romkatv
Copy link
Owner

romkatv commented Dec 9, 2023

That would be it. Could you report a bug against OpenBSD? Give them this script and describe what happens when you interpret it with sh and what you expect to happen instead.

@oe7drt
Copy link
Contributor Author

oe7drt commented Dec 9, 2023

That would be it. Could you report a bug against OpenBSD? Give them this script and describe what happens when you interpret it with sh and what you expect to happen instead.

What would I expect to happen? This is really a bit too complex for my understanding, I do some basic scripting now and then, but these simplifications are something I never really needed.

Now what I think to understand:

the text enclosed by "" gets expanded from the shell, which is basically the case switch, which does nothing per default.

I don't get the part with : as I've never seen this before except the prezto installation which replaces variables IIRC.

: "$(: <<\END

but what exactly should the line above do?

@romkatv
Copy link
Owner

romkatv commented Dec 9, 2023

The expected behavior of this script is succeeding without doing anything. zsh and bash behave as expected. sh, however, behaves unexpectedly: it prints an error and exits with a non-zero status code.

: is a builtin command that does nothing and succeeds. It's another name for true. The thing between <<\END and END is a heredoc. The backslash instructs the shell to NOT expand anything in it. You don't need to include this explanation in the bug report. People on the receiving end will likely understand your script.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants