Austin Group Defect Tracker

Aardvark Mark IV


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0001138 [1003.1(2016/18)/Issue7+TC2] System Interfaces Editorial Enhancement Request 2017-04-27 12:02 2020-10-23 15:15
Reporter joerg View Status public  
Assigned To
Priority normal Resolution Open  
Status New  
Name Jörg Schilling
Organization
User Reference
Section System Interfaces
Page Number new interface
Line Number newinterface
Interp Status ---
Final Accepted Text
Summary 0001138: Add strsignal(), sig2str() and str2sig() to the standard.
Description Solaris contains:

char * strsignal(int signum) signal number -> sig destription

int str2sig(const char *s, int *sigp) signal name -> signal number

int sig2str(int i, char *s) signal number -> signal name

We should add these interfaces to permit e.g. the kill command to be implemented with POSIX interfaces.
Desired Action Add strsignal() to string.h
Add sig2str() and str2sig() to signal.h

Add the three functions to the system interfaces descriptions.

We might be able to use the Solaris man pages as a starter for the text.
Tags No tags attached.
Attached Files

- Relationships

-  Notes
(0003678)
joerg (reporter)
2017-04-27 12:11

I forgot: add SIG2STR_MAX to signal.h
(0003679)
schwarze (reporter)
2017-04-27 13:32

schwarze@isnote $ man strsignal | col -b | sed -n '/^STAN/,$p'
STANDARDS
     The strsignal() function conforms to IEEE Std 1003.1-2008 (POSIX.1).

HISTORY
     The strsignal() function first appeared in AT&T SystemV Release4 UNIX
     and was reimplemented for NetBSD 1.0.

OpenBSD 6.1 June 5, 2013 OpenBSD 6.1

http://pubs.opengroup.org/onlinepubs/9699919799/functions/strsignal.html [^]


Public functions str2sig(3) or sig2str(3) do not exist in FreeBSD or NetBSD, and definitely not in OpenBSD. Regarding DragonFly and the Linux man pages project, i don't see these functions in the manual pages either (while i do see strsignal(3) there).

In FreeBSD, the name str2sig() clashes with at least one static symbol (in usr.bin/fstat/fuser.c). Probably not a big problem, just mentioning it for completeness.

The only systems where i do see evidence for public str2sig(3) and sig2str(3) are illumos and Oracle Solaris 9 to 11.

Is that sufficiently common for standardization? Just asking... As far as i understand, establishing new interfaces is not the typical job of POSIX.
(0003680)
joerg (reporter)
2017-04-27 14:15

Thank you for the hint that I missed to find strsignal() in the standard ;-)

In order to ad a new interface, there should be a need for that interface andI believe that the two functions would help programmers to write portable programs in special as many singal numbers are not unique across platforms.
(0003681)
kre (reporter)
2017-04-27 15:47

Re (note 3680)
    In order to ad a new interface, there should be a need for that interface

Quite correct, but "I believe" is not evidence of that. The way to do it is
to actually implement the interface, and have it actually used (as note 3679
suggests).

That way we get some real evidence that the interface proposed is the correct
one.

For example, I wouldn't implement either of the 2 proposed new functions with
the function prototype you gave, for me it would be ...

int str2sig(const char *s) signal name -> signal number

int sig2str(int i, char *s, size_t len) signal number -> signal name

(and that still leaves aside the choice of names, str_to_sig() (etc) would
be another possibility - but with naming it tends to be whatever becomes
popular first, as there is no one right answer.)

For str2sig() a return value of 0 would indicate an error (no such sig name)
as the one thing we know about signal numbers is that 0 is not one of them.

And for sig2str() we need a buffer length arg, as while we might "just know"
that SIG2STR_MAX is sufficient, implementing things that way means that
there's no possibility to ever increase that value (or binary compat/safety is
lost.) The constant can still exist, but it should just be for users to size
the buffer, not for the internals of the function to use.

But all of this is just my opinion, the only way we ever really know what
works is for users to use the interface, and be happy enough that they use
it (not just reinvent it) and don't keep asking for changes.
(0003682)
jilles (reporter)
2017-04-27 16:30

Various BSD systems provide an extern const char * const sys_signame[]; from libc, such that sys_signame[SIGHUP] is "HUP", etc.

However, a function interface is superior to an array. Using common ELF linking, non-PIE executables use copy relocations to access the array, which means that changing its size is not binary compatible, and exporting an array like this forces the inefficient pattern of pointers to static data in a shared library, which need to be relocated in every process using the library even if that process does not use the array at all.

Note that signal names, unlike strsignal() messages, are not translatable.

Existing software that needs to work with signal names tends to either use interfaces like sys_signame and sig2str/str2sig, or create its own table using a list of signals that may exist, like

