Raymond Toy pushed to branch issue-269-unix-get-user-homedir at cmucl / cmucl
Commits:
-
c78a982f
by Raymond Toy at 2023-11-26T14:32:34-08:00
-
089574ef
by Raymond Toy at 2023-11-26T14:51:49-08:00
-
b26975f6
by Raymond Toy at 2023-11-26T14:52:03-08:00
4 changed files:
Changes:
... | ... | @@ -2902,22 +2902,25 @@ |
2902 | 2902 | c-string))
|
2903 | 2903 | |
2904 | 2904 | (defun unix-get-user-homedir (name)
|
2905 | - _N"Get the user home directory for user named NAME. If there's no such
|
|
2906 | - user or if we don't have enough space to store the path, return NIL."
|
|
2907 | - (with-alien ((homedir (array c-call:char 1024)))
|
|
2905 | + _N"Get the user home directory for user named NAME. Two values are
|
|
2906 | + returned: the pathname of the home directory and a status code. If
|
|
2907 | + the home directory does not exist NIL is returned. The status is 0
|
|
2908 | + if no errors occurred. Otherwise a non-zero value is returned.
|
|
2909 | + Examining errno may give information about what failed."
|
|
2910 | + (with-alien ((status c-call:int))
|
|
2908 | 2911 | (let ((result
|
2909 | 2912 | (alien-funcall
|
2910 | 2913 | (extern-alien "os_get_user_homedir"
|
2911 | - (function c-call:int
|
|
2914 | + (function c-call:c-string
|
|
2912 | 2915 | c-call:c-string
|
2913 | - (* char)
|
|
2914 | - c-call:int))
|
|
2916 | + (* c-call:int)))
|
|
2915 | 2917 | name
|
2916 | - (cast homedir (* c-call:char))
|
|
2917 | - 1024)))
|
|
2918 | - (when (zerop result)
|
|
2919 | - (pathname
|
|
2920 | - (concatenate 'string
|
|
2921 | - (cast homedir c-call:c-string)
|
|
2922 | - "/"))))))
|
|
2918 | + (addr status))))
|
|
2919 | + (if (and (zerop status) result)
|
|
2920 | + (values (pathname
|
|
2921 | + (concatenate 'string
|
|
2922 | + result
|
|
2923 | + "/"))
|
|
2924 | + status)
|
|
2925 | + (values result status)))))
|
|
2923 | 2926 | |
... | ... | @@ -1434,7 +1434,10 @@ msgstr "" |
1434 | 1434 | |
1435 | 1435 | #: src/code/unix.lisp
|
1436 | 1436 | msgid ""
|
1437 | -"Get the user home directory for user named NAME. If there's no such\n"
|
|
1438 | -" user or if we don't have enough space to store the path, return NIL."
|
|
1437 | +"Get the user home directory for user named NAME. Two values are\n"
|
|
1438 | +" returned: the pathname of the home directory and a status code. If\n"
|
|
1439 | +" the home directory does not exist NIL is returned. The status is 0\n"
|
|
1440 | +" if no errors occurred. Otherwise a non-zero value is returned.\n"
|
|
1441 | +" Examining errno may give information about what failed."
|
|
1439 | 1442 | msgstr ""
|
1440 | 1443 |
... | ... | @@ -864,43 +864,65 @@ os_software_version(void) |
864 | 864 | return result;
|
865 | 865 | }
|
866 | 866 | |
867 | -int
|
|
868 | -os_get_user_homedir(const char* name, char* homedir, int len)
|
|
867 | +char *
|
|
868 | +os_get_user_homedir(const char* name, int *status)
|
|
869 | 869 | {
|
870 | - int rc;
|
|
871 | 870 | int buflen;
|
872 | 871 | char * buf;
|
873 | 872 | struct passwd pwd;
|
874 | 873 | struct passwd *result;
|
875 | 874 | |
876 | 875 | buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
|
876 | + /*
|
|
877 | + * If sysconf failed, just try some possibly large enough value
|
|
878 | + */
|
|
879 | + if (buflen == -1) {
|
|
880 | + buflen = 1024;
|
|
881 | + }
|
|
877 | 882 | |
878 | - buf = malloc(buflen);
|
|
883 | + /*
|
|
884 | + * sysconf may return a value that is not large enough, so start
|
|
885 | + * with the given value and keep increasing it until we reach some
|
|
886 | + * upper limit and give up.
|
|
887 | + */
|
|
888 | + while (buflen <= (1 << 20)) {
|
|
889 | + errno = 0;
|
|
890 | + buf = malloc(buflen);
|
|
879 | 891 | |
880 | - if (buf == NULL) {
|
|
881 | - return -1;
|
|
882 | - }
|
|
892 | + if (buf == NULL) {
|
|
893 | + *status = -1;
|
|
894 | + return NULL;
|
|
895 | + }
|
|
896 | + |
|
897 | + *status = getpwnam_r(name, &pwd, buf, buflen, &result);
|
|
883 | 898 | |
884 | - rc = getpwnam_r(name, &pwd, buf, buflen, &result);
|
|
899 | + if (*status == 0) {
|
|
900 | + /*
|
|
901 | + * Success, or entry was not found. If found the result
|
|
902 | + * is not NULL. Return the result or NULL
|
|
903 | + */
|
|
904 | + fprintf(stderr, "dir = %s\n", pwd.pw_dir);
|
|
905 | + return result ? strdup(pwd.pw_dir) : NULL;
|
|
906 | + }
|
|
885 | 907 | |
886 | - if ((rc == 0) && result != NULL) {
|
|
887 | 908 | /*
|
888 | - * Found a matching entry. Copy it to the output buffer if we
|
|
889 | - * have room. If not, set code to -1
|
|
909 | + * Check errno for ERANGE. If so, the buffer was too small, so grow it.
|
|
890 | 910 | */
|
891 | - if (strlen(pwd.pw_dir) < len) {
|
|
892 | - strcpy(homedir, pwd.pw_dir);
|
|
911 | + if (errno == ERANGE) {
|
|
912 | + free(buf);
|
|
913 | + buflen *= 2;
|
|
893 | 914 | } else {
|
894 | - rc = -1;
|
|
915 | + /*
|
|
916 | + * Some other error. Just return NULL
|
|
917 | + */
|
|
918 | + return NULL;
|
|
895 | 919 | }
|
896 | - } else {
|
|
897 | - rc = -1;
|
|
898 | 920 | }
|
899 | 921 | |
900 | - if (buf) {
|
|
901 | - free(buf);
|
|
902 | - }
|
|
903 | -
|
|
904 | - return rc;
|
|
922 | + /*
|
|
923 | + * Ran out of space. Just return NULL and set status to -1.
|
|
924 | + */
|
|
925 | + *status = -1;
|
|
926 | + return NULL;
|
|
905 | 927 | }
|
906 | 928 | |
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | |
4 | 4 | (in-package "OS-TESTS")
|
5 | 5 | |
6 | -(define-test user-homedir
|
|
6 | +(define-test user-homedir.1
|
|
7 | 7 | "Test user-homedir"
|
8 | 8 | (:tag :issues)
|
9 | 9 | ;; Simple test to see if unix-get-user-homedir returns the expected
|
... | ... | @@ -16,9 +16,22 @@ |
16 | 16 | (let* ((info-dir (unix:user-info-dir user-info))
|
17 | 17 | (info-name (unix:user-info-name user-info))
|
18 | 18 | (expected-home-pathname (pathname
|
19 | - (concatenate 'string info-dir "/")))
|
|
20 | - (home-pathname (unix:unix-get-user-homedir info-name)))
|
|
21 | - (assert-true info-dir)
|
|
22 | - (assert-true info-name)
|
|
19 | + (concatenate 'string info-dir "/"))))
|
|
20 | + (multiple-value-bind (home-pathname status)
|
|
21 | + (unix:unix-get-user-homedir info-name)
|
|
22 | + (assert-true info-dir)
|
|
23 | + (assert-true info-name)
|
|
23 | 24 | |
24 | - (assert-equal home-pathname expected-home-pathname)))) |
|
25 | + (assert-equal home-pathname expected-home-pathname)
|
|
26 | + (assert-eql status 0)))))
|
|
27 | + |
|
28 | +(define-test user-homedir.2
|
|
29 | + "Test user-homedir"
|
|
30 | + (:tag :issues)
|
|
31 | + ;; Simple test to see if unix-get-user-homedir returns the expected
|
|
32 | + ;; value for a user that does not exist. Well, we assume such a
|
|
33 | + ;; user doesn't exist.
|
|
34 | + (multiple-value-bind (home-pathname status)
|
|
35 | + (unix:unix-get-user-homedir "zotuserunknown")
|
|
36 | + (assert-eql home-pathname nil)
|
|
37 | + (assert-eql status 0))) |