I got a problem report from Mark Willson: "I recently installed mg (via the Debian package) under WSL on Windows 10. I found that the 'backup-to-home-directory' option didn't work.
The cause of this appears to be that getlogin under WSL returns NULL, probably due to my use of wsltty to invoke bash. The patch below fixes the issue for me:" [snip] - if ((un = getlogin()) != NULL) + if ((un = getenv("LOGNAME")) != NULL) [snip] Which put me onto the track of what was going on. I found the following in the Linux manpage: BUGS Unfortunately, it is often rather easy to fool getlogin(). Sometimes it does not work at all, because some program messed up the utmp file. Often, it gives only the first 8 characters of the login name. The user currently logged in on the controlling terminal of our program need not be the user who started it. Avoid getlogin() for security- related purposes. Note that glibc does not follow the POSIX specification and uses stdin instead of /dev/tty. A bug. (Other recent systems, like SunOS 5.8 and HP-UX 11.11 and FreeBSD 4.8 all return the login name also when stdin is redirected.) Nobody knows precisely what cuserid() does; avoid it in portable pro‐ grams. Or avoid it altogether: use getpwuid(geteuid()) instead, if that is what you meant. Do not use cuserid(). So I started looking at the code and rewrote it a bit, which I think makes it more portable and removes a syscall in the process. I do suspect this can be written even more elegantly, but didn't want to rework the code too much. I also took the liberty to remove some whitespace. Index: fileio.c =================================================================== RCS file: /cvs/src/usr.bin/mg/fileio.c,v retrieving revision 1.104 @@ -703,7 +706,7 @@ expandtilde(const char *fn) struct stat statbuf; const char *cp; char user[LOGIN_NAME_MAX], path[NFILEN]; - char *un, *ret; + char *ret; size_t ulen, plen; path[0] = '\0'; @@ -722,21 +725,21 @@ expandtilde(const char *fn) return (NULL); return(ret); } + pw = getpwuid(geteuid()); if (ulen == 0) { /* ~/ or ~ */ - if ((un = getlogin()) != NULL) - (void)strlcpy(user, un, sizeof(user)); + if (pw != NULL) + (void)strlcpy(user, pw->pw_name, sizeof(user)); else user[0] = '\0'; } else { /* ~user/ or ~user */ memcpy(user, &fn[1], ulen); user[ulen] = '\0'; } - pw = getpwnam(user); if (pw != NULL) { plen = strlcpy(path, pw->pw_dir, sizeof(path)); if (plen == 0 || path[plen - 1] != '/') { if (strlcat(path, "/", sizeof(path)) >= sizeof(path)) { - dobeep(); + dobeep(); ewprintf("Path too long"); return (NULL); }