/*
  * get_user_info()
- * (copied from initdb.c) find the current user
  */
 int
 get_user_info(char **user_name)
 {
    int         user_id;
+   char       *errstr;
 
 #ifndef WIN32
-   struct passwd *pw = getpwuid(geteuid());
-
    user_id = geteuid();
-#else                          /* the windows code */
-   struct passwd_win32
-   {
-       int         pw_uid;
-       char        pw_name[128];
-   }           pass_win32;
-   struct passwd_win32 *pw = &pass_win32;
-   DWORD       pwname_size = sizeof(pass_win32.pw_name) - 1;
-
-   GetUserName(pw->pw_name, &pwname_size);
-
+#else
    user_id = 1;
 #endif
 
-   *user_name = pg_strdup(pw->pw_name);
+   *user_name = get_user_name(&errstr);
+   if (!*user_name)
+       pg_fatal("%s\n", errstr);
+
+   /* make a copy */
+   *user_name = pg_strdup(*user_name);
 
    return user_id;
 }
 
    char        ident_user[IDENT_USERNAME_MAX + 1];
    uid_t       uid;
    gid_t       gid;
-   struct passwd *pass;
+   const char *user_name;
+   char       *errstr;
 
    errno = 0;
    if (getpeereid(port->sock, &uid, &gid) != 0)
        return STATUS_ERROR;
    }
 
-   pass = getpwuid(uid);
-
-   if (pass == NULL)
+   user_name = get_user_name(&errstr);
+   if (!user_name)
    {
-       ereport(LOG,
-               (errmsg("local user with ID %d does not exist",
-                       (int) uid)));
+       ereport(LOG, (errmsg_internal("%s", errstr)));
+       pfree(errstr);
        return STATUS_ERROR;
    }
 
-   strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
+   strlcpy(ident_user, user_name, IDENT_USERNAME_MAX + 1);
 
    return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
 }
 
  */
 #include "postgres.h"
 
-#include <pwd.h>
 #include <unistd.h>
 
 #if defined(__alpha) && defined(__osf__)       /* no __alpha__ ? */
 static void startup_hacks(const char *progname);
 static void help(const char *progname);
 static void check_root(const char *progname);
-static char *get_current_username(const char *progname);
 
 
 /*
    else if (argc > 1 && strcmp(argv[1], "--single") == 0)
        PostgresMain(argc, argv,
                     NULL,      /* no dbname */
-                    get_current_username(progname));   /* does not return */
+                    strdup(get_user_name_or_exit(progname)));  /* does not return */
    else
        PostmasterMain(argc, argv);     /* does not return */
    abort();                    /* should not get here */
    }
 #endif   /* WIN32 */
 }
-
-
-
-static char *
-get_current_username(const char *progname)
-{
-#ifndef WIN32
-   struct passwd *pw;
-
-   pw = getpwuid(geteuid());
-   if (pw == NULL)
-   {
-       write_stderr("%s: invalid effective UID: %d\n",
-                    progname, (int) geteuid());
-       exit(1);
-   }
-   /* Allocate new memory because later getpwuid() calls can overwrite it. */
-   return strdup(pw->pw_name);
-#else
-   unsigned long namesize = 256 /* UNLEN */ + 1;
-   char       *name;
-
-   name = malloc(namesize);
-   if (!GetUserName(name, &namesize))
-   {
-       write_stderr("%s: could not determine user name (GetUserName failed)\n",
-                    progname);
-       exit(1);
-   }
-
-   return name;
-#endif
-}
 
 /*
  * find the current user
  *
- * on unix make sure it isn't really root
+ * on unix make sure it isn't root
  */
 static char *
 get_id(void)
 {
-#ifndef WIN32
-
-   struct passwd *pw;
+   const char     *username;
 
+#ifndef WIN32
    if (geteuid() == 0)         /* 0 is root's uid */
    {
        fprintf(stderr,
                progname);
        exit(1);
    }
-
-   pw = getpwuid(geteuid());
-   if (!pw)
-   {
-       fprintf(stderr,
-             _("%s: could not obtain information about current user: %s\n"),
-               progname, strerror(errno));
-       exit(1);
-   }
-#else                          /* the windows code */
-
-   struct passwd_win32
-   {
-       int         pw_uid;
-       char        pw_name[128];
-   }           pass_win32;
-   struct passwd_win32 *pw = &pass_win32;
-   DWORD       pwname_size = sizeof(pass_win32.pw_name) - 1;
-
-   pw->pw_uid = 1;
-   if (!GetUserName(pw->pw_name, &pwname_size))
-   {
-       fprintf(stderr, _("%s: could not get current user name: %s\n"),
-               progname, strerror(errno));
-       exit(1);
-   }
 #endif
 
-   return pg_strdup(pw->pw_name);
+   username = get_user_name_or_exit(progname);
+
+   return pg_strdup(username);
 }
 
 static char *
 
 #ifndef WIN32
            struct passwd *pw;
 
