Re: leaks fd for internal functions but not external command
Thanks for that thoughtful response. * I understand that the design decision is to have variable file descriptors to stay open after per-command redirection * I understand that implementation constraints make it impossible to do this uniformly (for external command redirection) * I understand that it is difficult for the script author to detect which case his code will be I'm trying to make bash better and more usable. The shell normally does a great job of hiding the difference between internal and external commands, so even though it's very well documented, most of the time the user doesn't need to be aware. This is great for the user, and according to the principle of least surprise. The syntactic sugar of having bash select a free fd (which necessary for good composability of operations in complex script pipelines) is a great benefit, especially when mixing with older pipelines having fixed numeric fd. You say that there are technical reasons why the syntactic sugar of also keeping the fd open can't be implemented uniformly. I wonder if this puts unnecessary cognitive burden on the user, leading to reluctance to get the benefits, or to the introduction of latent bugs. There is a case I explain below which can lead to a leaked fd being held on to by subsequently invoked external processes. Of course it will technically be the users fault but I'm looking at reducing the cognitive burdens that make such a fault ultimately inevitable. The cognitive burdens of leaving the fd open are: 1. It breaks the normal expectation that per-command redirects are limited to the scope of the command. A naked exec already works to hold open a variable fd in a wider scope if that's what the scripter actually wants: exec {fd}>... ; 2. As syntactic sugar it moves, not removes, the boiler-plate burden This naked exec (see above) saved by the syntactic sugar in the case where the fd should remain open is offset by the naked exec now required in order to close the fd for the traditional case that the fd should not left open beyond the scope of the command. 3. The unmeetable cognitive burden is that in order to safely manage the previous two item, the user needs to know if the command will be external or internal or a function. This makes it hard for the user depend on this feature, because it is not possible to be sure at script author time whether a command is external. It may have become a function, (due to export -f, source, etc) which affect the execution environment. 4. The inevitable propagation of leaked fd's The knowing user can remember to always use an identity wrapper function to force treatment as external commands as internal functions in order to get uniform behaviour, and also explicitly close the fd afterwards. (I hope this doesn't break exec optimisations or signal propagation over a different process tree topology, though I doubt it. But other users may not know to close the fd which was never apparent (due invoking an external command) but which becomes an fd leak when they combine with other bash features (functions wrapping of external commands, or export -f environment that does this unawares) and those leaked fd's may then be inherited by other invoked external processes which may hold on to them for some time. This contrived example minimises the pipeline fd contortions in order to show that when what was an external command then becomes an internal command, it can as a consequence result in an fd leak to external processes (bash+lsof+grep here) which may be long lived. stty {x}>/tmp/log bash -c 'lsof -p $$ | grep log ; :' stty() { command stty $EXTRA_STTY "$@" } stty {x}>/tmp/log bash -c 'lsof -p $$ | grep log ; :' Leading to questions like: "Why does wrapping a one command in a function cause a different background process to hang on to a private handle not even used there?" The future: I recognise what you say about past design decisions, but for the future, as it is hard to safely get the benefit of leaving the handle open for variable per-command redefines, even for users who know about it, I wonder if the syntactic sugar might be redefined to reduce the cognitive burden and widen the benefit for the most valued variable fd's feature. If the variable fd syntactic sugar were re-designed so that variable handles were also limited to the scope the command, the same as for external commands, the same as for numeric handles, then: * the behaviour would be uniform, * the cognitive burden would be reduced * and there would be no behaviour dependent on the runtime environment (export -f to wrap external commands). * and no risk of unexpected or hard to control fd leaks to subsequent external (long lived) commands This would allow users to have full and safe benefit of bash-selected fd's, which I am sure is what is intended. I have done my best to be clear in a reasonable manner, but you are the man, it is your project, we stand or fall by your decisions, not mine. Sam On Wed,
[PATCH] Fix \H: Use getaddrinfo to get full hostname
At the moment, \h and \H used in prompt PS1 or PS2 will actually return the same value while manpage claims that \h should return hostname up to the first '.' (like `hostname`) and \H should return full hostname (like `hostname -f`). This commit will make bash use the same API like hostname command to return full hostname like intended. This patch is based on the original work from Renato Silva [Link 1]. Link 1: https://lists.gnu.org/archive/html/bug-bash/2014-06/msg00021.html --- shell.c | 16 +--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/shell.c b/shell.c index a2b2a55e..28e89a2b 100644 --- a/shell.c +++ b/shell.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "filecntl.h" #if defined (HAVE_PWD_H) # include @@ -1839,6 +1840,8 @@ get_current_user_info () static void shell_initialize () { + struct addrinfo *addr_info; + struct addrinfo addr_hints; char hostname[256]; int should_be_restricted; @@ -1864,10 +1867,17 @@ shell_initialize () if (current_host_name == 0) { /* Initialize current_host_name. */ - if (gethostname (hostname, 255) < 0) - current_host_name = "??host??"; + memset(&addr_hints, 0, sizeof(struct addrinfo)); + addr_hints.ai_flags = AI_CANONNAME; + + if (gethostname (hostname, 255) >= 0) +{ + if (getaddrinfo (hostname, NULL, &addr_hints, &addr_info) == 0) +strncpy (hostname, addr_info->ai_canonname, 255); + current_host_name = savestring (hostname); +} else - current_host_name = savestring (hostname); + current_host_name = "??host??"; } /* Initialize the stuff in current_user that comes from the password -- 2.22.0
Re: [PATCH] Fix \H: Use getaddrinfo to get full hostname
On 7/24/19 9:58 AM, Thomas Deutschmann wrote: > At the moment, \h and \H used in prompt PS1 or PS2 will actually return > the same value while manpage claims that \h should return hostname up to > the first '.' (like `hostname`) and \H should return full hostname (like > `hostname -f`). Thanks for the patch. This is system-dependent: there are systems, like mine, where `hostname' returns the system's FQDN. It all depends on the administrator's choices. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/
Re: [PATCH] Fix \H: Use getaddrinfo to get full hostname
On 2019-07-24 16:27, Chet Ramey wrote: > Thanks for the patch. This is system-dependent: there are systems, like > mine, where `hostname' returns the system's FQDN. It all depends on the > administrator's choices. Can you tell me more about your system and how you (your administrator) set up your system so that hostname will return FQDN? I hope you are not talking about putting FQDN into a file which is expecting hostname only... Or in other words: At the moment I am wondering what should be wrong on my system or on Debian/Ubuntu out of the box: You set hostname to hostname only (no FQDN) and set domain option in /etc/resolv.conf for example for FQDN. But maybe I am missing something. Thanks. -- Regards, Thomas Deutschmann / Gentoo Linux Developer C4DD 695F A713 8F24 2AA1 5638 5849 7EE5 1D5D 74A5 signature.asc Description: OpenPGP digital signature
Re: [PATCH] Fix \H: Use getaddrinfo to get full hostname
On 7/24/19 10:38 AM, Thomas Deutschmann wrote: > On 2019-07-24 16:27, Chet Ramey wrote: >> Thanks for the patch. This is system-dependent: there are systems, like >> mine, where `hostname' returns the system's FQDN. It all depends on the >> administrator's choices. > > Can you tell me more about your system and how you (your administrator) > set up your system so that hostname will return FQDN? I use Mac OS X: caleb.ins.cwru.edu(1)$ hostname caleb.ins.cwru.edu caleb.ins.cwru.edu(1)$ hostname -f caleb.ins.cwru.edu caleb.ins.cwru.edu(1)$ uname -a Darwin caleb.ins.cwru.edu 18.6.0 Darwin Kernel Version 18.6.0: Thu Apr 25 23:16:27 PDT 2019; root:xnu-4903.261.4~2/RELEASE_X86_64 x86_64 > > I hope you are not talking about putting FQDN into a file which is > expecting hostname only... There is no `file', and there's no requirement that `hostname' not return the FQDN. > > Or in other words: At the moment I am wondering what should be wrong on > my system or on Debian/Ubuntu out of the box: You set hostname to > hostname only (no FQDN) and set domain option in /etc/resolv.conf for > example for FQDN. But maybe I am missing something. The world isn't all Linux. -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/ signature.asc Description: OpenPGP digital signature
Re: [PATCH] Fix \H: Use getaddrinfo to get full hostname
On Wed, Jul 24, 2019 at 04:38:06PM +0200, Thomas Deutschmann wrote: > Can you tell me more about your system and how you (your administrator) > set up your system so that hostname will return FQDN? It's common outside the Linux world. # hostname minea.eeg.ccf.org # uname -a HP-UX minea B.11.11 U 9000/785 4239047153 unlimited-user license > I hope you are not talking about putting FQDN into a file which is > expecting hostname only... Yes, many people do precisely that. They configure their systems so the "hostname" command returns an FQDN, as I showed above. (Not my design, not my choice.) This is what bash's \H vs. \h is for. If your system's hostname has dots in it, \h shows only the part up to the first dot (because that's usually what you want in your prompt -- the shorter version), and \H is available just in case you actually want the full version.
Re: [PATCH] Fix \H: Use getaddrinfo to get full hostname
On 2019-07-24 16:46, Greg Wooledge wrote: >> I hope you are not talking about putting FQDN into a file which is >> expecting hostname only... > > Yes, many people do precisely that. They configure their systems > so the "hostname" command returns an FQDN, as I showed above. (Not > my design, not my choice.) I consider this as misconfiguration. :( I can't believe that we somehow encourage people to either do something wrong (put FQDN where just non-FQDN is expected and bypass DNS mechanism) or use $(hostname -f) in PS1 when they want FQDN. Anyway, back to bash: So you are rejecting this patch, right? Maybe update man page at least to clarify that "\H" in contrast to "\h" is supposed to return the same value but _unfiltered_? Thanks. -- Regards, Thomas Deutschmann / Gentoo Linux Developer C4DD 695F A713 8F24 2AA1 5638 5849 7EE5 1D5D 74A5 signature.asc Description: OpenPGP digital signature
Re: [PATCH] Fix \H: Use getaddrinfo to get full hostname
On Wed, Jul 24, 2019 at 05:23:27PM +0200, Thomas Deutschmann wrote: > On 2019-07-24 16:46, Greg Wooledge wrote: > >> I hope you are not talking about putting FQDN into a file which is > >> expecting hostname only... > > > > Yes, many people do precisely that. They configure their systems > > so the "hostname" command returns an FQDN, as I showed above. (Not > > my design, not my choice.) > > I consider this as misconfiguration. :( > > I can't believe that we somehow encourage people to either do something > wrong (put FQDN where just non-FQDN is expected and bypass DNS > mechanism) or use $(hostname -f) in PS1 when they want FQDN. Your perspective is too limited. Linux-based systems are very popular, but they're not the entire Unix world. # hostname -f # hostname -f # hostname minea.eeg.ccf.org # Personally, I don't like hostname returning a FQDN, but many other people *do*. It's common. When I work on a system that's set that way, I leave it set that way. It's so common that bash has two different PS1 escape sequences to handle it. Has had them for decades, as far as I know. There is nothing "wrong" about this configuration. I don't like it, and you clearly don't like it, but our opinions only matter to us.
expression evaluation problem
shopt -o expand_aliases my=declare int='my -i' my str='cf80' int v=960 uxtra=1 c=0 # In evaluating this expression: ((v = v | ( uxtra>=++c ? ((0x${str:2*c:2}) & 63) << (6*(uxtra-c)) : 0 ))) I get 985 and not 960 as expected Which only happens when 'c' is 0 in the middle 'str' expression, but the ++c should increment 'c' to '1' before it is tested to be less than or equal to 'uxtra'(=1). Then it would take the 1st or 2nd sub expression depending on that. But the test has to happen 1st, which would pre-increment 'c' to 1. If 'c' is 1, then it should return '80' from 'str' combine with 0x to make 0x80 or 128. That, anded with '63' should be 0, shouldn't it? So why isn't it evaluating to '0', 'or'ed with 960, and giving 960? Indeed, if I manually put a '1' in place of that 'c' in the middle of the expression, I get the expected answer of 960. So it seems 'c' is evaluating as '0', even though the middle sub-expression can't be taken/evaluated until 'c' has been incremented to 1. BASH=4.4.12 Thanks -linda
Re: [PATCH] Fix \H: Use getaddrinfo to get full hostname
On 2019-07-24 17:32, Greg Wooledge wrote: > Your perspective is too limited. Linux-based systems are very popular, > but they're not the entire Unix world. > > [...] > > There is nothing "wrong" about this configuration. I don't like it, > and you clearly don't like it, but our opinions only matter to us. OK :( Thank you for the explanation! -- Regards, Thomas Deutschmann / Gentoo Linux Developer C4DD 695F A713 8F24 2AA1 5638 5849 7EE5 1D5D 74A5 signature.asc Description: OpenPGP digital signature
Re: expression evaluation problem
On Wed, Jul 24, 2019 at 09:39:46AM -0700, L A Walsh wrote: > str='cf80' > v=960 uxtra=1 c=0 Irrelevant alias shenanigans omitted. These are your variables. > # In evaluating this expression: > ((v = v | ( uxtra>=++c ? ((0x${str:2*c:2}) & 63) << (6*(uxtra-c)) : 0 ))) > > > I get 985 and not 960 as expected > > Which only happens when 'c' is 0 in the middle 'str' expression, > but the ++c should increment 'c' to '1' before it is tested to be > less than or equal to 'uxtra'(=1). The ${str:2*c:2} part is performed first, while c is still 0, and it expands to "cf". Only then does the arithmetic evaluation begin. wooledg:~$ str='cf80' wooledg:~$ v=960 uxtra=1 c=0 wooledg:~$ ((v = v | ( uxtra>=++c ? ((0xcf) & 63) << (6*(uxtra-c)) : 0 ))) wooledg:~$ declare -p v declare -- v="975" Even with that parameter expansion out of the way, this arithmetic command is still ridiculously over-complicated. I can't even guess what it's supposed to do. Have you considered performing your calculation in steps, with intermediate values stored in temporary variables with clear names? That greatly improves readability. Isolating the ++c into its own step would also remove all questions about whether the increment is performed before or after other calculations (or in this case, parameter expansions). In-lining ++c inside a larger calculation can be OK in very simple situations, but a nightmare to read/understand/debug in more complex cases.
Explicit variables declaration statements do not resolve back-references from same statement
Found this strange behavior difference in Bash, between explicit and implicit declarations of variables. An implicit variables declaration statement resolve back-references to variables from the same statement. Whereas: An explicit variables declaration statement does not resolve back-reference variables from the same statement. Illustration code: knip code start #!/usr/bin/env bash unset a b c printf $'\nExplicit declarations statements:\n' printf $'\ntypeset -i a=2 b=$a c="$((a - 1))":\n=> ' typeset -i a=2 b=$a c="$((a - 1))" printf 'a=%d b=%d c=%d\n' "${a}" "${b}" "${c}" unset a b c printf $'\ndeclare a=hello b=world c="$a $b":\n=> ' declare a='hello' b='world' c="${a} ${b}" printf $"a='%s' b='%s' c='%s'\\n" "${a}" "${b}" "${c}" unset a b c printf $'\nImplicit declarations statements:\n' a=2 b=$a c="$((a - 1))" printf $'\na=2 b=$a c="$((a - 1))":\n=> ' printf 'a=%d b=%d c=%d\n' "${a}" "${b}" "${c}" unset a b c a='hello' b='world' c="${a} ${b}" printf $'\na=hello b=world c="$a $b":\n=> ' printf $"a='%s' b='%s' c='%s'\\n" "$a" "$b" "$c" knip code end Output: Explicit declarations statements: typeset -i a=2 b=$a c="$((a - 1))": => a=2 b=2 c=1 declare a=hello b=world c="$a $b": => ./b.sh[10]: declare: not found [Aucun fichier ou dossier de ce type] a='' b='' c='' Implicit declarations statements: a=2 b=$a c="$((a - 1))": => a=2 b=2 c=1 a=hello b=world c="$a $b": => a='hello' b='world' c='hello world' ksh93 resolves explicit back-references with typeset. -- Léa Gris signature.asc Description: OpenPGP digital signature
errata: Explicit variables declaration statements do not resolve back-references from same statement
Found this strange behavior difference in Bash, between explicit and implicit declarations of variables. An implicit variables declaration statement resolve back-references to variables from the same statement. Whereas: An explicit variables declaration statement does not resolve back-reference variables from the same statement. Illustration code: knip code start #!/usr/bin/env bash unset a b c printf $'\nExplicit declarations statements:\n' printf $'\ntypeset -i a=2 b=$a c="$((a - 1))":\n=> ' typeset -i a=2 b=$a c="$((a - 1))" printf 'a=%d b=%d c=%d\n' "${a}" "${b}" "${c}" unset a b c printf $'\ndeclare a=hello b=world c="$a $b":\n=> ' declare a='hello' b='world' c="${a} ${b}" printf $"a='%s' b='%s' c='%s'\\n" "${a}" "${b}" "${c}" unset a b c printf $'\nImplicit declarations statements:\n' a=2 b=$a c="$((a - 1))" printf $'\na=2 b=$a c="$((a - 1))":\n=> ' printf 'a=%d b=%d c=%d\n' "${a}" "${b}" "${c}" unset a b c a='hello' b='world' c="${a} ${b}" printf $'\na=hello b=world c="$a $b":\n=> ' printf $"a='%s' b='%s' c='%s'\\n" "$a" "$b" "$c" knip code end Output: bash ./test_declare.sh Explicit declarations statements: typeset -i a=2 b=$a c="$((a - 1))": => a=2 b=0 c=-1 declare a=hello b=world c="$a $b": => a='hello' b='world' c=' ' Implicit declarations statements: a=2 b=$a c="$((a - 1))": => a=2 b=2 c=1 a=hello b=world c="$a $b": => a='hello' b='world' c='hello world' ksh93 resolves explicit back-references with typeset. -- Léa Gris signature.asc Description: OpenPGP digital signature
Re: [PATCH] Fix \H: Use getaddrinfo to get full hostname
On 2019/07/24 07:38, Thomas Deutschmann wrote: > Can you tell me more about your system and how you (your administrator) > set up your system so that hostname will return FQDN? > My linux box has 2 interfaces, internal & external, with different domain names on each. While hostname and hostname-f both return the shortname that is common to both domain names, i.e. foo.external.tld(on eth2) foo.in.external.tld (on br0=bridge(eth0+eth5)) & hostname returns 'foo' & domainname returns 'external.tld'. My resolve.conf has domain set to 'in.external.tld'.
Re: expression evaluation problem
On 2019/07/24 10:51, Greg Wooledge wrote: > On Wed, Jul 24, 2019 at 09:39:46AM -0700, L A Walsh wrote: > >> str='cf80' >> v=960 uxtra=1 c=0 >> > > Irrelevant alias shenanigans omitted. These are your variables. > Those aren't my variables. If you assign the integer attribute to a variable it isn't the same as when you don't. > >> # In evaluating this expression: >> ((v = v | ( uxtra>=++c ? ((0x${str:2*c:2}) & 63) << (6*(uxtra-c)) : 0 ))) >> >> >> I get 985 and not 960 as expected >> >> Which only happens when 'c' is 0 in the middle 'str' expression, >> but the ++c should increment 'c' to '1' before it is tested to be >> less than or equal to 'uxtra'(=1). >> > > The ${str:2*c:2} part is performed first, while c is still 0, and it > expands to "cf". > --- Why? It isn't even necessary when 'c' is greater than 'uxtra' > Only then does the arithmetic evaluation begin. > Perhaps that such evaluate happens outside of normal evaluation rules is why shell is so slow? > wooledg:~$ str='cf80' > wooledg:~$ v=960 uxtra=1 c=0 > wooledg:~$ ((v = v | ( uxtra>=++c ? ((0xcf) & 63) << (6*(uxtra-c)) : 0 ))) > wooledg:~$ declare -p v > declare -- v="975" > > Even with that parameter expansion out of the way, this arithmetic > command is still ridiculously over-complicated. I can't even guess > what it's supposed to do. > That's because it is a fragment from a program. It was the minimum from that program to reproduce the problem. It's supposed to assign 960 to 'v'. 'v' is for 'value'. 'c' is an integer counter. uxtra is a limit. > Have you considered performing your calculation in steps, with > intermediate values stored in temporary variables with clear names? > That greatly improves readability. > --- Does it improve execution time? That's more of a concern here than readability, since it is an expression fragment, it isn't meant to be understood in isolation. More to the point, how do I get evaluation to occur in arithmetic order? I.e. so the string operation is done in the order the expression is evaluated? > Isolating the ++c into its own step would also remove all questions > about whether the increment is performed before or after other > calculations (or in this case, parameter expansions). In-lining ++c > inside a larger calculation can be OK in very simple situations, but > a nightmare to read/understand/debug in more complex cases. > The important part for me is whether or not it is faster to perform 1 calculation, or 100. So which would be faster? In this case execution speed is more important than clarity. I consider that a 'constraint'.
Re: [PATCH] Fix \H: Use getaddrinfo to get full hostname
On 7/24/19 11:23 AM, Thomas Deutschmann wrote: > On 2019-07-24 16:46, Greg Wooledge wrote: >>> I hope you are not talking about putting FQDN into a file which is >>> expecting hostname only... >> >> Yes, many people do precisely that. They configure their systems >> so the "hostname" command returns an FQDN, as I showed above. (Not >> my design, not my choice.) > > I consider this as misconfiguration. :( This is how Mac OS X works in an enterprise environment (this one, at least). > I can't believe that we somehow encourage people to either do something > wrong (put FQDN where just non-FQDN is expected and bypass DNS > mechanism) or use $(hostname -f) in PS1 when they want FQDN. Users don't "put" the FQDN anywhere. I didn't do anything when setting up this system. This is my official hostname as set by enterprise DNS. > Anyway, back to bash: > > So you are rejecting this patch, right? Maybe update man page at least > to clarify that "\H" in contrast to "\h" is supposed to return the same > value but _unfiltered_? What does `unfiltered' mean that's different from what the man page says? I don't see the difference. I think the current implementation is fine, but you can easily use a shell variable and expand it in $PS1 if you want something other than what gethostname() gives you. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/ signature.asc Description: OpenPGP digital signature
Re: expression evaluation problem
On Wed, Jul 24, 2019 at 11:43:11AM -0700, L A Walsh wrote: > Those aren't my variables. > If you assign the integer attribute to a variable it isn't the same > as when you don't. In this case it *is*, because everything is being fed to an arithmetic command anyway. Simplifying the bug report as much as possible lets us avoid confusing and unnecessary diversions. > > The ${str:2*c:2} part is performed first, while c is still 0, and it > > expands to "cf". > > > --- > Why? It isn't even necessary when 'c' is greater than 'uxtra' Because that's how bash works. $((expression)) The expression is treated as if it were within double quotes, but a double quote inside the parentheses is not treated specially. All to‐ kens in the expression undergo parameter and variable expansion, com‐ mand substitution, and quote removal. The result is treated as the arithmetic expression to be evaluated. Arithmetic expansions may be nested.
Re: errata: Explicit variables declaration statements do not resolve back-references from same statement
On 7/24/19 2:06 PM, Léa Gris wrote: > Found this strange behavior difference in Bash, between explicit and > implicit declarations of variables. It's not that strange. > An implicit variables declaration statement resolve back-references to > variables from the same statement. An assignment statement. > > Whereas: > > An explicit variables declaration statement does not resolve back-reference > variables from the same statement. A builtin command performing an assignment on its arguments. Look at it this way. Since builtins are simple commands, their arguments are expanded before being invoked. The job of the builtin is to take the expanded arguments and perform the assignments (values and attributes). Since the expansions are performed before the builtin is invoked, the values have not been updated by any previous assignments appearing as arguments to the builtin. > ksh93 resolves explicit back-references with typeset. ksh93 probably does something special to the arguments to typeset so they're different from other builtins. Bash does some similar things to implement POSIX's concept of `declaration commands', but those have mostly to do with the expansions performed on the rhs of the assignment. -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/ signature.asc Description: OpenPGP digital signature