char *table[] = {
#ifdef SIGFOO
        [SIGFOO] = "FOO",
#endif
...
}
(0003685)
joerg (reporter)
2017-05-04 10:57

For making portable shell implementations easier, it would be a good idea if
the standard also adds a "NSIG" definition that may redirect to a getconf()
call.
(0003686)
kre (reporter)
2017-05-04 12:29

NSIG is not useful unless we also make assumptions about the values
used for the signal numbers, like that they are from 1..NSIG which
the standard avoids doing (and should continue to do.)

I am soon going to delete the earlier note I posted with the proposal I made
to NetBSD developers, and replace it with the current (simpler) version,
which has no need of an NSIG definition.
(0003688)
kre (reporter)
2017-05-10 02:00
edited on: 2017-05-10 02:31

Note that this note replaces an earlier note (3683, and 3684) which described
an earlier proposal.

I have just added, to NetBSD, functions as described in the
man page I am including in this note. If there is ever a desire to add
functions for this purpose to POSIX, please consider these as alternatives
to str2sig() and sig2str() as included above (I am not requesting that they
actually be included, just that I believe these are better than those...)

Complete source (such as it is - quite *BSD dependent, as they use sys_signame
as described by Jilles in note 3682) is available (for a time anyway) from
    ftp://munnari.oz.au/kre/signame.tgz [^] [^]
(files unpack into the current directory, a test program can be built, on
BSD systems anyway, by "cc *.c" - there is no Makefile.)

Note at the end where it says "First appeared in NetBSD 8.0" - 8.0 has
not been released yet (getting closer, but still some way away.)

The functions described are all pure, and thread safe (though depending upon
the implementation might need some internal locking while acquiring the data
from the system). The current NetBSD implementations are async-signal-safe,
but I would not specify them that way, in order to allow the implementation to
use whatever means it desires to initialise its state. And in any case,
there is almost no possible need for these functions in a signal handler,
the signal number is provided (so we know its number, and that it is valid)
and while the name may be of interest, the results of strsignal() are far
more likely to be relevant.

kre

NAME
     signalname signalnumber signalnext -- convert between signal numbers and
     names

LIBRARY
     Standard C Library (libc, -lc)

SYNOPSIS
     #include <signal.h>

     const char *
     signalname(int sig);

     int
     signalnumber(const char *name);

     int
     signalnext(int sig);

DESCRIPTION
     The signalname() function takes a signal number sig, and returns the name
     of that signal. The name returned is locale independent, and can be the
     string representation of one of the signal names from <signal.h> such as
     SIGHUP, SIGSTOP, SIGKILL, or some similar name, but does not contain the
     leading ``SIG'' prefix.

     The return value of signalname() is NULL if sig does not represent a
     valid signal number, or if the signal number given has no name.

     The signalnumber() function converts the signal name name to the number
     corresponding to that signal. The name is handled in a case-insensitive
     manner. Any leading ``SIG'' prefix in name is ignored.

     The signalnumber() function returns the signal number, or zero (0) if the
     name given does not represent a valid signal.

     The signalnext() function takes a signal number, and returns the number
     of the next available bigger signal number. When no higher signal
     numbers remain, it returns zero (0). The parameter sig can be given as
     zero (0), to obtain the smallest implemented signal number.

     The signalnext() function returns minus one (-1) on error, if the given
     signal sig is neither a valid signal number, nor zero. It returns zero
     when the input signal number, sig, is the biggest available signal
     number. Otherwise it returns the signal number of an implemented signal
     that is larger than sig and such that there are no implemented signals
     with values between sig and the value returned.

     The signalnext() function can also be used to determine if a non-zero
     signal number is valid or not (0 is always invalid, but cannot be
     detected as such this way.) Given the non-zero signal number to check as
     sig, if signalnext() returns anything other than minus one (-1) then sig
     represents a valid signal number. If the return value is -1 then sig is
     invalid.

SEE ALSO
     kill(1), intro(2), psignal(3), strsignal(3)

HISTORY
     The signalname(), signalnext() and signalnumber() functions first
     appeared in NetBSD 8.0.

(0004148)
Don Cragun (manager)
2018-10-11 15:48

After discussing this in the 2018-10-11 conference call, we have asked the Open Group OR to see if The Open Group would sponsor adding sig2str() and str2sig() to a future revision of the standard.
(0004212)
ajosey (manager)
2019-01-16 13:36

The Open Group Base Working group has agreed to sponsor the addition of sig2str() and str2sig() as a new work item. The next stage will be to develop manual page entries for review and eventual approval at The Open Group.
(0004975)
geoffclare (manager)
2020-09-08 09:30
edited on: 2020-10-23 10:57

Suggested changes to go into The Open Group company review...

On page 333 line 11275 section <signal.h>, add:
[CX]The <signal.h> header shall define the following symbolic constant. The value shall be suitable for use in #if preprocessing directives:

