[Git][cmucl/cmucl][issue-408-get-user-name-and-homedir] 5 commits: Implement os_getpwuid per review comments
Raymond Toy pushed to branch issue-408-get-user-name-and-homedir at cmucl / cmucl Commits: e6e80bd0 by Raymond Toy at 2025-11-10T07:02:47-08:00 Implement os_getpwuid per review comments We implement os_getpwuid and use it as needed to get the user name and/or user directory. This requires updating os_get_username and get_homedir_from_uid and their callers of course. unix::unix-get-username needs updating too. - - - - - 1b2bbe7b by Raymond Toy at 2025-11-10T07:07:13-08:00 Remove old code that we've replaced. - - - - - ec1a3722 by Raymond Toy at 2025-11-10T07:13:11-08:00 Slightly simplify logic in get_homedir_from_uid - - - - - 9d281610 by Raymond Toy at 2025-11-10T08:31:29-08:00 Change API of os_get_username look like other functions Make os_get_username use the same API as used by get_homedir_from_name, get_homedir_from_uid, and os_get_user_homedir. Update unix-get-username implementation appropriately. - - - - - d076e577 by Raymond Toy at 2025-11-10T08:34:44-08:00 Remove old version of unix-get-username - - - - - 3 changed files: - src/code/unix.lisp - src/i18n/locale/cmucl-unix.pot - src/lisp/os-common.c Changes: ===================================== src/code/unix.lisp ===================================== @@ -2543,15 +2543,26 @@ (string-decode (cast result c-string) :default))) (defun unix-get-username (uid) - (let (name) - (unwind-protect - (progn - (setf name - (alien-funcall - (extern-alien "os_get_username" - (function (* char) uid-t)) - uid)) - (unless (null-alien name) - (cast name c-call:c-string))) - (unless (null-alien name) + _N"Returns a string that is the user name corresponding to the given UID. + If no such uid exists or if the user name does not exist, NIL is + returned." + (with-alien ((status c-call:int)) + (let (result) + (unwind-protect + (progn + (setf result + (alien-funcall + (extern-alien "os_get_username" + (function (* c-call:c-string) + uid-t + (* c-call:int))) + uid + (addr status))) + (values + (if (and (zerop status) + (not (null-alien result))) + (cast result c-call:c-string) + nil) + status)) (free-alien name))))) + ===================================== src/i18n/locale/cmucl-unix.pot ===================================== @@ -810,3 +810,10 @@ msgstr "" msgid "Returns a string that describes the error code Errno" msgstr "" +#: src/code/unix.lisp +msgid "" +"Returns a string that is the user name corresponding to the given UID.\n" +" If no such uid exists or if the user name does not exist, NIL is\n" +" returned." +msgstr "" + ===================================== src/lisp/os-common.c ===================================== @@ -731,56 +731,37 @@ os_lstat(const char* path, uint64_t *dev, uint64_t *ino, unsigned int *mode, uin } /* - * From the given UID, find the corresponding user name and home - * directory. - * - * NAME and DIR are set to the user name and home directory. The - * caller must free these. If no such uid exists, NAME and DIR are - * set to NULL. - * - * Returns the status of getpwuid. Zero indicates success. Otherwise - * the errno is returned. + * Basic interface to getpwuid, except we will automatically retry if + * the given buffer is too small. To support this |buffer| is a + * pointer to a char buffer. This will be updated with a new buffer + * if we needed to retry getpwuid with a larger buffer. The remaining + * parameters are the same as for getpwuid. */ int -os_get_user_info(uid_t uid, char **name, char **dir) +os_getpwuid(uid_t uid, struct passwd *pwd, char **buffer, size_t buflen, struct passwd **result) { - char initial[1024]; - char *buffer, *obuffer; - size_t size; - struct passwd pwd; - struct passwd *ppwd; int status; - - *name = NULL; - *dir = NULL; - - buffer = initial; - obuffer = NULL; - size = sizeof(initial) / sizeof(initial[0]); + char *obuffer = NULL; /* * Keep trying with larger buffers until a maximum is reached. We * assume (1 << 20) is large enough for any OS. */ again: - switch (status = getpwuid_r(uid, &pwd, buffer, size, &ppwd)) { + switch (status = getpwuid_r(uid, pwd, *buffer, buflen, result)) { case 0: /* Success, though we might not have a matching entry */ - if (ppwd) { - *name = strdup(pwd.pw_name); - *dir = strdup(pwd.pw_dir); - } break; case ERANGE: /* Buffer is too small, double its size and try again */ - size *= 2; - if (size > (1 << 20)) { + buflen *= 2; + if (buflen > (1 << 20)) { break; } - if ((buffer = realloc(obuffer, size)) == NULL) { + if ((*buffer = realloc(obuffer, buflen)) == NULL) { break; } - obuffer = buffer; + obuffer = *buffer; goto again; default: /* All other errors */ @@ -791,23 +772,38 @@ again: return status; } + /* * Given the UID, return the user name. If the uid does not exist, * returns NULL. The caller must call free on the string that is * returned. */ char * -os_get_username(uid_t uid) +os_get_username(uid_t uid, int *status) { - int status; + char *buf; char *name; - char *dir; + struct passwd pwd; + struct passwd *result; + char buffer[1024]; - status = os_get_user_info(uid, &name, &dir); + buf = buffer; - free(dir); + *status = os_getpwuid(uid, &pwd, &buf, 1024, &result); - return (status == 0) ? name : NULL; + if (*status != 0 || result == NULL || result->pw_name == NULL) { + name = NULL; + } else { + name = strdup(result->pw_name); + if (name == NULL) { + *status = errno; + } + if (buf != buffer) { + free(buf); + } + } + + return name; } /* @@ -818,13 +814,14 @@ os_get_username(uid_t uid) char * os_file_author(const char *path) { + int status; struct stat sb; if (stat(path, &sb) != 0) { return NULL; } - return os_get_username(sb.st_uid); + return os_get_username(sb.st_uid, &status); } int @@ -986,16 +983,29 @@ get_homedir_from_name(const char* name, int *status) static char * get_homedir_from_uid(uid_t uid, int *status) { - char *name; + char buffer[1024]; + char *buf; char *dir; - - *status = os_get_user_info(uid, &name, &dir); + struct passwd pwd; + struct passwd *result; - free(name); - - return (*status == 0) ? dir : NULL; -} + buf = buffer; + dir = NULL; + *status = os_getpwuid(uid, &pwd, &buf, 1024, &result); + + if (*status == 0 && result != NULL && result->pw_dir != NULL) { + dir = strdup(result->pw_dir); + if (dir == NULL) { + *status = errno; + } + if (buf != buffer) { + free(buf); + } + } + + return dir; +} /* * Return the home directory of the user named NAME. If NAME is the View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/5da6959fd78d7c663dc188c... -- View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/5da6959fd78d7c663dc188c... You're receiving this email because of your account on gitlab.common-lisp.net.
participants (1)
-
Raymond Toy (@rtoy)