run-command: unify signal and regular logic for wait_or_whine()

Since 507d7804c0 (pager: don't use unsafe functions in signal handlers,
2015-09-04), we have a separate code path in wait_or_whine() for the
case that we're in a signal handler. But that code path misses some of
the cases handled by the main logic.

This was improved in be8fc53e36 (pager: properly log pager exit code
when signalled, 2021-02-02), but that covered only case: actually
returning the correct error code. But there are some other cases:

  - if waitpid() returns failure, we wouldn't notice and would look at
    uninitialized garbage in the status variable; it's not clear if it's
    possible to trigger this or not

  - if the process exited by signal, then we would still report "-1"
    rather than the correct signal code

This latter case even had a test added in be8fc53e36, but it doesn't
work reliably. It sets the pager command to:

  >pager-used; test-tool sigchain

The latter command will die by signal, but because there are multiple
commands, there will be a shell in between. And it's the shell whose
waitpid() call will see the signal death, and it will then exit with
code 143, which is what Git will see.

To make matters even more confusing, some shells (such as bash) will
realize that there's nothing for the shell to do after test-tool
finishes, and will turn it into an exec. So the test was only checking
what it thought when /bin/sh points to a shell like bash (we're relying
on the shell used internally by Git to spawn sub-commands here, so even
running the test under bash would not be enough).

This patch adjusts the tests to explicitly call "exec" in the pager
command, which produces a consistent outcome regardless of shell. Note
that without the code change in this patch it _should_ fail reliably,
but doesn't. That test, like its siblings, tries to trigger SIGPIPE in
the git-log process writing to the pager, but only do so racily. That
will be fixed in a follow-on patch.

For the code change here, we have two options:

  - we can teach the in_signal code to handle WIFSIGNALED()

  - we can stop returning early when in_signal is set, and instead
    annotate individual calls that we need to skip in this case

The former is a simpler patch, but means we're essentially duplicating
all of the logic. So instead I went with the latter. The result is a
bigger patch, and we do run the risk of new code being added but
forgetting to handle in_signal. But in the long run it seems more
maintainable.

