Merge remote-tracking branch 'origin/master' into for-steve
[sxemacs] / src / editfns.c
index abb35e3..c2d6a01 100644 (file)
@@ -39,10 +39,12 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 #include "casetab.h"
 #include "chartab.h"
 #include "line-number.h"
+#include "ent/ent.h"
 
 #include "systime.h"
 #include "sysdep.h"
 #include "syspwd.h"
+#include "sysgrp.h"
 #include "sysfile.h"           /* for getcwd */
 
 /* Some static data, and a function to initialize it for each run */
@@ -600,15 +602,14 @@ On Unix it is obtained from TMPDIR, with /tmp as the default.
 {
        char *tmpdir;
        tmpdir = getenv("TMPDIR");
+       char path[5 /* strlen ("/tmp/") */  + 1 + _POSIX_PATH_MAX];
        if (!tmpdir) {
                struct stat st;
                int myuid = getuid();
-               char path[5 /* strlen ("/tmp/") */  + 1 +
-                          _POSIX_PATH_MAX];
 
                strcpy(path, "/tmp/");
                strncat(path, user_login_name(NULL), _POSIX_PATH_MAX);
-                path[sizeof(path)-1]=0;
+               path[sizeof(path)-1]=0;
                if (lstat(path, &st) < 0 && errno == ENOENT) {
                        mkdir(path, 0700);      /* ignore retval -- checked next anyway. */
                }
@@ -616,29 +617,32 @@ On Unix it is obtained from TMPDIR, with /tmp as the default.
                    S_ISDIR(st.st_mode)) {
                        tmpdir = path;
                } else {
-                        strncpy(path, getenv("HOME"), sizeof(path)-1);
-                       strncat(path, "/tmp/", sizeof(path)-strlen(path)-1);
-                       if (stat(path, &st) < 0 && errno == ENOENT) {
-                               int fd;
-                               char warnpath[ 
-                                              /* strlen(".created_by_sxemacs") */ 
-                                              19 + _POSIX_PATH_MAX + 1];
-                               mkdir(path, 0700);      /* ignore retvals */
-                               strncpy(warnpath, path, _POSIX_PATH_MAX);
-                                warnpath[sizeof(warnpath)-1]=0;
-
-                                /* we already are reserved these 20 bytes... */
-                               strcat(warnpath, ".created_by_sxemacs");
-                               if ((fd =
-                                    open(warnpath, O_WRONLY | O_CREAT,
-                                         0644)) > 0) {
-                                       write(fd,
-                                             "SXEmacs created this directory because /tmp/<yourname> was unavailable -- \nPlease check !\n",
-                                             89);
-                                       close(fd);
+                       const char* home_env = getenv("HOME");
+                       if ( home_env ) {
+                               xstrncpy(path, home_env, sizeof(path));
+                               xstrncat(path, "/tmp/", sizeof(path)-1);
+                               if ( mkdir(path, 0700) >= 0 || errno == EEXIST ) {
+                                       int fd;
+                                       char warnpath[
+                                               /* strlen(".created_by_sxemacs") */
+                                               19 + _POSIX_PATH_MAX + 1];
+                                       xstrncpy(warnpath, path, sizeof(warnpath));
+
+                                       /* we already are reserved these 20 bytes... */
+                                       xstrncat(warnpath, ".created_by_sxemacs", 
+                                                sizeof(warnpath)-1);
+                                       if ((fd = open(warnpath, O_WRONLY | O_CREAT,
+                                                      0644)) >= 0) {
+                                               write(fd, "SXEmacs created this directory "
+                                                         "because /tmp/<yourname> "
+                                                         "was unavailable -- \nPlease check !\n",
+                                                     89);
+                                               close(fd);
+                                       }
                                }
                        }
-                       if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
+                       if (stat(path, &st) == 0 && st.st_uid == (uid_t) myuid
+                           && S_ISDIR(st.st_mode)) {
                                tmpdir = path;
                        } else {
                                tmpdir = "/tmp";
@@ -694,9 +698,7 @@ char *user_login_name(uid_t * uid)
                   environment variables should be disregarded in that case.  --Stig */
                char *user_name = getenv("LOGNAME");
                if (!user_name)
-                       user_name = getenv(
-                                                 "USER"
-                           );
+                       user_name = getenv("USER");
                if (user_name)
                        return (user_name);
                else {
@@ -706,6 +708,47 @@ char *user_login_name(uid_t * uid)
        }
 }
 
+DEFUN("user-group-name", Fuser_group_name, 0, 1, 0,    /*
+Return the group name under which the user logged in, as a string.
+This is based on the effective gid, not the real gid.
+If the optional argument GID is present, then this function returns 
+the group name for that UID, or nil.
+*/
+      (gid))
+{
+       char *returned_name;
+       uid_t local_gid;
+
+       if (!NILP(gid)) {
+               CHECK_INT(gid);
+               local_gid = XINT(gid);
+               returned_name = user_group_name(&local_gid);
+       } else {
+               returned_name = user_group_name(NULL);
+       }
+       /* #### - I believe this should return nil instead of "unknown" when pw==0
+          pw=0 is indicated by a null return from user_login_name
+        */
+       return returned_name ? build_string(returned_name) : Qnil;
+}
+
+/* This function may be called from other C routines when a
+   character string representation of the user_group_name is
+   needed but a Lisp Object is not.  The GID is passed by
+   reference.  If GID == NULL, then the group for
+   for the user running XEmacs will be returned.  This
+   corresponds to a nil argument to Fuser_group_name.
+*/
+char *user_group_name(gid_t * gid)
+{
+       /* gid == NULL to return the group of this user */
+       struct group * grp = getgrgid( gid ? *gid : getegid());
+       if (grp == NULL) {
+               return NULL;
+       }
+       return grp->gr_name;
+}
+
 DEFUN("user-real-login-name", Fuser_real_login_name, 0, 0, 0,  /*
 Return the name of the user's real uid, as a string.
 This ignores the environment variables LOGNAME and USER, so it differs from
@@ -720,22 +763,76 @@ This ignores the environment variables LOGNAME and USER, so it differs from
        return tem;
 }
 
-DEFUN("user-uid", Fuser_uid, 0, 0, 0,  /*
-Return the effective uid of Emacs, as an integer.
+DEFUN("user-uid", Fuser_uid, 0, 1, 0,  /*
+Return the effective uid of the Emacs process, as an integer.
+If the optional argument `user_name' is specified it returns the uid of
+the user with that name. Will return `nil' if there is no user with the
+specified name,
 */
-      ())
+      (user_name))
+{
+       if (!NILP(user_name)) {
+               const char * user_name_ext = NULL;
+
+               CHECK_STRING(user_name);
+
+               TO_EXTERNAL_FORMAT(LISP_STRING, user_name,
+                                  C_STRING_ALLOCA, user_name_ext, Qnative);
+
+               struct passwd *pw = getpwnam(user_name_ext);
+               if (pw) {
+                       return make_int(pw->pw_uid);
+               } else {
+                       return Qnil;
+               }
+       } else {
+               return make_int(geteuid());
+       }
+}
+
+DEFUN("user-gid", Fuser_gid, 0, 1, 0,  /*
+Return the effective gid of the Emacs process, as an integer.
+If the optional argument `group_name' is specified it returns the gid of
+the group with that name. It will return `nil' if the system has no
+group with the specified name. 
+*/
+      (group_name))
 {
-       return make_int(geteuid());
+       if (!NILP(group_name)) {
+               const char *group_name_ext = NULL;
+
+               CHECK_STRING(group_name);
+
+               TO_EXTERNAL_FORMAT(LISP_STRING, group_name,
+                                  C_STRING_ALLOCA, group_name_ext, Qnative);
+
+               struct group *grp = getgrnam(group_name_ext);
+               if (grp) {
+                       return make_int(grp->gr_gid);
+               } else {
+                       return Qnil;
+               }
+       } else {
+               return make_int(getegid());
+       }
 }
 
 DEFUN("user-real-uid", Fuser_real_uid, 0, 0, 0,        /*
-Return the real uid of Emacs, as an integer.
+Return the real uid of the Emacs process, as an integer.
 */
       ())
 {
        return make_int(getuid());
 }
 
+DEFUN("user-real-gid", Fuser_real_gid, 0, 0, 0,        /*
+Return the real gid of the Emacs process, as an integer.
+*/
+      ())
+{
+       return make_int(getgid());
+}
+
 DEFUN("user-full-name", Fuser_full_name, 0, 1, 0,      /*
 Return the full name of the user logged in, as a string.
 If the optional argument USER is given, then the full name for that
@@ -915,7 +1012,7 @@ The time is returned as a big integer.
 
        EMACS_GET_TIME(t);
        bigz_init(btime);
-       
+
        bigz_set_long(btime, EMACS_SECS(t));
        mpz_mul_ui(btime, btime, 1000000UL);
        mpz_add_ui(btime, btime, EMACS_USECS(t));
@@ -1048,7 +1145,7 @@ time will be 0.
        return list3(make_float(user), make_float(sys), make_float(real));
 }
 
-DEFUN("uptime", Fuptime, 0, 1, "P", /* 
+DEFUN("uptime", Fuptime, 0, 1, "P", /*
 Display SXEmacs \"uptime\".
 
 When called interactively, without a prefix arg, return a list of 4
@@ -1160,7 +1257,7 @@ TIME is specified as (HIGH LOW . IGNORED) or (HIGH . LOW), as from
 `current-time' and `file-attributes'.  If TIME is not specified it
 defaults to the current time.
 
-If compiled with ENT, TIME may also be a big integer representing 
+If compiled with ENT, TIME may also be a big integer representing
 the number of microseconds since the Epoch, as output by
 `current-btime'.
 
@@ -1347,9 +1444,10 @@ If you want them to stand for years in this century, you must do that yourself.
                        tzstring = (char *)XSTRING_DATA(zone);
                } else if (INTP(zone)) {
                        int abszone = abs(XINT(zone));
-                       snprintf(tzbuf, countof(tzbuf) - 1, "XXX%s%d:%02d:%02d",
-                                "-" + (XINT(zone) < 0), abszone / (60 * 60),
-                                (abszone / 60) % 60, abszone % 60);
+                       int sz = snprintf(tzbuf, sizeof(tzbuf), "XXX%s%d:%02d:%02d",
+                                         "-" + (XINT(zone) < 0), abszone / (60 * 60),
+                                         (abszone / 60) % 60, abszone % 60);
+                       assert(sz >= 0 && (size_t)sz < sizeof(tzbuf));
                        tzstring = tzbuf;
                } else {
                        error("Invalid time zone specification");
@@ -1421,9 +1519,10 @@ Like `encode-time' but return a big integer time instead.
                        tzstring = (char *)XSTRING_DATA(zone);
                else if (INTP(zone)) {
                        int abszone = abs(XINT(zone));
-                       sprintf(tzbuf, "XXX%s%d:%02d:%02d",
-                               "-" + (XINT(zone) < 0), abszone / (60 * 60),
-                               (abszone / 60) % 60, abszone % 60);
+                       int sz = snprintf(tzbuf, sizeof(tzbuf), "XXX%s%d:%02d:%02d",
+                                         "-" + (XINT(zone) < 0), abszone / (60 * 60),
+                                         (abszone / 60) % 60, abszone % 60);
+                       assert(sz>=0 && (size_t)sz < sizeof(tzbuf));
                        tzstring = tzbuf;
                } else
                        error("Invalid time zone specification");
@@ -1559,8 +1658,10 @@ the data it can't find.
                        /* No local time zone name is available; use "+-NNNN"
                           instead.  */
                        int am = (offset < 0 ? -offset : offset) / 60;
-                       sprintf(buf, "%c%02d%02d", (offset < 0 ? '-' : '+'),
-                               am / 60, am % 60);
+                       int sz = snprintf(buf, sizeof(buf), "%c%02d%02d",
+                                         (offset < 0 ? '-' : '+'),
+                                         am / 60, am % 60);
+                       assert(sz>=0 && (size_t)sz < sizeof(buf));
                        s = buf;
                }
                return list2(make_int(offset), build_string(s));
@@ -1746,7 +1847,7 @@ DEFUN("insert-string", Finsert_string, 1, 2, 0,   /*
 Insert STRING into BUFFER at BUFFER's point.
 Point moves forward so that it ends up after the inserted text.
 Any other markers at the point of insertion remain before the text.
-If a string has non-null string-extent-data, new extents will be created.
+If a string has non-null, duplicable string-extent-data, new extents will be created.
 BUFFER defaults to the current buffer.
 */
       (string, buffer))
@@ -2688,9 +2789,12 @@ void syms_of_editfns(void)
 
        DEFSUBR(Ftemp_directory);
        DEFSUBR(Fuser_login_name);
+       DEFSUBR(Fuser_group_name);
        DEFSUBR(Fuser_real_login_name);
        DEFSUBR(Fuser_uid);
        DEFSUBR(Fuser_real_uid);
+       DEFSUBR(Fuser_gid);
+       DEFSUBR(Fuser_real_gid);
        DEFSUBR(Fuser_full_name);
        DEFSUBR(Fuser_home_directory);
        DEFSUBR(Femacs_pid);