+           errno = 0;  /* clear errno before call */
            pw = getpwuid(geteuid());
            if (!pw)
            {
-               psql_error("could not get home directory: %s\n", strerror(errno));
+               psql_error("could not get home directory for user id %d: %s\n",
+                          (int) geteuid(), errno ?
+                          strerror(errno) : "user does not exist");
                exit(EXIT_FAILURE);
            }
            dir = pw->pw_dir;
 
 #include "postgres_fe.h"
 
 #ifndef WIN32
-#ifdef HAVE_PWD_H
-#include <pwd.h>               /* for getpwuid() */
-#endif
 #include <sys/types.h>         /* (ditto) */
 #include <unistd.h>                /* for geteuid() */
 #else
 {
    const char *env;
    const char *user;
-
-#ifndef WIN32
-   struct passwd *pw = NULL;
-#endif
+   char       *errstr;
 
    /* Find default user, in case we need it. */
    user = getenv("PGUSER");
    if (!user)
    {
-#if !defined(WIN32) && !defined(__OS2__)
-       pw = getpwuid(geteuid());
-       if (pw)
-           user = pw->pw_name;
-       else
+       user = get_user_name(&errstr);
+       if (!user)
        {
-           psql_error("could not get current user name: %s\n", strerror(errno));
+           psql_error("%s\n", errstr);
            exit(EXIT_FAILURE);
        }
-#else                          /* WIN32 */
-       char        buf[128];
-       DWORD       bufsize = sizeof(buf) - 1;
-
-       if (GetUserName(buf, &bufsize))
-           user = buf;
-#endif   /* WIN32 */
    }
 
    printf(_("psql is the PostgreSQL interactive terminal.\n\n"));
 
            else if (getenv("PGUSER"))
                dbname = getenv("PGUSER");
            else
-               dbname = get_user_name(progname);
+               dbname = get_user_name_or_exit(progname);
        }
 
        if (tables.head != NULL)
 
 
 #include "postgres_fe.h"
 
-#include <pwd.h>
 #include <signal.h>
 #include <unistd.h>
 
 static CRITICAL_SECTION cancelConnLock;
 #endif
 