I've skipped any non-trivial calls for the in_signal case, like calling
error(). We'll also skip the call to clear_child_for_cleanup(), as we
were before. This is arguably the wrong thing to do, since we wouldn't
want to try to clean it up again. But:

  - we can't call it as-is, because it calls free(), which we must avoid
    in a signal handler (we'd have to pass in_signal so it can skip the
    free() call)

  - we'll only go through the list of children to clean once, since our
    cleanup_children_on_signal() handler pops itself after running (and
    then re-raises, so eventually we'd just exit). So this cleanup only
    matters if a process is on the cleanup list _and_ it has a separate
    handler to clean itself up. Which is questionable in the first place
    (and AFAIK we do not do).

  - double-cleanup isn't actually that bad anyway. waitpid() will just
    return an error, which we won't even report because of in_signal.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 files changed
tree: d795b0ba3c6a26a48e6d7c1cb8f4e70b8b273fae
  1. .github/
  2. block-sha1/
  3. builtin/
  4. ci/
  5. compat/
  6. contrib/
  7. Documentation/
  8. ewah/
  9. git-gui/
  10. gitk-git/
  11. gitweb/
  12. mergetools/
  13. negotiator/
  14. perl/
  15. po/
  16. ppc/
  17. refs/
  18. sha1dc/
  19. sha256/
  20. t/
  21. templates/
  22. trace2/
  23. vcs-svn/
  24. xdiff/
  25. .cirrus.yml
  26. .clang-format
  27. .editorconfig
  28. .gitattributes
  29. .gitignore
  30. .gitmodules
  31. .mailmap
  32. .travis.yml
  33. .tsan-suppressions
  34. abspath.c
  35. aclocal.m4
  36. add-interactive.c
  37. add-interactive.h
  38. add-patch.c
  39. advice.c
  40. advice.h
  41. alias.c
  42. alias.h
  43. alloc.c
  44. alloc.h
  45. apply.c
  46. apply.h
  47. archive-tar.c
  48. archive-zip.c
  49. archive.c
  50. archive.h
  51. attr.c
  52. attr.h
  53. banned.h
  54. base85.c
  55. bisect.c
  56. bisect.h
  57. blame.c
  58. blame.h
  59. blob.c
  60. blob.h
  61. bloom.c
  62. bloom.h
  63. branch.c
  64. branch.h
  65. builtin.h
  66. bulk-checkin.c
  67. bulk-checkin.h
  68. bundle.c
  69. bundle.h
  70. cache-tree.c
  71. cache-tree.h
  72. cache.h
  73. chdir-notify.c
  74. chdir-notify.h
  75. check-builtins.sh
  76. check_bindir
  77. checkout.c
  78. checkout.h
  79. CODE_OF_CONDUCT.md
  80. color.c
  81. color.h
  82. column.c
  83. column.h
  84. combine-diff.c
  85. command-list.txt
  86. commit-graph.c
  87. commit-graph.h
  88. commit-reach.c
  89. commit-reach.h
  90. commit-slab-decl.h
  91. commit-slab-impl.h
  92. commit-slab.h
  93. commit.c
  94. commit.h
  95. common-main.c
  96. config.c
  97. config.h
  98. config.mak.dev
  99. config.mak.in
  100. config.mak.uname
  101. configure.ac
  102. connect.c
  103. connect.h
  104. connected.c
  105. connected.h
  106. convert.c
  107. convert.h
  108. copy.c
  109. COPYING
  110. credential.c
  111. credential.h
  112. csum-file.c
  113. csum-file.h
  114. ctype.c
  115. daemon.c
  116. date.c
  117. decorate.c
  118. decorate.h
  119. delta-islands.c
  120. delta-islands.h
  121. delta.h
  122. detect-compiler
  123. diff-delta.c
  124. diff-lib.c
  125. diff-no-index.c
  126. diff.c
  127. diff.h
  128. diffcore-break.c
  129. diffcore-delta.c
  130. diffcore-order.c
  131. diffcore-pickaxe.c
  132. diffcore-rename.c
  133. diffcore.h
  134. dir-iterator.c
  135. dir-iterator.h
  136. dir.c
  137. dir.h
  138. editor.c
  139. entry.c
  140. environment.c
  141. environment.h
  142. exec-cmd.c
  143. exec-cmd.h
  144. fetch-negotiator.c
  145. fetch-negotiator.h
  146. fetch-pack.c
  147. fetch-pack.h
  148. fmt-merge-msg.c
  149. fmt-merge-msg.h
  150. fsck.c
  151. fsck.h
  152. fsmonitor.c
  153. fsmonitor.h
  154. fuzz-commit-graph.c
  155. fuzz-pack-headers.c
  156. fuzz-pack-idx.c
  157. generate-cmdlist.sh
  158. generate-configlist.sh
  159. gettext.c
  160. gettext.h
  161. git-add--interactive.perl
  162. git-archimport.perl
  163. git-bisect.sh
  164. git-compat-util.h
  165. git-cvsexportcommit.perl
  166. git-cvsimport.perl
  167. git-cvsserver.perl
  168. git-difftool--helper.sh
  169. git-filter-branch.sh
  170. git-instaweb.sh
  171. git-merge-octopus.sh
  172. git-merge-one-file.sh
  173. git-merge-resolve.sh
  174. git-mergetool--lib.sh
  175. git-mergetool.sh
  176. git-p4.py
  177. git-quiltimport.sh
  178. git-rebase--preserve-merges.sh
  179. git-request-pull.sh
  180. git-send-email.perl
  181. git-sh-i18n.sh
  182. git-sh-setup.sh
  183. git-submodule.sh
  184. git-svn.perl
  185. GIT-VERSION-GEN
  186. git-web--browse.sh
  187. git.c
  188. git.rc
  189. gpg-interface.c
  190. gpg-interface.h
  191. graph.c
  192. graph.h
  193. grep.c
  194. grep.h
  195. hash-lookup.c
  196. hash-lookup.h
  197. hash.h
  198. hashmap.c
  199. hashmap.h
  200. help.c
  201. help.h
  202. hex.c
  203. http-backend.c
  204. http-fetch.c
  205. http-push.c
  206. http-walker.c
  207. http.c
  208. http.h
  209. ident.c
  210. imap-send.c
  211. INSTALL
  212. iterator.h
  213. json-writer.c
  214. json-writer.h
  215. khash.h
  216. kwset.c
  217. kwset.h
  218. levenshtein.c
  219. levenshtein.h
  220. LGPL-2.1
  221. line-log.c
  222. line-log.h
  223. line-range.c
  224. line-range.h
  225. linear-assignment.c
  226. linear-assignment.h
  227. list-objects-filter-options.c
  228. list-objects-filter-options.h
  229. list-objects-filter.c
  230. list-objects-filter.h
  231. list-objects.c
  232. list-objects.h
  233. list.h
  234. ll-merge.c
  235. ll-merge.h
  236. lockfile.c
  237. lockfile.h
  238. log-tree.c
  239. log-tree.h
  240. ls-refs.c
  241. ls-refs.h
  242. mailinfo.c
  243. mailinfo.h
  244. mailmap.c
  245. mailmap.h
  246. Makefile
  247. match-trees.c
  248. mem-pool.c
  249. mem-pool.h
  250. merge-blobs.c
  251. merge-blobs.h
  252. merge-ort-wrappers.c
  253. merge-ort-wrappers.h
  254. merge-ort.c
  255. merge-ort.h
  256. merge-recursive.c
  257. merge-recursive.h
  258. merge.c
  259. mergesort.c
  260. mergesort.h
  261. midx.c
  262. midx.h
  263. name-hash.c
  264. notes-cache.c
  265. notes-cache.h
  266. notes-merge.c
  267. notes-merge.h
  268. notes-utils.c
  269. notes-utils.h
  270. notes.c
  271. notes.h
  272. object-file.c
  273. object-name.c
  274. object-store.h
  275. object.c
  276. object.h
  277. oid-array.c
  278. oid-array.h
  279. oidmap.c
  280. oidmap.h
  281. oidset.c
  282. oidset.h
  283. pack-bitmap-write.c
  284. pack-bitmap.c
  285. pack-bitmap.h
  286. pack-check.c
  287. pack-objects.c
  288. pack-objects.h
  289. pack-revindex.c
  290. pack-revindex.h
  291. pack-write.c
  292. pack.h
  293. packfile.c
  294. packfile.h
  295. pager.c
  296. parse-options-cb.c
  297. parse-options.c
  298. parse-options.h
  299. patch-delta.c
  300. patch-ids.c
  301. patch-ids.h
  302. path.c
  303. path.h
  304. pathspec.c
  305. pathspec.h
  306. pkt-line.c
  307. pkt-line.h
  308. preload-index.c
  309. pretty.c
  310. pretty.h
  311. prio-queue.c
  312. prio-queue.h
  313. progress.c
  314. progress.h
  315. promisor-remote.c
  316. promisor-remote.h
  317. prompt.c
  318. prompt.h
  319. protocol.c
  320. protocol.h
  321. prune-packed.c
  322. prune-packed.h
  323. quote.c
  324. quote.h
  325. range-diff.c
  326. range-diff.h
  327. reachable.c
  328. reachable.h
  329. read-cache.c
  330. README.md
  331. rebase-interactive.c
  332. rebase-interactive.h
  333. rebase.c
  334. rebase.h
  335. ref-filter.c
  336. ref-filter.h
  337. reflog-walk.c
  338. reflog-walk.h
  339. refs.c
  340. refs.h
  341. refspec.c
  342. refspec.h
  343. remote-curl.c
  344. remote.c
  345. remote.h
  346. replace-object.c
  347. replace-object.h
  348. repo-settings.c
  349. repository.c
  350. repository.h
  351. rerere.c
  352. rerere.h
  353. reset.c
  354. reset.h
  355. resolve-undo.c
  356. resolve-undo.h
  357. revision.c
  358. revision.h
  359. run-command.c
  360. run-command.h
  361. send-pack.c
  362. send-pack.h
  363. sequencer.c
  364. sequencer.h
  365. serve.c
  366. serve.h
  367. server-info.c
  368. setup.c
  369. sh-i18n--envsubst.c
  370. sha1dc_git.c
  371. sha1dc_git.h
  372. shallow.c
  373. shallow.h
  374. shell.c
  375. shortlog.h
  376. sideband.c
  377. sideband.h
  378. sigchain.c
  379. sigchain.h
  380. split-index.c
  381. split-index.h
  382. stable-qsort.c
  383. strbuf.c
  384. strbuf.h
  385. streaming.c
  386. streaming.h
  387. string-list.c
  388. string-list.h
  389. strmap.c
  390. strmap.h
  391. strvec.c
  392. strvec.h
  393. sub-process.c
  394. sub-process.h
  395. submodule-config.c
  396. submodule-config.h
  397. submodule.c
  398. submodule.h
  399. symlinks.c
  400. tag.c
  401. tag.h
  402. tar.h
  403. tempfile.c
  404. tempfile.h
  405. thread-utils.c
  406. thread-utils.h
  407. tmp-objdir.c
  408. tmp-objdir.h
  409. trace.c
  410. trace.h
  411. trace2.c
  412. trace2.h
  413. trailer.c
  414. trailer.h
  415. transport-helper.c
  416. transport-internal.h
  417. transport.c
  418. transport.h
  419. tree-diff.c
  420. tree-walk.c
  421. tree-walk.h
  422. tree.c
  423. tree.h
  424. unicode-width.h
  425. unimplemented.sh
  426. unix-socket.c
  427. unix-socket.h
  428. unpack-trees.c
  429. unpack-trees.h
  430. upload-pack.c
  431. upload-pack.h
  432. url.c
  433. url.h
  434. urlmatch.c
  435. urlmatch.h
  436. usage.c
  437. userdiff.c
  438. userdiff.h
  439. utf8.c
  440. utf8.h
  441. varint.c
  442. varint.h
  443. version.c
  444. version.h
  445. versioncmp.c
  446. walker.c
  447. walker.h
  448. wildmatch.c
  449. wildmatch.h
  450. worktree.c
  451. worktree.h
  452. wrap-for-bin.sh
  453. wrapper.c
  454. write-or-die.c
  455. ws.c
  456. wt-status.c
  457. wt-status.h
  458. xdiff-interface.c
  459. xdiff-interface.h
  460. zlib.c
README.md

Build status

Git - fast, scalable, distributed revision control system

Git is a fast, scalable, distributed revision control system with an unusually rich command set that provides both high-level operations and full access to internals.

Git is an Open Source project covered by the GNU General Public License version 2 (some parts of it are under different licenses, compatible with the GPLv2). It was originally written by Linus Torvalds with help of a group of hackers around the net.

Please read the file INSTALL for installation instructions.

Many Git online resources are accessible from https://git-scm.com/ including full documentation and Git related tools.

See Documentation/gittutorial.txt to get started, then see Documentation/giteveryday.txt for a useful minimum set of commands, and Documentation/git-<commandname>.txt for documentation of each command. If git has been correctly installed, then the tutorial can also be read with man gittutorial or git help tutorial, and the documentation of each command with man git-<commandname> or git help <commandname>.

CVS users may also want to read Documentation/gitcvs-migration.txt (man gitcvs-migration or git help cvs-migration if git is installed).

The user discussion and development of Git take place on the Git mailing list -- everyone is welcome to post bug reports, feature requests, comments and patches to git@vger.kernel.org (read Documentation/SubmittingPatches for instructions on patch submission). To subscribe to the list, send an email with just “subscribe git” in the body to majordomo@vger.kernel.org. The mailing list archives are available at https://lore.kernel.org/git/, http://marc.info/?l=git and other archival sites.

Issues which are security relevant should be disclosed privately to the Git Security mailing list git-security@googlegroups.com.

The maintainer frequently sends the “What's cooking” reports that list the current status of various development topics to the mailing list. The discussion following them give a good reference for project status, development direction and remaining tasks.

The name “git” was given by Linus Torvalds when he wrote the very first version. He described the tool as “the stupid content tracker” and the name as (depending on your mood):

  • random three-letter combination that is pronounceable, and not actually used by any common UNIX command. The fact that it is a mispronunciation of “get” may or may not be relevant.
  • stupid. contemptible and despicable. simple. Take your pick from the dictionary of slang.
  • “global information tracker”: you're in a good mood, and it actually works for you. Angels sing, and a light suddenly fills the room.
  • “goddamn idiotic truckload of sh*t”: when it breaks