Raymond Toy pushed to branch issue-269-unix-get-user-homedir at cmucl / cmucl
Commits:
-
2f767eed
by Raymond Toy at 2023-11-27T11:04:00-08:00
-
3d955819
by Raymond Toy at 2023-11-27T11:04:59-08:00
-
c6a9f865
by Raymond Toy at 2023-11-27T11:06:34-08:00
-
637a5d78
by Raymond Toy at 2023-11-27T11:08:51-08:00
-
d7a3d533
by Raymond Toy at 2023-11-27T11:09:46-08:00
9 changed files:
- .gitlab-ci.yml
- src/code/exports.lisp
- src/code/filesys.lisp
- src/code/unix.lisp
- src/i18n/locale/cmucl-unix.pot
- src/i18n/locale/cmucl.pot
- src/lisp/os-common.c
- tests/filesys.lisp
- − tests/os.lisp
Changes:
| ... | ... | @@ -62,7 +62,6 @@ linux:test: |
| 62 | 62 | - job: linux:build
|
| 63 | 63 | artifacts: true
|
| 64 | 64 | script:
|
| 65 | - - printenv
|
|
| 66 | 65 | - bin/run-unit-tests.sh -l dist/bin/lisp 2>&1 | tee test.log
|
| 67 | 66 | |
| 68 | 67 | linux:ansi-test:
|
| ... | ... | @@ -147,7 +146,6 @@ osx:test: |
| 147 | 146 | artifacts: true
|
| 148 | 147 | script:
|
| 149 | 148 | - echo LANG = $LANG
|
| 150 | - - printenv
|
|
| 151 | 149 | - bin/run-unit-tests.sh -l dist/bin/lisp 2>&1 | tee test.log
|
| 152 | 150 | |
| 153 | 151 | osx:ansi-test:
|
| ... | ... | @@ -227,7 +227,6 @@ |
| 227 | 227 | "UNIX-MKDIR"
|
| 228 | 228 | "UNIX-RMDIR"
|
| 229 | 229 | "UNIX-UNLINK"
|
| 230 | - "UNIX-GET-USER-HOMEDIR"
|
|
| 231 | 230 | "TIMEZONE"
|
| 232 | 231 | "TIMEVAL"
|
| 233 | 232 | "SIZE-T"
|
| ... | ... | @@ -1713,7 +1712,9 @@ |
| 1713 | 1712 | "DESCRIBE-EXTERNAL-FORMAT"
|
| 1714 | 1713 | "LIST-ALL-EXTERNAL-FORMATS"
|
| 1715 | 1714 | "STRING-ENCODE" "STRING-DECODE"
|
| 1716 | - "SET-SYSTEM-EXTERNAL-FORMAT"))
|
|
| 1715 | + "SET-SYSTEM-EXTERNAL-FORMAT")
|
|
| 1716 | + ;; File sys items
|
|
| 1717 | + (:export "GET-USER-HOMEDIR-PATHNAME"))
|
|
| 1717 | 1718 | |
| 1718 | 1719 | (defpackage "STREAM"
|
| 1719 | 1720 | (:import-from "SYSTEM" "LISP-STREAM")
|
| ... | ... | @@ -27,7 +27,8 @@ |
| 27 | 27 | |
| 28 | 28 | (in-package "EXTENSIONS")
|
| 29 | 29 | (export '(print-directory complete-file ambiguous-files default-directory
|
| 30 | - purge-backup-files file-writable unix-namestring))
|
|
| 30 | + purge-backup-files file-writable unix-namestring
|
|
| 31 | + get-user-homedir-pathname))
|
|
| 31 | 32 | (in-package "LISP")
|
| 32 | 33 | |
| 33 | 34 | |
| ... | ... | @@ -1483,3 +1484,28 @@ optionally keeping some of the most recent old versions." |
| 1483 | 1484 | (go retry))))))
|
| 1484 | 1485 | ;; Only the first path in a search-list is considered.
|
| 1485 | 1486 | (return (values pathspec created-p))))))
|
| 1487 | + |
|
| 1488 | +;;; GET-USER-HOMEDIR-PATHNAME -- Public
|
|
| 1489 | +;;;
|
|
| 1490 | +(defun get-user-homedir-pathname (name)
|
|
| 1491 | + _N"Get the user home directory for user named NAME. Two values are
|
|
| 1492 | + returned: the pathname of the home directory and a status code. If
|
|
| 1493 | + the home directory does not exist NIL is returned. The status is 0
|
|
| 1494 | + if no errors occurred. Otherwise a non-zero value is returned.
|
|
| 1495 | + Examining errno may give information about what failed."
|
|
| 1496 | + (alien:with-alien ((status c-call:int))
|
|
| 1497 | + (let ((result
|
|
| 1498 | + (alien:alien-funcall
|
|
| 1499 | + (alien:extern-alien "os_get_user_homedir"
|
|
| 1500 | + (function c-call:c-string
|
|
| 1501 | + c-call:c-string
|
|
| 1502 | + (* c-call:int)))
|
|
| 1503 | + name
|
|
| 1504 | + (alien:addr status))))
|
|
| 1505 | + (if (and (zerop status) result)
|
|
| 1506 | + (values (pathname
|
|
| 1507 | + (concatenate 'string
|
|
| 1508 | + result
|
|
| 1509 | + "/"))
|
|
| 1510 | + status)
|
|
| 1511 | + (values result status))))) |
| ... | ... | @@ -2900,27 +2900,3 @@ |
| 2900 | 2900 | (extern-alien "os_get_locale_codeset"
|
| 2901 | 2901 | (function (* char))))
|
| 2902 | 2902 | c-string)) |
| 2903 | - |
|
| 2904 | -(defun unix-get-user-homedir (name)
|
|
| 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))
|
|
| 2911 | - (let ((result
|
|
| 2912 | - (alien-funcall
|
|
| 2913 | - (extern-alien "os_get_user_homedir"
|
|
| 2914 | - (function c-call:c-string
|
|
| 2915 | - c-call:c-string
|
|
| 2916 | - (* c-call:int)))
|
|
| 2917 | - name
|
|
| 2918 | - (addr status))))
|
|
| 2919 | - (if (and (zerop status) result)
|
|
| 2920 | - (values (pathname
|
|
| 2921 | - (concatenate 'string
|
|
| 2922 | - result
|
|
| 2923 | - "/"))
|
|
| 2924 | - status)
|
|
| 2925 | - (values result status)))))
|
|
| 2926 | - |
| ... | ... | @@ -1432,12 +1432,3 @@ msgstr "" |
| 1432 | 1432 | msgid "Get the codeset from the locale"
|
| 1433 | 1433 | msgstr ""
|
| 1434 | 1434 | |
| 1435 | -#: src/code/unix.lisp
|
|
| 1436 | -msgid ""
|
|
| 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."
|
|
| 1442 | -msgstr ""
|
|
| 1443 | - |
| ... | ... | @@ -10207,6 +10207,15 @@ msgstr "" |
| 10207 | 10207 | msgid "Can't create directory ~A."
|
| 10208 | 10208 | msgstr ""
|
| 10209 | 10209 | |
| 10210 | +#: src/code/filesys.lisp
|
|
| 10211 | +msgid ""
|
|
| 10212 | +"Get the user home directory for user named NAME. Two values are\n"
|
|
| 10213 | +" returned: the pathname of the home directory and a status code. If\n"
|
|
| 10214 | +" the home directory does not exist NIL is returned. The status is 0\n"
|
|
| 10215 | +" if no errors occurred. Otherwise a non-zero value is returned.\n"
|
|
| 10216 | +" Examining errno may give information about what failed."
|
|
| 10217 | +msgstr ""
|
|
| 10218 | + |
|
| 10210 | 10219 | #: src/code/load.lisp
|
| 10211 | 10220 | msgid "The default for the :IF-SOURCE-NEWER argument to load."
|
| 10212 | 10221 | msgstr ""
|
| ... | ... | @@ -864,17 +864,24 @@ os_software_version(void) |
| 864 | 864 | return result;
|
| 865 | 865 | }
|
| 866 | 866 | |
| 867 | +/*
|
|
| 868 | + * Return the home directory of the user named NAME. If the user does
|
|
| 869 | + * not exist, returns NULL. Also returns NULL if the home directory
|
|
| 870 | + * cannot be determined for any reason. The parameter STATUS is 0 if
|
|
| 871 | + * getpwnam_r was successful. Otherwise it is the return value from
|
|
| 872 | + * getpwnam_r or -1 if we ran out of memory for the buffer.
|
|
| 873 | + */
|
|
| 867 | 874 | char *
|
| 868 | 875 | os_get_user_homedir(const char* name, int *status)
|
| 869 | 876 | {
|
| 870 | 877 | int buflen;
|
| 871 | - char * buf;
|
|
| 878 | + char *buf = NULL;
|
|
| 872 | 879 | struct passwd pwd;
|
| 873 | 880 | struct passwd *result;
|
| 874 | 881 | |
| 875 | 882 | buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
|
| 876 | 883 | /*
|
| 877 | - * If sysconf failed, just try some possibly large enough value
|
|
| 884 | + * If sysconf failed, just try some possibly large enough value.
|
|
| 878 | 885 | */
|
| 879 | 886 | if (buflen == -1) {
|
| 880 | 887 | buflen = 1024;
|
| ... | ... | @@ -886,8 +893,7 @@ os_get_user_homedir(const char* name, int *status) |
| 886 | 893 | * upper limit and give up.
|
| 887 | 894 | */
|
| 888 | 895 | while (buflen <= (1 << 20)) {
|
| 889 | - errno = 0;
|
|
| 890 | - buf = malloc(buflen);
|
|
| 896 | + buf = realloc(buf, buflen);
|
|
| 891 | 897 | |
| 892 | 898 | if (buf == NULL) {
|
| 893 | 899 | *status = -1;
|
| ... | ... | @@ -898,23 +904,24 @@ os_get_user_homedir(const char* name, int *status) |
| 898 | 904 | |
| 899 | 905 | if (*status == 0) {
|
| 900 | 906 | /*
|
| 901 | - * Success, or entry was not found. If found the result
|
|
| 907 | + * Success, or entry was not found. If found, the result
|
|
| 902 | 908 | * is not NULL. Return the result or NULL
|
| 903 | 909 | */
|
| 904 | - fprintf(stderr, "dir = %s\n", pwd.pw_dir);
|
|
| 905 | - return result ? strdup(pwd.pw_dir) : NULL;
|
|
| 910 | + char* path = result ? strdup(pwd.pw_dir) : NULL;
|
|
| 911 | + free(buf);
|
|
| 912 | + return path;
|
|
| 906 | 913 | }
|
| 907 | 914 | |
| 908 | 915 | /*
|
| 909 | 916 | * Check errno for ERANGE. If so, the buffer was too small, so grow it.
|
| 910 | 917 | */
|
| 911 | 918 | if (errno == ERANGE) {
|
| 912 | - free(buf);
|
|
| 913 | 919 | buflen *= 2;
|
| 914 | 920 | } else {
|
| 915 | 921 | /*
|
| 916 | 922 | * Some other error. Just return NULL
|
| 917 | 923 | */
|
| 924 | + free(buf);
|
|
| 918 | 925 | return NULL;
|
| 919 | 926 | }
|
| 920 | 927 | }
|
| ... | ... | @@ -922,6 +929,7 @@ os_get_user_homedir(const char* name, int *status) |
| 922 | 929 | /*
|
| 923 | 930 | * Ran out of space. Just return NULL and set status to -1.
|
| 924 | 931 | */
|
| 932 | + free(buf);
|
|
| 925 | 933 | *status = -1;
|
| 926 | 934 | return NULL;
|
| 927 | 935 | }
|
| ... | ... | @@ -55,6 +55,36 @@ |
| 55 | 55 | (ext:unix-namestring "/tmp/foo/bar/symlink" nil)))
|
| 56 | 56 | (unix:unix-unlink "/tmp/foo/bar/symlink")))
|
| 57 | 57 | |
| 58 | -
|
|
| 59 | -
|
|
| 58 | +(define-test user-homedir.1
|
|
| 59 | + "Test user-homedir"
|
|
| 60 | + (:tag :issues)
|
|
| 61 | + ;; Simple test to see if get-user-homedir-pathname returns the
|
|
| 62 | + ;; expected value. Use getuid and getpwuid to figure out what the
|
|
| 63 | + ;; name and home directory should be.
|
|
| 64 | + (let* ((uid (unix:unix-getuid))
|
|
| 65 | + (user-info (unix:unix-getpwuid uid)))
|
|
| 66 | + (assert-true uid)
|
|
| 67 | + (assert-true user-info)
|
|
| 68 | + (let* ((info-dir (unix:user-info-dir user-info))
|
|
| 69 | + (info-name (unix:user-info-name user-info))
|
|
| 70 | + (expected-home-pathname (pathname
|
|
| 71 | + (concatenate 'string info-dir "/"))))
|
|
| 72 | + (multiple-value-bind (home-pathname status)
|
|
| 73 | + (ext:get-user-homedir-pathname info-name)
|
|
| 74 | + (assert-true info-dir)
|
|
| 75 | + (assert-true info-name)
|
|
| 76 | + |
|
| 77 | + (assert-equal home-pathname expected-home-pathname)
|
|
| 78 | + (assert-eql status 0)))))
|
|
| 79 | + |
|
| 80 | +(define-test user-homedir.2
|
|
| 81 | + "Test user-homedir"
|
|
| 82 | + (:tag :issues)
|
|
| 83 | + ;; Simple test to see if get-user-homedir-pathname returns the expected
|
|
| 84 | + ;; value for a user that does not exist. Well, we assume such a
|
|
| 85 | + ;; user doesn't exist.
|
|
| 86 | + (multiple-value-bind (home-pathname status)
|
|
| 87 | + (ext:get-user-homedir-pathname "zotuserunknown")
|
|
| 88 | + (assert-eql home-pathname nil)
|
|
| 89 | + (assert-eql status 0)))
|
|
| 60 | 90 | |
| 1 | -(defpackage :os-tests
|
|
| 2 | - (:use :cl :lisp-unit))
|
|
| 3 | - |
|
| 4 | -(in-package "OS-TESTS")
|
|
| 5 | - |
|
| 6 | -(define-test user-homedir.1
|
|
| 7 | - "Test user-homedir"
|
|
| 8 | - (:tag :issues)
|
|
| 9 | - ;; Simple test to see if unix-get-user-homedir returns the expected
|
|
| 10 | - ;; value. Use getuid and getpwuid to figure out what the name and
|
|
| 11 | - ;; home directory should be.
|
|
| 12 | - (let* ((uid (unix:unix-getuid))
|
|
| 13 | - (user-info (unix:unix-getpwuid uid)))
|
|
| 14 | - (assert-true uid)
|
|
| 15 | - (assert-true user-info)
|
|
| 16 | - (let* ((info-dir (unix:user-info-dir user-info))
|
|
| 17 | - (info-name (unix:user-info-name user-info))
|
|
| 18 | - (expected-home-pathname (pathname
|
|
| 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)
|
|
| 24 | - |
|
| 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))) |