[comp.emacs] Changing major mode in server mode

cudcv@daisy.warwick.ac.uk (Rob McMahon) (03/15/88)

<munch>

I've just installed emacs 18.50, and have a couple of problems with M-x
server-start/emacsclient.

The first is more a comment than a problem.  In an NFS environment, you
can't have a server running on more than one machine, because each uses
the same rendezvous point, and each new invocation of the server removes
the socket the other machine had created.  Maybe it should be using
something like ("%s/.emacsclient.%s", getenv("HOME"), gethostname()) ?
This isn't much of a problem for me, since I do most of the things I'd
want a server for on the same machine.

The second problem is if I change major mode in the buffer created in
the server emacs, it calls kill-all-local-variables, which includes
server-buffer-clients, which means C-x# doesn't work any more.  I know I
can usually end up in the right mode by tacking things onto
auto-mode-alist, or by setting default-major-mode, but often I want to
switch modes:  I'm replying to someone's mail, and I want to include a
bit of C, so I switch to c-mode for a while:  I'm writing a C program
and I want to insert a block comment, so I switch to text-mode for a
while.

Is there any way round this ?  Can I protect server-buffer-clients for a
while, or can I 'push' a mode and then exit it leaving all my variables
the way they were before ?  Or do I have to write my own alternatives to
c-mode and text-mode (and tex-mode, and ...) that don't call
kill-all-local-variables ?

Thanks,

Rob



-- 
UUCP:   ...!mcvax!ukc!warwick!cudcv	PHONE:  +44 203 523037
JANET:  cudcv@uk.ac.warwick.cu          ARPA:   cudcv@cu.warwick.ac.uk
Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England

pinkas@cadev4.intel.com (Israel Pinkas ~) (03/19/88)

In article <480@sol.warwick.ac.uk> cudcv@cu.warwick.ac.uk (Rob McMahon) writes:
><munch>
>
>I've just installed emacs 18.50, and have a couple of problems with M-x
>server-start/emacsclient.
>
>The first is more a comment than a problem.  In an NFS environment, you
>can't have a server running on more than one machine, because each uses
>the same rendezvous point, and each new invocation of the server removes
>the socket the other machine had created.  Maybe it should be using
>something like ("%s/.emacsclient.%s", getenv("HOME"), gethostname()) ?
>This isn't much of a problem for me, since I do most of the things I'd
>want a server for on the same machine.

I have this same problem.  I sent some mail to the GNU people about a year
ago, telling them what I had to do with GNU Emacs 17, but the changes never
made it into v18.  Anyway, here is the problem.

The NFS spec does not provide for special files to be accessed across NFS.
Thus, creating, reading, and writing a socket are not possible over NFS.
In our environment, we have a large number of workstations mounting
directories from a large VAX.  Almost all the users home directories are
mounted in this way.  This means that ~/.emacs_server is not feasible to
use unless emacs happens to be running on the file server, shich is not
desirable.

My solution was to change the three files that deal with the server/client.
They are: etc/emacsclient.c, etc/server.c, and lisp/server.el.  I changed
the name of the server file in each of these to /tmp/.emacs_server_<user>,
where <user> is the environment variable USER if available, the return
value of getuid() otherwise.

My reasoning is that the /tmp directory should be local.  (We run X on all
of our workstations, and X10 puts a socket file in /tmp.  I figured that if
/tmp is not local, we have bigger problems than emacs servers not running.)
Diskless nodes should be OK as they do not mount / via NFS.  (This is not
tested, though.)

Following are the diffs I put into 18.49.  When I get 18.50, I will look
into what problems might be caused on sysV (which I understand iis
supported, but we have some nodes running NFS also).

Note that you may still only have one emacs server per user per machine.
Thus, if you have a group account, and two users run emacs, the second one
to start the server will receive all subsequent requests.  Other things
might be messed up.  Since this was a limitation in the original code, I
don't mind this.  And I am wary.  The reason that I didn't do anything
about this is that I couldn't figure out how to make the clients know which
server to talk to.  A possibility for resolving this could be:

If under X, encode $DISPLAY in the server filename.  All clients on that
window would get the same server.  Since I don't anticipate two users on
the same window in the same account not being able to use the same emacs,
this should work.  Something similar could be done for Suns and other
windowing systems.

Otherwise, we must be running the server on the same terminal as the
client.  (I don't know what to do in the case of layers/emacs terminal
emulation.  Suggestions welcome.)  Place the name of the terminal in the
server filename.  For ptys (layers, terminal-mode) the terminal name of the
real terminal might be used.

-Israel

Cut here and make sure that Pnews did not add a .signature below

------------------------------------------------------------------
*** lisp/server.el.orig	Sun Feb 21 13:00:39 1988
--- lisp/server.el	Fri Mar 18 15:23:31 1988
***************
*** 108,114
        (progn
  	(set-process-sentinel server-process nil)
  	(condition-case () (delete-process server-process) (error nil))))
!   (condition-case () (delete-file "~/.emacs_server") (error nil))
    ;; If we already had a server, clear out associated status.
    (while server-clients
      (let ((buffer (nth 1 (car server-clients))))

--- 108,114 -----
        (progn
  	(set-process-sentinel server-process nil)
  	(condition-case () (delete-process server-process) (error nil))))
!   (condition-case () (delete-file "/tmp/.emacs_server_$USER") (error nil))
    ;; If we already had a server, clear out associated status.
    (while server-clients
      (let ((buffer (nth 1 (car server-clients))))
*** etc/server.c.orig	Thu Feb 25 10:56:33 1988
--- etc/server.c	Fri Mar 18 15:19:00 1988
***************
*** 55,61
  {
    int s, infd, fromlen;
    struct sockaddr_un server, fromunix;
!   char *homedir;
    char *str, string[BUFSIZ], code[BUFSIZ];
    FILE *infile;
    FILE **openfiles;

--- 55,61 -----
  {
    int s, infd, fromlen;
    struct sockaddr_un server, fromunix;
!   char *username;
    char *str, string[BUFSIZ], code[BUFSIZ];
    FILE *infile;
    FILE **openfiles;
***************
*** 78,90
        exit (1);
      }
    server.sun_family = AF_UNIX;
!   if ((homedir = getenv ("HOME")) == NULL)
!     {
!       fprintf (stderr,"No home directory\n");
!       exit (1);
!     }
!   strcpy (server.sun_path, homedir);
!   strcat (server.sun_path, "/.emacs_server");
    if (bind (s, &server, strlen (server.sun_path) + 2) < 0)
      {
        perror ("bind");

--- 78,87 -----
        exit (1);
      }
    server.sun_family = AF_UNIX;
!   if ((username = getenv ("USER")) == NULL)
!     sprintf(server.sun_path, "/tmp/.emacs_server_%d", getuid());
!   else
!     sprintf(server.sun_path, "/tmp/.emacs_server_%s", username);
    if (bind (s, &server, strlen (server.sun_path) + 2) < 0)
      {
        perror ("bind");
*** etc/emacsclient.c.orig	Fri Mar 18 15:06:56 1988
--- etc/emacsclient.c	Fri Mar 18 15:20:34 1988
***************
*** 48,54
    int s, n, i;
    FILE *out;
    struct sockaddr_un server;
!   char *homedir, *cwd, *str;
    char string[BUFSIZ];
  
    char *getenv (), *getwd ();

--- 48,54 -----
    int s, n, i;
    FILE *out;
    struct sockaddr_un server;
!   char *username, *cwd, *str;
    char string[BUFSIZ];
  
    char *getenv (), *getwd ();
***************
*** 69,81
        exit (1);
      }
    server.sun_family = AF_UNIX;
!   if ((homedir = getenv ("HOME")) == NULL)
!     {
!       fprintf (stderr, "No home directory\n");
!       exit (1);
!     }
!   strcpy (server.sun_path, homedir);
!   strcat (server.sun_path, "/.emacs_server");
    if (connect (s, &server, strlen (server.sun_path) + 2) < 0)
      {
        perror ("connect");

--- 69,78 -----
        exit (1);
      }
    server.sun_family = AF_UNIX;
!   if ((username = getenv ("USER")) == NULL)
!     sprintf(server.sun_path, "/tmp/.emacs_server_%d", getuid());
!   else
!     sprintf(server.sun_path, "/tmp/.emacs_server_%s", username);
    if (connect (s, &server, strlen (server.sun_path) + 2) < 0)
      {
        perror ("connect");

----------------------------------------------------------------------
Disclaimer: The above are my personal opinions, and in no way represent
the opinions of Intel Corporation.  In no way should the above be taken
to be a statement of Intel.

UUCP:	{amdcad,decwrl,hplabs,oliveb,pur-ee,qantel}!intelca!mipos3!cadev4!pinkas
ARPA:	pinkas%cadev4.intel.com@relay.cs.net
CSNET:	pinkas%cadev4.intel.com

---------
"You can do more with a kind word and a gun than with just a kind word"

			-Al Capone

jbw@bucsb.UUCP (Joe Wells) (03/19/88)

In article <480@sol.warwick.ac.uk> cudcv@cu.warwick.ac.uk (Rob McMahon) writes:
>The second problem is if I change major mode in the buffer created in
>the server emacs, it calls kill-all-local-variables, which includes
>server-buffer-clients, which means C-x# doesn't work any more.
>
>Is there any way round this ?  Can I protect server-buffer-clients for a
>while, or can I 'push' a mode and then exit it leaving all my variables
>the way they were before ?  Or do I have to write my own alternatives to
>c-mode and text-mode (and tex-mode, and ...) that don't call
>kill-all-local-variables ?
>
>UUCP:   ...!mcvax!ukc!warwick!cudcv	PHONE:  +44 203 523037
>JANET:  cudcv@uk.ac.warwick.cu          ARPA:   cudcv@cu.warwick.ac.uk
>Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England

I have run into this same problem in the past.  My solution was to
rewrite kill-all-local-variables so that it left my variables alone.
This is not straightforward, since there is no function to kill a
single local variable.  kill-all-local-variables is one of the C
functions, so my function had to use the original
kill-all-local-variables, and then restore the variables that I wanted
to keep.  My version of kill-all-local-variables follows.

----
Joe Wells can be reached at:
UUCP:  ..!harvard!bu-cs!bucsb!jbw    _   /|
ARPANET: jbw@bucsb.bu.edu            \`o_O'
CSNET: jbw%bucsb@bu-cs                 ( )   "Ack! Phft!"
BITNET:  clxj9lc@bostonu                U

;;; save the original kill-all-local-variables
;;; must check if we have already changed it
(if (not (fboundp 'old-kill-all-local-variables))
    (fset 'old-kill-all-local-variables
	  (symbol-function 'kill-all-local-variables)))

(defun kill-all-local-variables ()
  "Eliminate all the buffer-local variable values of the current buffer.
This buffer will then see the default values of all variables.

NOTE: This function has been modified to ignore buffer-local variables
which match the regexp in save-local-variables."
  (let ((oldvars (buffer-local-variables)))
    (old-kill-all-local-variables)
    (while oldvars
      (let* ((elem (car oldvars))
	     (var (car elem))
	     (value (cdr elem)))
	(cond ((string-match save-local-variables (symbol-name var))
	       (make-local-variable var)
	       (set var value))))
      (setq oldvars (cdr oldvars)))))

(defvar save-local-variables ""
  "This is a regexp which is used each time kill-local-variables is
called to determine which variables not to kill.  The variable name is
matched against the regexp.")

mike@turing.UNM.EDU (Michael I. Bushnell) (03/22/88)

In article <1894@mipos3.intel.com> pinkas@cadev4.UUCP (Israel Pinkas ~) writes:

>The NFS spec does not provide for special files to be accessed across NFS.
>Thus, creating, reading, and writing a socket are not possible over NFS.
>In our environment, we have a large number of workstations mounting
>directories from a large VAX.  Almost all the users home directories are
>mounted in this way.  This means that ~/.emacs_server is not feasible to
>use unless emacs happens to be running on the file server, shich is not
>desirable.

The NFS spec does not dal with special files.  Correct.  But it does
deal with sockets (in a strange way).  Socket != Spec. file.  My
directory is on another machine.  All my processes are on this one,
and everything works fine.

The emacsclient must be started on the same machine as the emacs
itself.  This will also prevent the creation of another .emacs_server
from another client.  The socket is actually created on the server,
but the connect/accept/listen must all occur on the same machine.  But
NOT necessarily the server itself.

The "solution" is thus not necessary.
			Michael I. Bushnell
			HASA - "A" division
14308 Skyline Rd NE				Computer Science Dept.
Albuquerque, NM  87123		OR		Farris Engineering Ctr.
	OR					University of New Mexico
mike@turing.unm.edu				Albuquerque, NM  87131
{ucbvax,gatech}!unmvax!turing.unm.edu!mike

cudcv@daisy.warwick.ac.uk (Rob McMahon) (04/03/88)

I did try to reply to this, but the mailer was having none of it ...

In article <1894@mipos3.intel.com> pinkas@cadev4.UUCP (Israel Pinkas ~) writes:
|[Re: problems with having the same socket name on multiple machines
|when in and NFS environment]
|I changed the name of the server file ... to /tmp/.emacs_server_<user>,
 
Thanks for the patches, but:
 
|The NFS spec does not provide for special files to be accessed across NFS.
|Thus, creating, reading, and writing a socket are not possible over NFS.
|...
|My reasoning [for moving the socket to /tmp] is that the /tmp directory
|should be local.  (... X10 puts a socket file in /tmp.  I figured that
|if /tmp is not local, we have bigger problems than emacs servers not
|running.)  Diskless nodes should be OK as they do not mount / via NFS.
|(This is not tested, though.)
 
I'm confused.  I sit here now on my diskless machine using emacsclient,
emacs version 18.50, with no patches, and with the socket in my home
directory, NFS mounted.  All works fine.  Maybe Sun have changed the NFS
spec since the VAX version ?  After all, I can't think of any good
reason for it to fail, all it wants from the socket is it's mode and
filehandle.
 
Rob
 
--
UUCP:   ...!mcvax!ukc!warwick!cudcv    PHONE:  +44 203 523037
JANET:  cudcv@uk.ac.warwick.cu          ARPA:   cudcv@cu.warwick.ac.uk
Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England
-- 
UUCP:   ...!mcvax!ukc!warwick!cudcv	PHONE:  +44 203 523037
JANET:  cudcv@uk.ac.warwick.cu          ARPA:   cudcv@cu.warwick.ac.uk
Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England