1/* $Xorg: saveutil.c,v 1.5 2001/02/09 02:06:01 xorgcvs Exp $ */
2/******************************************************************************
3
4Copyright 1993, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25******************************************************************************/
26/* $XFree86: xc/programs/xsm/saveutil.c,v 1.5 2001/01/17 23:46:31 dawes Exp $ */
27
28#include "xsm.h"
29#include "log.h"
30#include "saveutil.h"
31#include "info.h"
32
33static char 		 session_save_file[PATH_MAX];
34
35
36void
37set_session_save_file_name(const char *session_name)
38{
39    const char *p;
40
41    p = getenv ("SM_SAVE_DIR");
42    if (!p)
43    {
44	p = getenv ("HOME");
45	if (!p)
46	    p = ".";
47    }
48
49    snprintf (session_save_file, sizeof(session_save_file),
50	      "%s/.XSM-%s", p, session_name);
51}
52
53
54
55int
56ReadSave(const char *session_name, char **sm_id)
57{
58    char		*buf;
59    int			buflen;
60    char		*p;
61    PendingClient	*c = NULL;
62    Prop		*prop = NULL;
63    PropValue		*val;
64    FILE		*f;
65    int			state, i;
66    int			version_number;
67
68    f = fopen(session_save_file, "r");
69    if(!f) {
70	if (verbose)
71	    printf("No session save file.\n");
72	*sm_id = NULL;
73	return 0;
74    }
75    fcntl(fileno(f), F_SETFD, FD_CLOEXEC);
76    if (verbose)
77	printf("Reading session save file...\n");
78
79    buf = NULL;
80    buflen = 0;
81
82    /* Read version # */
83    getnextline(&buf, &buflen, f);
84    if((p = strchr(buf, '\n'))) *p = '\0';
85    version_number = atoi (buf);
86    if (version_number > SAVEFILE_VERSION)
87    {
88	if (verbose)
89	    printf("Unsupported version number of session save file.\n");
90	*sm_id = NULL;
91	if (buf)
92	    free (buf);
93	return 0;
94    }
95
96    /* Read SM's id */
97    getnextline(&buf, &buflen, f);
98    if((p = strchr(buf, '\n'))) *p = '\0';
99    *sm_id = XtNewString(buf);
100
101    /* Read number of clients running in the last session */
102    if (version_number >= 2)
103    {
104	getnextline(&buf, &buflen, f);
105	if((p = strchr(buf, '\n'))) *p = '\0';
106	num_clients_in_last_session = atoi (buf);
107    }
108
109    state = 0;
110    while(getnextline(&buf, &buflen, f)) {
111	if((p = strchr(buf, '\n'))) *p = '\0';
112	for(p = buf; *p && isspace(*p); p++) /* LOOP */;
113	if(*p == '#') continue;
114
115	if(!*p)
116	{
117	    if (version_number >= 3 &&
118		ListCount (PendingList) == num_clients_in_last_session)
119	    {
120		state = 5;
121		break;
122	    }
123	    else
124	    {
125		state = 0;
126		continue;
127	    }
128	}
129
130	if(!isspace(buf[0])) {
131	    switch(state) {
132		case 0:
133		    c = (PendingClient *)XtMalloc(sizeof *c);
134		    if(!c) nomem();
135
136		    c->clientId = XtNewString(p);
137		    c->clientHostname = NULL;  /* set in next state */
138
139		    c->props = ListInit();
140		    if(!c->props) nomem();
141
142		    if(!ListAddLast(PendingList, (char *)c)) nomem();
143
144		    state = 1;
145		    break;
146
147		case 1:
148		    c->clientHostname = XtNewString(p);
149                    state = 2;
150                    break;
151
152		case 2:
153		case 4:
154		    prop = (Prop *)XtMalloc(sizeof *prop);
155		    if(!prop) nomem();
156
157		    prop->name = XtNewString(p);
158		    prop->values = ListInit();
159		    if(!prop->values) nomem();
160
161		    prop->type = NULL;
162
163		    if(!ListAddLast(c->props, (char *)prop)) nomem();
164
165		    state = 3;
166		    break;
167
168		case 3:
169		    prop->type = XtNewString(p);
170		    state = 4;
171		    break;
172
173		default:
174		    fprintf(stderr, "state %d\n", state);
175		    fprintf(stderr,
176			    "Corrupt save file line ignored:\n%s\n", buf);
177		    continue;
178	    }
179	} else {
180	    if (state != 4) {
181		fprintf(stderr, "Corrupt save file line ignored:\n%s\n", buf);
182		continue;
183	    }
184	    val = (PropValue *)XtMalloc(sizeof *val);
185	    if(!val) nomem();
186
187	    if (strcmp (prop->type, SmCARD8) == 0)
188	    {
189		val->length = 1;
190		val->value = (XtPointer) XtMalloc (1);
191		*((char *)(val->value)) = atoi (p);
192	    }
193	    else
194	    {
195		val->length = strlen(p);
196		val->value = XtNewString(p);
197	    }
198
199	    if(!ListAddLast(prop->values, (char *)val)) nomem();
200	}
201    }
202
203    /* Read commands for non-session aware clients */
204
205    if (state == 5)
206    {
207	char *strbuf;
208	int bufsize = 0;
209
210	getnextline(&buf, &buflen, f);
211	if((p = strchr(buf, '\n'))) *p = '\0';
212	non_session_aware_count = atoi (buf);
213
214	if (non_session_aware_count > 0)
215	{
216	    non_session_aware_clients = (char **) malloc (
217	        non_session_aware_count * sizeof (char *));
218
219	    for (i = 0; i < non_session_aware_count; i++)
220	    {
221		getnextline(&buf, &buflen, f);
222		if((p = strchr(buf, '\n'))) *p = '\0';
223		non_session_aware_clients[i] = malloc (strlen (buf) + 2);
224		strcpy (non_session_aware_clients[i], buf);
225		bufsize += (strlen (buf) + 1);
226	    }
227
228	    strbuf = malloc (bufsize + 1);
229	    strbuf[0] = '\0';
230
231	    for (i = 0; i < non_session_aware_count; i++)
232	    {
233		strcat (strbuf, non_session_aware_clients[i]);
234		strcat (strbuf, "\n");
235	    }
236
237	    XtVaSetValues (manualRestartCommands,
238	        XtNstring, strbuf,
239	        NULL);
240
241	    free ((char *) strbuf);
242	}
243    }
244
245    fclose(f);
246
247    if (buf)
248	free (buf);
249
250    return 1;
251}
252
253
254
255static void
256SaveClient(FILE *f, ClientRec *client)
257{
258    List *pl;
259
260    fprintf (f, "%s\n", client->clientId);
261    fprintf (f, "%s\n", client->clientHostname);
262
263    for (pl = ListFirst (client->props); pl; pl = ListNext (pl))
264    {
265	Prop *pprop = (Prop *) pl->thing;
266	List *pj, *vl;
267	PropValue *pval;
268
269	fprintf (f, "%s\n", pprop->name);
270	fprintf (f, "%s\n", pprop->type);
271
272	if (strcmp (pprop->type, SmCARD8) == 0)
273	{
274	    char *card8;
275	    int value;
276
277	    vl = ListFirst (pprop->values);
278	    pval = (PropValue *) vl->thing;
279
280	    card8 = pval->value;
281	    value = *card8;
282	    fprintf(f, "\t%d\n", value);
283	}
284	else
285	{
286	    for (pj = ListFirst (pprop->values); pj; pj = ListNext (pj))
287	    {
288		pval = (PropValue *) pj->thing;
289		fprintf (f, "\t%s\n", (char *)pval->value);
290	    }
291	}
292    }
293
294    fprintf (f, "\n");
295}
296
297
298
299void
300WriteSave(const char *sm_id)
301{
302    ClientRec *client;
303    FILE *f;
304    List *cl;
305    char *commands;
306    char *p, *c;
307    int count;
308
309    f = fopen (session_save_file, "w");
310
311    if (!f)
312    {
313	char msg[36 + sizeof(session_save_file)];
314
315	snprintf (msg, sizeof(msg), "%s: Error creating session save file %s",
316		  Argv[0], session_save_file);
317	add_log_text (msg);
318	perror (msg);
319    }
320    else
321    {
322	fcntl(fileno(f), F_SETFD, FD_CLOEXEC);
323	fprintf (f, "%d\n", SAVEFILE_VERSION);
324	fprintf (f, "%s\n", sm_id);
325
326	count = 0;
327	for (cl = ListFirst (RunningList); cl; cl = ListNext (cl))
328	{
329	    client = (ClientRec *) cl->thing;
330
331	    if (client->restartHint != SmRestartNever)
332		count++;
333	}
334	count += ListCount (RestartAnywayList);
335
336	fprintf (f, "%d\n", count);
337	if (count == 0)
338	    fprintf (f, "\n");
339
340	for (cl = ListFirst (RunningList); cl; cl = ListNext (cl))
341	{
342	    client = (ClientRec *) cl->thing;
343
344	    if (client->restartHint == SmRestartNever)
345		continue;
346
347	    SaveClient (f, client);
348	}
349
350	for (cl = ListFirst (RestartAnywayList); cl; cl = ListNext (cl))
351	{
352	    client = (ClientRec *) cl->thing;
353
354	    SaveClient (f, client);
355	}
356
357
358	/* Save the non-session aware clients */
359
360	XtVaGetValues (manualRestartCommands,
361	    XtNstring, &commands,
362	    NULL);
363
364	p = c = commands;
365	count = 0;
366
367	while (*p)
368	{
369	    if (*p == '\n')
370	    {
371		if (p != c)
372		    count++;
373		c = p + 1;
374	    }
375	    p++;
376	}
377	if (p != c)
378	    count++;
379
380	fprintf (f, "%d\n", count);
381
382	p = c = commands;
383
384	while (*p)
385	{
386	    if (*p == '\n')
387	    {
388		if (p != c)
389		{
390		    *p = '\0';
391		    fprintf (f, "%s\n", c);
392		    *p = '\n';
393		}
394		c = p + 1;
395	    }
396	    p++;
397	}
398
399	if (p != c)
400	    fprintf (f, "%s\n", c);
401
402	fclose (f);
403    }
404}
405
406
407
408Status
409DeleteSession(const char *session_name)
410{
411    char	*buf;
412    int		buflen;
413    char	*p;
414    const char	*dir;
415    FILE	*f;
416    int		state;
417    int		foundDiscard;
418    char	filename[256];
419    int		version_number;
420
421    dir = getenv ("SM_SAVE_DIR");
422    if (!dir)
423    {
424	dir = getenv ("HOME");
425	if (!dir)
426	    dir = ".";
427    }
428
429    snprintf (filename, sizeof(filename), "%s/.XSM-%s", dir, session_name);
430
431    f = fopen(filename, "r");
432    if(!f) {
433	return (0);
434    }
435    fcntl(fileno(f), F_SETFD, FD_CLOEXEC);
436
437    buf = NULL;
438    buflen = 0;
439
440    /* Read version # */
441    getnextline(&buf, &buflen, f);
442    if((p = strchr(buf, '\n'))) *p = '\0';
443    version_number = atoi (buf);
444    if (version_number > SAVEFILE_VERSION)
445    {
446	if (verbose)
447	    printf("Can't delete session save file - incompatible version.\n");
448	if (buf)
449	    free (buf);
450	return (0);
451    }
452
453    /* Skip SM's id */
454    getnextline(&buf, &buflen, f);
455
456    /* Skip number of clients running in the last session */
457    if (version_number >= 2)
458	getnextline(&buf, &buflen, f);
459
460    state = 0;
461    foundDiscard = 0;
462    while(getnextline(&buf, &buflen, f)) {
463	if((p = strchr(buf, '\n'))) *p = '\0';
464	for(p = buf; *p && isspace(*p); p++) /* LOOP */;
465	if(*p == '#') continue;
466
467	if(!*p) {
468	    state = 0;
469	    foundDiscard = 0;
470	    continue;
471	}
472
473	if(!isspace(buf[0])) {
474	    switch(state) {
475		case 0:
476		    state = 1;
477		    break;
478
479		case 1:
480                    state = 2;
481                    break;
482
483		case 2:
484		case 4:
485		    if (strcmp (p, SmDiscardCommand) == 0)
486			foundDiscard = 1;
487		    state = 3;
488		    break;
489
490		case 3:
491		    state = 4;
492		    break;
493
494		default:
495		    continue;
496	    }
497	} else {
498	    if (state != 4) {
499		continue;
500	    }
501	    if (foundDiscard)
502	    {
503		execute_system_command (p);	/* Discard Command */
504		foundDiscard = 0;
505	    }
506	}
507    }
508
509    fclose(f);
510
511    if (buf)
512	free (buf);
513
514    return ((remove (filename) == -1) ? 0 : 1);
515}
516
517
518
519Bool
520getnextline(char **pbuf, int *plen, FILE *f)
521{
522	int c;
523	int i;
524
525	i = 0;
526	while(1) {
527	    if(i+2 > *plen) {
528		if(*plen) *plen *= 2;
529		else *plen = BUFSIZ;
530		if(*pbuf) *pbuf = (char *) realloc(*pbuf, *plen + 1);
531		else *pbuf = (char *) malloc(*plen + 1);
532	    }
533	    c = getc(f);
534	    if(c == EOF) break;
535	    (*pbuf)[i++] = c;
536	    if(c == '\n') break;
537	}
538	(*pbuf)[i] = '\0';
539	return i;
540}
541