SIG2STR_MAX
Maximum size of a signal name returned by sig2str(), including the terminating null byte.[/CX]

On page 338 line 11462 section <signal.h>, add:
[CX]int sig2str(int, char *);[/CX]

On page 338 line 11485 section <signal.h>, add:
[CX]int str2sig(const char *restrict, int *restrict);[/CX]

On page 339 line 11501 section <signal.h>, add sig2str() to SEE ALSO.

On page 494 line 17105 section 2.4.3, add sig2str() to the list of async-signal-safe functions.

On page 1950 insert a new sig2str page:

NAME
sig2str, str2sig -- translate between signal names and numbers

SYNOPSIS
#include <signal.h>

[CX]int sig2str(int signum, char *str);
int str2sig(const char *restrict str, int *restrict pnum);[/CX]

DESCRIPTION
The sig2str() function shall translate the signal number specified by signum to a signal name and shall store this string in the location specified by str. The application shall ensure that str points to a location that can store the string including the terminating null byte. The symbolic constant SIG2STR_MAX defined in <signal.h> gives the maximum number of bytes required.

If signum is equal to 0, the behavior is unspecified.

If signum is equal to one of the symbolic constants listed in the table of signal numbers in [xref to <signal.h>], the stored signal name shall be the name of the symbolic constant without the SIG prefix.

If signum is equal to SIGRTMIN or SIGRTMAX, the stored string shall be "RTMIN" or "RTMAX", respectively.

If signum is between SIGRTMIN+1 and (SIGRTMIN+SIGRTMAX)/2 inclusive, the stored string shall be of the form "RTMIN+n", where n is the shortest decimal representation of the value of signum-SIGRTMIN.

If signum is between (SIGRTMIN+SIGRTMAX)/2 + 1 and SIGRTMAX-1 inclusive, the stored string shall be either of the form "RTMIN+n" or of the form "RTMAX-m", where n is the shortest decimal representation of the value of signum-SIGRTMIN and m is the shortest decimal representation of the value of SIGRTMAX-signum.

If signum is a valid, supported signal number, is either less than SIGRTMIN or greater than SIGRTMAX, and is not equal to one of the symbolic constants listed in the table of signal numbers in [xref to <signal.h>], the stored string shall uniquely identify the signal number signum in an unspecified manner.

The str2sig() function shall translate the signal name in the string pointed to by str to a signal number and shall store this value in the location specified by pnum.

If str points to a string containing the name of one of the symbolic constants listed in the table of signal numbers in [xref to <signal.h>], without the SIG prefix, the stored signal number shall be equal to the value of the symbolic constant.

If str points to the string "RTMIN" or "RTMAX", the stored value shall be equal to SIGRTMIN or SIGRTMAX, respectively.

If str points to a string of the form "RTMIN+n", where n is a decimal representation of a number between 1 and SIGRTMAX-SIGRTMIN-1 inclusive, the stored value shall be equal to SIGRTMIN+n.

If str points to a string of the form "RTMAX-n", where n is a decimal representation of a number between 1 and SIGRTMAX-SIGRTMIN-1 inclusive, the stored value shall be equal to SIGRTMAX-n.

If str points to a string containing a decimal representation of a valid, supported signal number, the value stored in the location pointed to by pnum shall be equal to that number.

If str points to a string containing a decimal representation of the value 0 and the string was not returned by a previous successful call to sig2str() with a signum argument of 0, the behavior is unspecified.

If str points to a string returned by a previous successful call to sig2str(signum, str), the value stored in the location pointed to by pnum shall be equal to signum.

If str points to a string that does not meet any of the above criteria, str2sig() shall store a value in the location pointed to by pnum if and only if it recognizes the string as an additional implementation-dependent form of signal name.

RETURN VALUE
If signum is a valid, supported signal number (that is, one for which kill() does not return -1 with errno set to [EINVAL]), the sig2str() function shall return 0; otherwise, if signum is not equal to 0, it shall return -1.

If str2sig() stores a value in the location pointed to by pnum, it shall return 0; otherwise, it shall return -1.

ERRORS
No errors are defined.

EXAMPLES
None.

APPLICATION USAGE
None.

RATIONALE
Historical versions of these functions translated a signum value 0 to "EXIT" (and vice versa), so that they could be used by the shell for the trap utility. When adding the functions to this standard, the standard developers felt that they should be aimed at more general-purpose use, and consequently requiring this behavior did not seem appropriate and so the behavior in this case has been made unspecified.

FUTURE DIRECTIONS
None.

SEE ALSO
kill(), sigaction(), strsignal()

XBD <signal.h>

CHANGE HISTORY
First released in Issue 8.

Add sig2str() to the SEE ALSO section for each function page listed in the sig2str() SEE ALSO above.

