Skip to content

Added implementation for syslog related functionality. #136

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

Merged
merged 10 commits into from
Apr 2, 2021

Conversation

fabriziobertocci
Copy link
Contributor

Few comments on this implementation:


Linux: tested with a simple program. Works as expected (compared with libc syslog). Although I have to admit I did not do any extensive testing... will also add some tests to Cosmopolitan.


Windows works with some limitations as the logged messages uses Event ID = 0. Log viewer will report that this event ID is not defined, but will show the message content. E.g.:

The description for Event ID 0 from source fab cannot be found. Either the component that raises this event is not installed on your local computer or the installation is corrupted. You can install or repair the component on the local computer.
...

Is there a way with Cosmopolitan to use the message processor to build messages and add them to the executable? See: https://docs.microsoft.com/en-us/windows/win32/eventlog/message-text-files


I have added the implementation to the 'sock' subdirectory of libc (on Unix it uses Unix sockets to communicate with the syslogd...) please let me know if you prefer having it in another submodule or in a dedicated module (libc/syslog).

As part of the implementation I have added the definition of struct sockaddr_un in sock.h. According to the Linux man page, the size of sun_path should be 108 bytes and not 14 bytes. I have tried to modify the size of those structs to be consistent with a max path of 108 bytes, but that breaks the system calls (connect() and bind() end up failing). For the implementation of syslog this is not critical since syslog needs to connect to /dev/log (and 14 bytes are enough).


I had to modify the const generation script (libc/sysv/consts.sh) because all the Windows constants (LOG_INFO, LOG_ERR, LOG_USER, ...) were set to zero. Regarding this script, I've noticed the header says the last column is for XENIX, but the code generated (when the script is executed) produces files like libc/sysv/consts/LOG_INFO.S:

#include "libc/sysv/consts/syscon.internal.h"
.syscon log,LOG_INFO,6,6,6,6,6,6

but the macro syscon is defined as:

.macro  .syscon group:req name:req linux:req xnu:req freebsd:req openbsd:req netbsd:req windows:req

(last value says windows:req)... so I guess the const.sh comment is wrong (this file appears to be generated automatically from libc/sysv/newconsts.py... I don't understand if the consts.sh is automatically generated from newconsts.py or the newconsts.py was only used to create the first version... Please review this.


I have discovered another issue while implementing the syslog. The function send() appears to be duplicated in cosmopolitan. There are two implementations (and there are two versions inside the cosmopolitan.a: one defined in libc/sysv/calls/send.s and one in libc/sock/send.c. The version in the .s file appears to be for BSD only.

When using Cosmopolitan to build an application that uses send(), in my case, the linker picked one the one from send.c, but when I used send() inside vsyslog, it picked up the one for BSD, causing syslog to fail. Now, strangely enough if I changed the syslog implementation to use sendto() instead of send(), it picked the right version and worked. This is confusing and I don't know how to solve it. Please review and advise.

On Unix, the syslog facility will connect to the syslogd through
the Unix socket /dev/log. On Windows it uses the event logging
API (ReportEvent).
Had to add the constants for the LOG_xxxx values for Windows.
Copy link
Owner

@jart jart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but the macro syscon is defined as:

.syscon definition looks fine to me. It has eight params.

appears to be generated automatically from libc/sysv/newconsts.py

consts.sh was generated by a handful of scripts over the years. Many of them have been deleted from this repo. I should delete those Python scripts too, since they're likely to just confuse people. consts.sh needs to be de facto maintained by hand. Each time I refactor it in a major way I write a one-off script to do it.

I have discovered another issue while implementing the syslog. The function send() appears to be duplicated in cosmopolitan

Oh wow I didn't know about:

scall   send                    0xffffff065fffffff      globl

Could you send me a change commenting that out? That wasn't intended.

Is there a way with Cosmopolitan to use the message processor to build messages and add them to the executable? See: https://docs.microsoft.com/en-us/windows/win32/eventlog/message-text-files

Your guess is as good as mine here. I don't know much about this type of file. I don't see any evidence they're embedded in the PE structure so it probably doesn't need any APE hacks. You can probably just put it in a C string and supply it to the API?

@@ -1,2 +1,12 @@
.include "o/libc/nt/codegen.inc"
.imp advapi32,__imp_RegisterEventSourceW,RegisterEventSourceW,1687

.text.windows
RegisterEventSourceW:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Did you make the accompanying edit to libc/nt/master.sh? That's the script I use to generate these files.
  2. By convention Cosmopolitan removes the W from the end of NT function names, although it needs to remain on the __imp_ function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. So I don't understand how those functions are generated: the .S files were there but they only contain the first two line (the .include and the .imp). When linking Cosmopolitan I would get unresolved externals (I've noticed that some of the .S files have only those two lines, others have the rest). After adding the code to call to the sysv2nt, it worked.
    The lic/nt/master.sh already contained the line for those functions.

  2. Once I understand better what to do, I can fix/rename these functions ending with the W...

libc/sock/sock.h Outdated
@@ -40,6 +40,11 @@ struct sockaddr_in { /* Linux+NT ABI */
uint8_t sin_zero[8];
};

struct sockaddr_un {
uint16_t sun_family; /* AF_UNIX */
char sun_path[14];/* path */
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change 14 to 108.

Please note XNU and BSD define this as:

struct sockaddr_un {
        unsigned char   sun_len; /* sockaddr len including NUL on freebsd but excluding it on openbsd/xnu */
        uint16_t     sun_family;
        char    sun_path[104];
};

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well if I change the length to 108 is not going to work. First, there's a guard in sock/connect-sysv.c:

  if (addrsize != sizeof(struct sockaddr_in)) return einval();

That will require either removing that control or changing the size of all the sockaddr structures. I did try to resize sockaddr_in and sockaddr to match 108+2=110 bytes, but I would get an error from connect() and bind() at runtime.

Regarding the XNU and BSD. Shouldn't sun_family be an unsigned char? See: https://www.freebsd.org/cgi/man.cgi?query=unix&sektion=4. I don't have a BSD or XNU machine around to try.

So for XNU and BSD it's just a matter of adding the socakddr_un_bsd definition in internal.h ? The function sockaddr2bsd seems to adjust the len/family field and should work for connect and bind implementation.

// TODO: If we use send() it will end up calling the send stubs under
// sysv/calls/send.S and that will report ENOSYS (apparently that
// function serves only BSD). If we use sendto() it works as expected.
// Why send() does not call the send() function defined in sock/send.c ?
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, are you saying that send(sockfd, buf, len, flags); isn't equivalent to sendto(sockfd, buf, len, flags, NULL, 0); on BSD?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No no... they are equivalent, of course. My problem was that if I was using send(), the linker would pick up the wrong BSD send() and not the correct one under libc/sock/send.c. Now that I have commented out that wrong definition, I changed the code to use send(). I have just rebuilt (I realized I needed to manually delete the send.s file and perform a clean build) and run my sendlog test. Now it works.

@fabriziobertocci
Copy link
Contributor Author

but the macro syscon is defined as:

.syscon definition looks fine to me. It has eight params.

appears to be generated automatically from libc/sysv/newconsts.py

consts.sh was generated by a handful of scripts over the years. Many of them have been deleted from this repo. I should delete those Python scripts too, since they're likely to just confuse people. consts.sh needs to be de facto maintained by hand. Each time I refactor it in a major way I write a one-off script to do it.

Ok well I'll leave it to you to remove those Python scripts. I have changed the comment on consts.sh for the last column (Windows).

I have discovered another issue while implementing the syslog. The function send() appears to be duplicated in cosmopolitan

Oh wow I didn't know about:

scall   send                    0xffffff065fffffff      globl

Could you send me a change commenting that out? That wasn't intended.
I have commented out that line. Part of the next changeset.

Is there a way with Cosmopolitan to use the message processor to build messages and add them to the executable? See: https://docs.microsoft.com/en-us/windows/win32/eventlog/message-text-files

Your guess is as good as mine here. I don't know much about this type of file. I don't see any evidence they're embedded in the PE structure so it probably doesn't need any APE hacks. You can probably just put it in a C string and supply it to the API?

I would have to investigate a bit here. It's my understanding that you need to use a message processor on Windows and then either put those messages in the final executable (through some linker commands) or in the DLL... but I'm no expert here.
I think for the time being syslog works "ok" on Windows: the message gets logged, it's just not categorized correctly.

@fabriziobertocci
Copy link
Contributor Author

One more question regarding the implementation of syslog.
If you see in syslog.c I need to initialize those globals log_opt and log_facility with their default value. Unfortunately I cannot use LOG_ODELAY and LOG_USER because those are not constants.... so I had to come up with that mechanism to perform lazy initialization of those globals.
Is there a better way to initialize globals with values that are potentially platform dependent (like in this case) ?

required to work around to the duplication of the send() function.

Added implementation to automatically initialize the identity of the
logger through the use of the global `program_invocation_short_name`.
jart added a commit that referenced this pull request Mar 29, 2021
Credit goes to @fabriziobertocci for finding this. See #136.
@jart
Copy link
Owner

jart commented Mar 31, 2021

I needed to spend some time thinking about this one, since I wasn't sure at first if it'd be possible to polyfill sockaddr for unix domain sockets. Now I think it's not going to be an issue. It'll just require making some ugly changes to the sockaddr2bsd and sockaddr2linux functions. Would you like to do that?

You're right about sa_family_t. That is indeed unsigned char on BSDs.

Same goes for the sizeof check in connect-sysv.c. If my code is getting in the way, just change it. The systems are the source of truth. Cosmopolitan aims to track that truth as accurately as possible.

The regeneration scripts get run is as follows, from the root of the repository:

master jart@nightmare:~/cosmo$ libc/nt/master.sh
master jart@nightmare:~/cosmo$ libc/sysv/syscalls.sh
master jart@nightmare:~/cosmo$ libc/sysv/consts.sh

I can merge as soon as you're able to confirm you've made the appropriate edits to the golden files above, because I don't want your work to get accidentally deleted in the future.

Also, good news: I just published a release yesterday and your work is featured prominently in the release notes. https://github.com/jart/cosmopolitan/releases/tag/0.3

@fabriziobertocci
Copy link
Contributor Author

fabriziobertocci commented Apr 1, 2021 via email

…o match the standard of 108 characters. Modified the bind/connect/sendto to adjust to this change
@fabriziobertocci
Copy link
Contributor Author

fabriziobertocci commented Apr 1, 2021 via email

Copy link
Owner

@jart jart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good for merging. Good eye on the BSD issues. I'll write some tests locally once this is merged and work out the remaining kinks. Thank you for your contribution!

@jart jart merged commit 6682013 into jart:master Apr 2, 2021
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