-/*
- * Returns the current user name.
- */
-const char *
-get_user_name(const char *progname)
-{
-#ifndef WIN32
-   struct passwd *pw;
-
-   pw = getpwuid(geteuid());
-   if (!pw)
-   {
-       fprintf(stderr, _("%s: could not obtain information about current user: %s\n"),
-               progname, strerror(errno));
-       exit(1);
-   }
-   return pw->pw_name;
-#else
-   static char username[128];  /* remains after function exit */
-   DWORD       len = sizeof(username) - 1;
-
-   if (!GetUserName(username, &len))
-   {
-       fprintf(stderr, _("%s: could not get current user name: %s\n"),
-               progname, strerror(errno));
-       exit(1);
-   }
-   return username;
-#endif
-}
-
-
 /*
  * Provide strictly harmonized handling of --help and --version
  * options.
 
 
 typedef void (*help_handler) (const char *progname);
 
-extern const char *get_user_name(const char *progname);
-
 extern void handle_help_version_opts(int argc, char *argv[],
                         const char *fixed_progname,
                         help_handler hlp);
 
        else if (getenv("PGUSER"))
            dbname = getenv("PGUSER");
        else
-           dbname = get_user_name(progname);
+           dbname = get_user_name_or_exit(progname);
    }
 
    initPQExpBuffer(&sql);
 
        else if (getenv("PGUSER"))
            dbname = getenv("PGUSER");
        else
-           dbname = get_user_name(progname);
+           dbname = get_user_name_or_exit(progname);
    }
 
    initPQExpBuffer(&sql);
 
            if (getenv("PGUSER"))
                newuser = getenv("PGUSER");
            else
-               newuser = get_user_name(progname);
+               newuser = get_user_name_or_exit(progname);
        }
    }
 
 
        else if (getenv("PGUSER"))
            dbname = getenv("PGUSER");
        else
-           dbname = get_user_name(progname);
+           dbname = get_user_name_or_exit(progname);
    }
 
    initPQExpBuffer(&sql);
 
            else if (getenv("PGUSER"))
                dbname = getenv("PGUSER");
            else
-               dbname = get_user_name(progname);
+               dbname = get_user_name_or_exit(progname);
        }
 
        reindex_system_catalogs(dbname, host, port, username, prompt_password,
            else if (getenv("PGUSER"))
                dbname = getenv("PGUSER");
            else
-               dbname = get_user_name(progname);
+               dbname = get_user_name_or_exit(progname);
        }
 
        if (indexes.head != NULL)
 
            else if (getenv("PGUSER"))
                dbname = getenv("PGUSER");
            else
-               dbname = get_user_name(progname);
+               dbname = get_user_name_or_exit(progname);
        }
 
        if (tables.head != NULL)
 
 /* port/quotes.c */
 extern char *escape_single_quotes_ascii(const char *src);
 
+/* port/username.c */
+extern const char *get_user_name(char **errstr);
+extern const char *get_user_name_or_exit(const char *progname);
+
 /* port/wait_error.c */
 extern char *wait_result_to_str(int exit_status);
 
 
 OBJS = $(LIBOBJS) chklocale.o dirmod.o erand48.o fls.o inet_net_ntop.o \
    noblock.o path.o pgcheckdir.o pg_crc.o pgmkdirp.o pgsleep.o \
    pgstrcasecmp.o pqsignal.o \
-   qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o
+   qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o username.o
 
 # foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND
 OBJS_SRV = $(OBJS:%.o=%_srv.o)
 
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * username.c
+ *   get user name
+ *
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *   src/port/username.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <errno.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+
+/*
+ * Returns the current user name in a static buffer, or NULL on error and
+ * sets errstr
+ */
+const char *
+get_user_name(char **errstr)
+{
+#ifndef WIN32
+   struct passwd *pw;
+   uid_t user_id = geteuid();
+
+   *errstr = NULL;
+
+   errno = 0;  /* clear errno before call */
+   pw = getpwuid(user_id);
+   if (!pw)
+   {
+       *errstr = psprintf(_("failed to look up effective user id %d: %s"),
+               (int) user_id, errno ? strerror(errno) :
+               _("user does not exist"));
+       return NULL;
+   }
+
+   return pw->pw_name;
+#else
+   /* UNLEN = 256, 'static' variable remains after function exit */
+   static char username[256 + 1]; 
+   DWORD       len = sizeof(username) - 1;
+
+   if (!GetUserName(username, &len))
+   {
+       *errstr = psprintf(_("user name lookup failure: %s"), strerror(errno));
+       return NULL;
+   }
+
+   return username;
+#endif
+}
+
+
+/*
+ * Returns the current user name in a static buffer or exits
+ */
+const char *
+get_user_name_or_exit(const char *progname)
+{
+   const char *user_name;
+   char       *errstr;
+
+   user_name = get_user_name(&errstr);
+
+   if (!user_name)
+   {
+       fprintf(stderr, "%s: %s\n", progname, errstr);
+       exit(1);
+   }
+   return user_name;
+}
 
      erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
      pgcheckdir.c pg_crc.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c
      qsort.c qsort_arg.c quotes.c
-     sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c rint.c win32env.c
-     win32error.c win32setlocale.c);
+     sprompt.c tar.c thread.c getopt.c getopt_long.c dirent.c rint.c username.c
+     win32env.c win32error.c win32setlocale.c);
 
    our @pgcommonallfiles = qw(
      exec.c pgfnames.c psprintf.c relpath.c rmtree.c wait_error.c);