On page 3792 line 130152 section E.1, add sig2str() and str2sig() to the POSIX_SIGNALS_EXT subprofile group.

(0004976)
kre (reporter)
2020-09-08 15:32

Re: Note: 0004975

Aside from most likely being an exact specification of what the Solaris
(maybe linux too) implementations happen to do, that is wildly over specified
for the purposes required here, and also technically wrong.

I cannot even begin to imagine where a sig2str() function would be returning
"EXIT" for "signal" 0 - 0 as a trap number relating to EXIT is a shell function,
and has no place at all in the generic OS interface. The XBD page for signal.h
says:

    The value 0 is reserved for use as the null signal (see kill( )).

which has no relationship at all with anything relating to exit. But I
suppose the Solaris function was defined for use in "trap -l" in sh, and
so it was convenient to have 0 return "EXIT". That implementation quirk has
no business being standardised here.

Aside: note that strsignal() and psignal() (and psiginfo()) which are
functions initially designed for regular applications to use aren't
required to return anything related to "exit" for "signal number" 0.


Beyond that, I see no particular reason why the exact signal named from
signal.h (with the SIG removed) are required to be returned - what's important
is that the names returned by sig2str() be able to be used as input to
str2sig() and result in the correct signal number being returned.

Far worse (as far as overspecification goes) is the description of how the
real time signals are to be handled. Why would anyone want to specify things
in that much detail? Aside from that happening to be what the Solaris
implementation does? Assuming that an implementation decides to return strings
in the RTMIN+n form, why cannot it always reurn RTMIN+n for all real time
signals, for n in the range [0..SIGRTMAX-SIGRTMIN] if that's what the
implementation prefers, or RTMAX-n (same range) or split the +n/-n variants
anywhere else it pleases? What conceivable reason is there for mandating
that particular split.

That is, even if it were correct, if SIGRTMIN==33 and SIGRTMAX==64 then
(SIGRTMIN+SIGRTMAX)/2 == 48.5 and since signals all have integral values,
that means that "If signum is between SIGRTMIN+1 and (SIGRTMIN+SIGRTMAX)/2
inclusive" means signals 34..48, and (SIGRTMIN+SIGRTMAX)/2 + 1 == 49.5,
which means that "If signum is between (SIGRTMIN+SIGRTMAX)/2 + 1 and
SIGRTMAX-1 inclusive" covers signals 50..63. What is to be done with 49?

Now obviously one could stick floor() calls around the results of the division
and avoid that issue, but much better would simply be to state (which is
actually already there) that for any signals which exist, but which don't
have names in signal.h an implementation defined string shall be returned.
That then covers the real time signals, and allows RTMIN+n RTMAX-n or
anything else the implementation chooses to provide - as long as the string
returned when handed to str2sig() will return the correct value.

The NetBSD implementation (which is as described in Note: 0003688 except that
it now also allows the RTMIN+n and RTMAX-n forms as args to signalnumber())
has real individual names for the real time signals. OK, they're boring
names, but they are a name for each signal. And that's what signalname()
returns for the real time signals (and signalnumber() translates back to
the appropriate number). Why should we be prohibited from returning those
names and be required to return the RTMIN+n (etc) format?

Just delete 90% of what is there, and say what the functions do, and what
the requirements on the implementation really are (justifiable requirements)
and leave out all of the Solaris implementation detail.

Next, why are we presuming that all values from 1 .. NSIG_MAX represent
signals? There's nothing elsewhere in the standard that requires that,
yet the text here says:

   If signum is between 1 and {NSIG_MAX}-1 inclusive, is either less than
   SIGRTMIN or greater than SIGRTMAX, and is not equal to one of the signal
   numbers for which a symbolic constant is defined in the <signal.h> header,
   the stored string shall uniquely identify the signal number signum in an
   unspecified manner.

which is saying that every value from 1 to NSIG_MAX-1 is required to be a
valid signal number? Why is that? My impression (which might be wrong)
is that FreeBSD have the "normal" signals in the block 1..n (for some n)
and the real time signals in a block which I think started at about 2*n
(give or take a few) - which is actually a very reasonable thing to do, as
it allows more signals to be added, in the same basic range as the existing
ones, without requiring the real time signals be renumbered (that is, doesn't
have the real time signals in the middle between different groups of
non-real-time signals).

Next:

Next, and perhaps worst, in this day and age, we should not be standardising
any interfaces where the application passes in a pointer to a string which is
simply assumed to be big enough for the result. That's insane. I appreciate
that implementations which defined such interfaces in the past, when we didn't
know better, are stuck with supporting them forever, but there's no reason we
should be encouraging applications to use this nonsense,

