You Have Mail

jruohonen1 pts0 comments

You Have Mail | Yet Another SysAdmin

You Have Mail

22 Nov, 2025

If you’ve ever logged in to a FreeBSD system, you have certainly seen the line “you have mail” .

No big deal might one say, it simply tells the user that there is mail to be read.

Indeed, that is the case… but have you maybe wondered how that is possible?

After all, it must come from somewhere, right ?!

Where to begin?

First of all, there must be some code that generates that message.<br>Given that the message is displayed after logging in to the system, the culprit must be login(1) .

This very program is what is spawned when you log onto your FreeBSD system - it also does the important job of authorizing the given user (Would be quite a mess if anyone could logon to the system after all - esp. without a password !)

Where to look?

Well, the only way we can find out where this message is coming from is checking the source code for the login program.

With all that said it is time to do just that!

Getting the src

If during install of your FreeBSD system you&rsquo;ve slected &ldquo;src&rdquo; than you are already set up and the sources can be found under /usr/src .

If you don&rsquo;t have the FreeBSD src tree you have multiple options available.

You can either clone the src tree or download a tarball and extract it.

Information can be found under the following link: https://docs.freebsd.org/en/books/handbook/mirrors/

If you want to follow along without getting the src tree you can use the public GitHub mirror - which makes it easy to just browse the src tree in the browser.

GitHub mirror: https://github.com/freebsd/freebsd-src

Alright, we are all set, let&rsquo;s dig into the code !

Tell me your secret

We have already established that during login a program named &ldquo;login&rdquo; is spawned on the tty .

Doing a which login tells us that the program is located under "/usr/bin/login" .

Given this clue let&rsquo;s look at the src tree.

If we navigate to src/usr.bin we can find a directory named &ldquo;login&rdquo; - this is the very source code of the program we are looking for!

In the directory in question we find the file login.c - A C program, where all the magic happens.

Let&rsquo;s open the file in our editor of choice and dig into it .

$ vim /usr/src/usr.bin/login/login.c

So far so good… but were is the magic that makes the message appear on login?

We are going to find out soon !

Delving into the code

Let&rsquo;s navigate to line 609 first.

if (!quietlog) {<br>...

Here we can see that a so called flag is checked (This is just a variable in C).

quietlog simply indicates if &ldquo;hushlogin&rdquo; is set by the user - in which case nothing gets printed to the screen! (Keep that in mind )

Let&rsquo;s move on to the meat and potatoes of the code in question (The listing will be a little longer).

const char *cw;

cw = login_getcapstr(lc, "welcome", NULL, NULL);<br>if (cw != NULL && access(cw, F_OK) == 0)<br>motd(cw);<br>else<br>motd(_PATH_MOTDFILE);

if (login_getcapbool(lc_user, "nocheckmail", 0) == 0 &&<br>login_getcapbool(lc, "nocheckmail", 0) == 0) {<br>char *cx;

/* $MAIL may have been set by class. */<br>cx = getenv("MAIL");<br>if (cx == NULL) {<br>asprintf(&cx, "%s/%s",<br>_PATH_MAILDIR, pwd->pw_name);<br>if (cx && stat(cx, &st) == 0 && st.st_size != 0)<br>(void)printf("You have %smail.\n",<br>(st.st_mtime > st.st_atime) ? "new " : "");<br>if (getenv("MAIL") == NULL)<br>free(cx);

What happens here ?<br>Well, simply put:

The code checks for a capability named welcome - Concering the MOTD (Message of the Day )

Also, it checks if &ldquo;nocheckmail&rdquo; is set - in which case there will be no mail checkup at all!

The bottom part deals with the actual mail check - You can see the string &ldquo;You have %smail&rdquo; there

Let&rsquo;s take a closer look at the actual mail check:

cx = getenv("MAIL");<br>if (cx == NULL) {<br>asprintf(&cx, "%s/%s",<br>_PATH_MAILDIR, pwd->pw_name);<br>if (cx && stat(cx, &st) == 0 && st.st_size != 0)<br>(void)printf("You have %smail.\n",<br>(st.st_mtime > st.st_atime) ? "new " : "");<br>if (getenv("MAIL") == NULL)<br>free(cx);

Let me explain a little here:<br>First, getenv (libc function) is called with the env variable name MAIL .

It is checked if it contains NULL - which would mean the variable is not set.

The second if construct is where the magic happens. You can see that there is a call to stat() .

stat() is a function that returns information about a file like size , access time , etc. In this case, st_size is checked.

Now I need to explain a little more…

In the beginning there was a line that stated:

cx = getenv("MAIL");

This very line assigns the content of MAIL to the variable cx !<br>This would in turn mean that cx could contain for example a string like "/var/mail/user" .

Since stat is called on that path, stat(cx, &st) , the information about the given file is now located in the structure/struct (A C data structure) &ldquo;st&rdquo; . Hence, we can access the size of the file in C via st.st_size - This gives us the...

mail login rsquo ldquo rdquo null

Related Articles