1 /* Client process that communicates with GNU Emacs acting as server.
2    Copyright (C) 1986, 1987 Free Software Foundation, Inc.
3 
4 This file is part of GNU Emacs.
5 
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10 
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING.  If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19 
20 
21 #define NO_SHORTNAMES
22 #include "../src/config.h"
23 #undef read
24 #undef write
25 #undef open
26 #ifdef close
27 #undef close
28 #endif
29 
30 
31 #if !defined(BSD) && !defined(HAVE_SYSVIPC)
32 #include <stdio.h>
33 
34 main (argc, argv)
35      int argc;
36      char **argv;
37 {
38   fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
39 	   argv[0]);
40   fprintf (stderr, "on systems with Berkeley sockets or System V IPC.\n");
41   exit (1);
42 }
43 
44 #else /* BSD or HAVE_SYSVIPC */
45 
46 #if defined(BSD) && ! defined (HAVE_SYSVIPC)
47 /* BSD code is very different from SYSV IPC code */
48 
49 #include <sys/types.h>
50 #include <sys/socket.h>
51 #include <sys/un.h>
52 #include <stdio.h>
53 #include <errno.h>
54 #include <sys/stat.h>
55 
56 extern int sys_nerr;
57 extern char *sys_errlist[];
58 extern int errno;
59 
60 main (argc, argv)
61      int argc;
62      char **argv;
63 {
64   int s, i;
65   FILE *out;
66   struct sockaddr_un server;
67   char *homedir, *cwd, *str;
68   char string[BUFSIZ];
69   struct stat statbfr;
70 
71   char *getenv (), *getwd ();
72 
73   if (argc < 2)
74     {
75       fprintf (stderr, "Usage: %s filename\n", argv[0]);
76       exit (1);
77     }
78 
79   /*
80    * Open up an AF_UNIX socket in this person's home directory
81    */
82 
83   if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
84     {
85       fprintf (stderr, "%s: ", argv[0]);
86       perror ("socket");
87       exit (1);
88     }
89   server.sun_family = AF_UNIX;
90 #ifndef SERVER_HOME_DIR
91   (void) sprintf (server.sun_path, "/tmp/esrv%d", geteuid());
92   if (stat (server.sun_path, &statbfr) == -1)
93     {
94       perror ("stat");
95       exit (1);
96     }
97   if (statbfr.st_uid != geteuid())
98     {
99       fprintf (stderr, "Illegal socket owner\n");
100       exit (1);
101     }
102 #else
103   if ((homedir = getenv ("HOME")) == NULL)
104     {
105       fprintf (stderr, "%s: No home directory\n", argv[0]);
106       exit (1);
107     }
108   strcpy (server.sun_path, homedir);
109   strcat (server.sun_path, "/.emacs_server");
110 #endif
111 
112   if (connect (s, &server, strlen (server.sun_path) + 2) < 0)
113     {
114       fprintf (stderr, "%s: ", argv[0]);
115       perror ("connect");
116       exit (1);
117     }
118   if ((out = fdopen (s, "r+")) == NULL)
119     {
120       fprintf (stderr, "%s: ", argv[0]);
121       perror ("fdopen");
122       exit (1);
123     }
124 
125   cwd = getwd (string);
126   if (cwd == 0)
127     {
128       /* getwd puts message in STRING if it fails.  */
129       fprintf (stderr, "%s: %s (%s)\n", argv[0], string,
130 	       (errno < sys_nerr) ? sys_errlist[errno] : "unknown error");
131       exit (1);
132     }
133 
134   for (i = 1; i < argc; i++)
135     {
136       if (*argv[i] == '+')
137 	{
138 	  char *p = argv[i] + 1;
139 	  while (*p >= '0' && *p <= '9') p++;
140 	  if (*p != 0)
141 	    fprintf (out, "%s/", cwd);
142 	}
143       else if (*argv[i] != '/')
144 	fprintf (out, "%s/", cwd);
145       fprintf (out, "%s ", argv[i]);
146     }
147   fprintf (out, "\n");
148   fflush (out);
149 
150   printf ("Waiting for Emacs...");
151   fflush (stdout);
152 
153   rewind (out); /* re-read the output */
154   str = fgets (string, BUFSIZ, out);
155 
156   /* Now, wait for an answer and print any messages.  */
157 
158   while (str = fgets (string, BUFSIZ, out))
159     printf ("%s", str);
160 
161   exit (0);
162 }
163 
164 #else /* This is the SYSV IPC section */
165 
166 #include <sys/types.h>
167 #include <sys/ipc.h>
168 #include <sys/msg.h>
169 #include <stdio.h>
170 
171 main (argc, argv)
172      int argc;
173      char **argv;
174 {
175   int s;
176   key_t key;
177   struct msgbuf * msgp =
178       (struct msgbuf *) malloc (sizeof *msgp + BUFSIZ);
179   struct msqid_ds * msg_st;
180   char *homedir, buf[BUFSIZ];
181   char gwdirb[BUFSIZ];
182   char *cwd;
183   char *temp;
184   char *getwd (), *getcwd (), *getenv ();
185 
186   if (argc < 2)
187     {
188       fprintf (stderr, "Usage: %s filename\n", argv[0]);
189       exit (1);
190     }
191 
192   /*
193    * Create a message queue using ~/.emacs_server as the path for ftok
194    */
195   if ((homedir = getenv ("HOME")) == NULL)
196     {
197       fprintf (stderr, "%s: No home directory\n", argv[0]);
198       exit (1);
199     }
200   strcpy (buf, homedir);
201   strcat (buf, "/.emacs_server");
202   creat (buf, 0600);
203   key = ftok (buf, 1);	/* unlikely to be anyone else using it */
204   s = msgget (key, 0600);
205   if (s == -1)
206     {
207       fprintf (stderr, "%s: ", argv[0]);
208       perror ("msgget");
209       exit (1);
210     }
211 
212   /* Determine working dir, so we can prefix it to all the arguments.  */
213 #ifdef BSD
214   temp = getwd (gwdirb);
215 #else
216   temp = getcwd (gwdirb, sizeof gwdirb);
217 #endif
218 
219   cwd = gwdirb;
220   if (temp != 0)
221     {
222       /* On some systems, cwd can look like `@machine/...';
223 	 ignore everything before the first slash in such a case.  */
224       while (*cwd && *cwd != '/')
225 	cwd++;
226       strcat (cwd, "/");
227     }
228   else
229     {
230       fprintf (stderr, cwd);
231       exit (1);
232     }
233 
234   msgp->mtext[0] = 0;
235   argc--; argv++;
236   while (argc)
237     {
238       if (*argv[0] == '+')
239 	{
240 	  char *p = argv[0] + 1;
241 	  while (*p >= '0' && *p <= '9') p++;
242 	  if (*p != 0)
243 	    strcat (msgp->mtext, cwd);
244 	}
245       else if (*argv[0] != '/')
246 	strcat (msgp->mtext, cwd);
247 
248       strcat (msgp->mtext, argv[0]);
249       strcat (msgp->mtext, " ");
250       argv++; argc--;
251     }
252   strcat (msgp->mtext, "\n");
253   msgp->mtype = 1;
254   if (msgsnd (s, msgp, strlen (msgp->mtext)+1, 0) < 0)
255     {
256       fprintf (stderr, "%s: ", argv[0]);
257       perror ("msgsnd");
258       exit (1);
259     }
260   /*
261    * Now, wait for an answer
262    */
263   printf ("Waiting for Emacs...");
264   fflush (stdout);
265 
266   msgrcv (s, msgp, BUFSIZ, getpid (), 0);	/* wait for anything back */
267   strcpy (buf, msgp->mtext);
268 
269   printf ("\n%s\n", buf);
270   exit (0);
271 }
272 
273 #endif /* HAVE_SYSVIPC */
274 
275 #endif /* BSD or HAVE_SYSVIPC */
276