At the very least the function should take a buffer length arg, to indicate
to the size that is available for the functions to write in (but that would
mean inventing something new, as there are no known implementations that
work like that) - but there is no reason that sig2str() (unlike say
strsignal()) could not return a pointer to a const char * - there aren't all
that many signals in any implementation (most < 100, but even 1000 would
be manageable) that the implementation cannot simply build a table of
string names (including each "RTMIN+1" "RTMIN+2" ... if that is what it
decidesto use) and return a pointer to the one of those that represents the
signum, and use the same table to translate the name back to a number for
str2sig(). That's a much nicer and safer interface, and is trivial to
implement (it is also faster as there is no string copying involved).

strsignal() can't work that way, as it returns a locale dependant string,
but sig2str() does not, so compiling the names into read-only memory
(ie: const char[]) in the function is easy and safe here (it is also thread
safe, and because of the "const" there's no issue with what happens if
the application mofifies the result (it cannot).

The NetBSD functions mentioned in Note: 0003688 do exist (and have for
multiple NetBSD releases now) and work that way without issue (of course,
they don't handle the EXIT nonsense).


More trivial issues:

    If str points to a string containing the name of one of the symbolic
    constants defined in the <signal.h> header that expands to a signal number,

One of those constants, if Note: 0004975 was accepted as written, is
SIG2STR_MAX which is likely to have a value (in most implementations)
somewhere around 8..10 (enough to hold RTMAX-nn\0) which is typically
longer than any SIGxxxx with the SIG part removed. Those values are
signal numbers (or at least it is possible to read the text that way)
as signal numbers are simly integers between 1 and NSIG_MAX-1 (incl) and
NSIG_MAX is going to be much bigger than 10 (it must be, there are more
than 10 defined signals).

Aside from that one, signal.h also contains SIGEV_NONE SIGEV_SIGNAL and
SIGEV_THREAD, the latter two of which are also likely to be valid signal
numbers (and all might be). On NetBSD they are 0, 1 and 2 resp. 1 and
2 are valid signal numbers.

There's also SIG_IGN which is typically 1, though that one is less clear,
as its value isn't an integer, but cast to be a pointer.

I doubt that the intent is that any of these are intended to be valid inputs
to str2sig() - so assuming that the text needs to say any more than that the
range of inputs to str2sig() is any different than the outputs from sig2str()
(whatever that might be) it needs to be written more precisely.

But, even more trivially,to continue that quote (expans it)

     If str points to a string containing the name of one of the symbolic
     constants defined in the <signal.h> header that expands to a signal
     number, without the SIG prefix,

that's a very poorly constructed sentence, assuming it did not need to be
rewritten anyway, then something more like

     If str points to a string containing the name of one of the symbolic
     constants that expands to a signal number, as defined in the <signal.h>
     header, without the SIG prefix,

[aside; apart from "that is what the solaris implementation did" why are we
so hung up on "without the SIG prefix" ? Why not make that implementation
defined?]

One more not-really related issue that I'll mention, the psignal() function
has no page of its own, it appears in the psiginfo() page only. Most of the
times when multiple functions are defined in one page in XSH, the ones that
come after the first are given pages that just say (in this case) "see psiginfo"


Finally, I continue to object to NSIG_MAX even existing - it is just a mild
objection, since I can easily set it to INT_MAX (with a suitable definition of
sigset_t which is easy to do) and forget it (or perhaps UINT_MAX). That that
limits the signals to no more than INT_MAX-1 (or UINT_MAX-1) because NSIG_MAX
for no particularly good reason is the highest possible signal number, plus 1, is irritating, but we can probably live with that.

Constants like that (unlike the dynamic values returned from sysconf())
make maintaining binary compatibility much harder than it otherwise needs
to be - some app is built when NSIG_MAX was 128 and then we decide we want
to change it to 256 - app breaks. So once set it can never be altered
again. Better not to have constants like that at all - especially not
newly invented ones that aren't required for any API compat with the past.
(0004977)
joerg (reporter)
2020-09-08 21:37

Just in case this is not known...

str2sig() and sig2str() exist since 32 years while it seems that the netbsd functions apparently have been been created just at the time when Note: 0003688 was entered.

So str2sig() and sig2str() are 29 years older and a web search for these functions results in the related man pages. A web search for "signalname" does not result in a pointer to the related man page.

I guess that no existing portable software supports the signalname() interface.

And BTW: stg2str(0, ...) returns "EXIT" as expected by the shell.
(0004978)
kre (reporter)
2020-09-08 22:49

Re: Note: 0004977

    str2sig() and sig2str() exist since 32 years

I expect that's true, but in all that time, they've hardly been used,
or they would have been in the standard from the beginning. The design
of these functions (as with others of that vintage) also leads a lot to
be desired.

    while it seems that the netbsd functions apparently have been
    been created just at the time when Note: 0003688 was entered

true as well, the requested functions were designed in a time when there
were no real concerns about defensive programming, and everyone knew that
if a "big enough" buffer was needed, one would be provided. gets() was
still a popular function back then. When I saw this issue I set out to
see if there might not be a better interface design that would solve the
same problem, and after some discussions on the NetBSD mailing lists, the
result is what was implemented, and then was published here in Note: 0003688

I'm not seriously expecting anyone to add the netbsd functions to posix,
or not any time soon - they haven't been around long enough, and aren't
widely supported enough.

I have no idea how web search engines decide what to show, or how they
locate man pages - the netbsd functions man page (one page for all 3
functions) has been around, and is and has been available on the web
for several years now. You can find them at
      https://man.netbsd.org/signalname.3 [^]
They used to also be available via man-k.org but that seems to be
unavailable now.

But this is I think the crux of this issue:

    And BTW: stg2str(0, ...) returns "EXIT" as expected by the shell.

Yes, that has been made clear. And what that says is that these functions
are really internal shell interfaces. Like any other internal shell
implementation detail, they have no real reason to appear in the standard.
As defined, they're essentially useless to anything other than the shell,
and its (usually) built in commands (a couple of them) and a few other
commands that are clones of those. They have no general purpose applicability
at all. The only difference between these functions, and some other local
function in the shell is that they can vary from system to system (but they're
not the only instance of that).

The right thing to do is simply reject this enhancement request, and not add
these functions to the standard at all.

I understand how it is useful for a shell implementation to be able to depend
upon functions like these existing for each system the shell is to be used
upon, but that is not, IMO, a good enough reason for them to appear here.


If anyone ever finds a general purpose use for being able to translate between
signal names and their equivalent numbers (which can't be achieved by simply
including <signal.h> and referring to the defined names) then perhaps a new
interface will be designed - maybe something like the NetBSD ones, maybe not,
and perhaps if that need becomes widespread enough, in some later version of
the standard, a decade or two from now, something could be added. But
whatever that looks like, the chances of it (them) having an interface
anything like sig2str() is close to zero. But I'm not going to hold my
breath, there is little need for the functionality provided (outside the
shell and related commands) so I can't see anyone bothering.
(0004980)
joerg (reporter)
2020-09-09 11:27

Re Note: 0004978

str2sig() and sig2str() are widely used since approx. 1995 I guess this is quite a while now.

Regarding what is in the standard and what is not.....

In 1988/1992, people had problems to get to a standard at all and with respect to the bug fixes in the past few years, my impression is that many people did not read the standard in depth in former times, so problems in the standard have not been discovered.

Look e.g. at the waitid() interface that has been added early but nobody discovered that someone forgot to change the documentation for exit() to mention that the masking with 0xFF only is in effect if the exit status is retrieved by the historic functions. This is where most programmers are srtill living in the 1970s, probably caused by plenty of incorrect implementations in the past

Look e.g. at the strl*() functions that have been introduced around 1995 by OpenBSD (IIRC), rated highly useful and copied by nearly any platform but Linux. The reason why it has not been added to POSIX so far is that one person claimed that the interface is bad, while it is still the best related interface we have in the UNIX world...

The interesting aspect of this meta discussion is that in the 1980s, it usually did take 1-2 years for a new useful idea to appear in other UNIX versions as well. Not that we have a standard, this takes longer.

I would be happy, if problems like this one could disappear.
(0004981)
geoffclare (manager)
2020-09-10 10:59

I have edited Note: 0004975 to address some of the points raised in Note: 0004976. In particular:
  • Instead of all values from 0 to {NSIG_MAX}-1 being translated, now only 0 and valid, supported signal numbers are translated.

  • The reference to the table of signal numbers on the <signal.h> page is clarified.
(0004982)
kre (reporter)
2020-09-10 13:05

The changes mentioned in Note: 0004981 look good, and resolve the trivial
issues they address, but of course do nothing to address the substantial
issues.

One other thing I failed to notice before, you're making the proposed new
interfaces async signal safe. Is that wise? While the actual (current)
implementation of the NetBSD variants for the same functionality is, and
I assume the Solaris version is as well, that is one thing I did not promise
about the NetBSD implementation.

It is entirely possible that an implementation of these might obtain the
data required from some external source (a system call, a file, or ...) and
need to malloc memory to save that data for later calls (there's no question
of free() being needed - once obtained it would simply remain).

An implementation like that is future-proof for statically linked programs,
otherwise if simply using compiled-in data, what these functions return are
the names/numbers of signals that existed at the time the application was
compiled (perhaps years, or decades, ago) rather than the current versions.

Or is the plan here to require all implementations to copy the implementation
method of the SysVR4/Solaris version, as well as its broken interface ?
(0004983)
joerg (reporter)
2020-09-10 13:30

Statically linked programs are not future proof. Solaris has given them up 15 years ago, after introducing a new desaster revovery method based on shared libraries. All you need is a known backup copy of the last working libc and for the really hard cases an alternate failproof boot environment.

The combination of a kernel and it's related shared libc provides the POSIX interfaces.

If you do this, the SVr4 method that does not need malloc() is just fine.
(0004984)
geoffclare (manager)
2020-09-10 14:31
edited on: 2020-09-10 14:31

Re: Note: 0004982 In the current proposal only sig2str() is required to be async-signal-safe as that is the one that applications might want to use in a signal handler.

Since open(), read() and close() are async-signal-safe, there is no reason a sig2str() that reads the info from a file could not be written in an async-signal-safe way.

(0004986)
kre (reporter)
2020-09-10 19:01

Re Note: 0004984

It makes no real difference whether one or both of these are required to
be async-signal-safe - if one is, the other will be - they use the exact
same data mapping names to numbers, just one looks up the name, and returns
the number, and the other looks up the number and returns the name.

It is getting the data that is the issue, the lookups and result returning
are not an issue.

While open/read/close are OK to use (as is stat() which might be needed),
malloc() is not, and until we see the file (its size, or perhaps its contents)
we don't know how big the buffer might need to be. If we have to malloc()
we cannot be async-signal-safe.

Re Note: 0004983 ... I am not implementing Solaris, nor am I copying its
decisions. We still allow (and actually generate some) static binaries
and they should work (and ideally keep on working into the future). While
there are issues with running really old static binaries, with careful
attention by the system, it can be done. But some data cannot help needing
to be updated, that data cannot be built into the application, or any
library it uses, or it will certainly cause problems. While I don't really
care about these functions for NetBSD, as absolutely nothing would ever
use them, I do care that the standard isn't written in a way that precludes
various different (reasonable) implementations.

The remote outside chance that some application might want to use sig2str()
in a signal handler doesn't justify forcing a low quality implementation.
(0004987)
geoffclare (manager)
2020-09-14 08:13
edited on: 2020-09-14 08:14

Re Note: 0004986 str2sig() does not just "look up the name and return the number", it also does string to integer conversion, and neither atoi() nor strtol() is in the list of async-signal-safe functions.

(0004988)
kre (reporter)
2020-09-14 13:59

Re Note: Note: 0004987 - nothing in the description of the interface says
that str2sig() uses either atoi() or strtol() - it is possible to convert
a string of digits to an integer in a 100% async-signal-safe way. Particularly
when the size of the resulting integer most likely doesn't even approach
the limits (the value would be too big to be a signal, on most implementations,
way before integer overflow becomes an issue).

However, as my position is that these functions (neither of them) ought to
be listed as async-signal-safe, this really doesn't matter to me.

This point also raises the question of why str2sig() is doing that? Do
we really need yet another atoi() in the library? I can see some utility
of having a function which can convert either a signal name, or the string
form of its numeric value, into the signal number - it makes coding a fraction
simpler and means that all applications will offer those alternatives
(assuming that there really are any other than sh & kill (and its clones)
which use these) .

But it means that even if the application only wants the names to work.

I think it would be better to leave it unspecified what happens when a
digit string is given to str2sig(). Apps that want to allow numeric input
can easily call strtol() (one hopes not atoi()) and make that happen.
This would also improve the symmetry of the two functions, anything is
defined to work as input to str2sig() would also be the defined output
of sig2str() - that doesn't happen when str2sig() converts a numeric arg.

Beyond that the specification doesn't make clear what happens when the
input is something like "13apples". My guess, given its vintage(), is
that the SysVR4 implementation probably just does something like

     if (isdigit(str[0])) sig = atoi(str);

(and then maybe bounds checks sig, maybe - since I assume it assumes that
all signals from 1..n are valid, which they probably are in SysVR4, and
Solaris) no more "valid signal number" check would be needed. If my guess
is right the str2sig("13apples", ...) would return (as the signal) "13".
Is that to be the required behaviour?

As an aside: apart from that signal handlers shouldn't be doing anything
nearly as complex as converting strings to integers (nor converting integers
into signal names) I can't think of a particularly good reason that atoi()
or strtol() aren't listed as async-signal-safe. Is there an implementation
of them somewhere where they aren't?

But once again, the best outcome here would be to simply reject this
proposal, and add nothing to the standard.
(0004989)
eblake (manager)
2020-09-14 14:11

Regarding Note: 0004988 on strtol() not being async-signal-safe: that's because it is locale-dependent (some locales have different thousands separators, and the parsing of strings into numbers is permitted to take that difference into account when deciding what to parse). As consulting the locale means interacting with environment variables, the whole function becomes non-async-safe.
(0004990)
geoffclare (manager)
2020-09-14 14:53

Re Note: 0004988 The Solaris code (assuming it hasn't changed in Illumos) uses strtol() and checks that the returned end pointer points to a null byte. It also looks up the resulting integer in the table. So str2sig("13apples", ...) returns an error.

https://github.com/illumos/illumos-gate/blob/master/usr/src/lib/libc/port/gen/str2sig.c [^]
(0004993)
kre (reporter)
2020-09-14 17:52

Re Note: Note: 0004989 ... yes, of course, somewhere I think I kind of knew that.
Thanks.

With that, and Note: 0004990 clearly no-one is going to make str2sig
async-signal-safe. So just don't make either that way - after all
an implementation of sig2str() might decide to call str2sig() on the
answer to make sure that the correct value was generated. Why not?
(0005040)
geoffclare (manager)
2020-10-09 09:38

As agreed in the Oct 8th teleconference, Note: 0004975 has been updated to make the behaviour for a signum value of 0 unspecified.
(0005045)
mkerrisk (reporter)
2020-10-11 06:23
edited on: 2020-10-11 07:16

Just by way of background, I note that the GNU C Library (glibc) recently (v2.32, Aug 2020) added:

    const char *sigabbrev_np(int signum)
        "This function returns the abbreviation describing the
         signal signum or NULL for invalid signal number. The
         message points to a static storage whose lifetime is
         the whole lifetime of the program."

For example, it returns "HUP" for SIGHUP.

(0005061)
geoffclare (manager)
2020-10-23 15:15

The sig2str() and str2sig() additions have been made in the Issue8NewAPIs branch in gitlab, based on Note: 0004975.

- Issue History
Date Modified Username Field Change
2017-04-27 12:02 joerg New Issue
2017-04-27 12:02 joerg Name => Jörg Schilling
2017-04-27 12:02 joerg Section => System Interfaces
2017-04-27 12:02 joerg Page Number => new interface
2017-04-27 12:02 joerg Line Number => newinterface
2017-04-27 12:11 joerg Note Added: 0003678
2017-04-27 13:32 schwarze Note Added: 0003679
2017-04-27 14:15 joerg Note Added: 0003680
2017-04-27 15:47 kre Note Added: 0003681
2017-04-27 16:30 jilles Note Added: 0003682
2017-04-28 02:14 kre Note Added: 0003683
2017-04-28 02:49 kre Note Added: 0003684
2017-05-04 10:57 joerg Note Added: 0003685
2017-05-04 12:29 kre Note Added: 0003686
2017-05-10 02:00 kre Note Added: 0003688
2017-05-10 02:00 kre Note Deleted: 0003683
2017-05-10 02:00 kre Note Deleted: 0003684
2017-05-10 02:31 kre Note Edited: 0003688
2017-05-10 02:31 kre Note Edited: 0003688
2018-10-11 15:48 Don Cragun Note Added: 0004148
2019-01-16 13:36 ajosey Note Added: 0004212
2020-09-08 09:30 geoffclare Note Added: 0004975
2020-09-08 09:30 geoffclare Note Edited: 0004975
2020-09-08 15:32 kre Note Added: 0004976
2020-09-08 21:37 joerg Note Added: 0004977
2020-09-08 22:49 kre Note Added: 0004978
2020-09-08 23:12 kre Note Added: 0004979
2020-09-08 23:13 kre Note Deleted: 0004979
2020-09-09 11:27 joerg Note Added: 0004980
2020-09-10 10:55 geoffclare Note Edited: 0004975
2020-09-10 10:59 geoffclare Note Added: 0004981
2020-09-10 13:05 kre Note Added: 0004982
2020-09-10 13:30 joerg Note Added: 0004983
2020-09-10 14:31 geoffclare Note Added: 0004984
2020-09-10 14:31 geoffclare Note Edited: 0004984
2020-09-10 19:01 kre Note Added: 0004986
2020-09-14 07:26 geoffclare Note Edited: 0004975
2020-09-14 08:00 geoffclare Note Edited: 0004975
2020-09-14 08:13 geoffclare Note Added: 0004987
2020-09-14 08:14 geoffclare Note Edited: 0004987
2020-09-14 13:59 kre Note Added: 0004988
2020-09-14 14:11 eblake Note Added: 0004989
2020-09-14 14:53 geoffclare Note Added: 0004990
2020-09-14 17:52 kre Note Added: 0004993
2020-10-09 09:31 geoffclare Note Edited: 0004975
2020-10-09 09:38 geoffclare Note Added: 0005040
2020-10-11 06:23 mkerrisk Note Added: 0005045
2020-10-11 07:15 mkerrisk Note Edited: 0005045
2020-10-11 07:16 mkerrisk Note Edited: 0005045
2020-10-23 10:57 geoffclare Note Edited: 0004975
2020-10-23 15:15 geoffclare Note Added: 0005061


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker