]> git.decadent.org.uk Git - ion3.git/blob - ion/ion.c
93a59776a7ef8a5b7fcd4a5e0d9cda17388a0430
[ion3.git] / ion / ion.c
1 /*
2  * ion/ion/ion.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2006. 
5  *
6  * Ion is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21
22 #include <libtu/util.h>
23 #include <libtu/optparser.h>
24 #include <libtu/errorlog.h>
25 #include <libextl/readconfig.h>
26 #include <libmainloop/exec.h>
27
28 #include <ioncore/common.h>
29 #include <ioncore/global.h>
30 #include <ioncore/ioncore.h>
31 #include <ioncore/exec.h>
32 #include <ioncore/event.h>
33 #include "../version.h"
34
35
36 /* Options. Getopt is not used because getopt_long is quite gnu-specific
37  * and they don't know of '-display foo' -style args anyway.
38  * Instead, I've reinvented the wheel in libtu :(.
39  */
40 static OptParserOpt ion_opts[]={
41     {OPT_ID('d'), "display",  OPT_ARG, "host:dpy.scr", 
42      DUMMY_TR("X display to use")},
43     
44     {'c', "conffile", OPT_ARG, "config_file", 
45      DUMMY_TR("Configuration file")},
46     
47     {'s', "searchdir", OPT_ARG, "dir", 
48      DUMMY_TR("Add directory to search path")},
49
50     {OPT_ID('o'), "oneroot",  0, NULL,
51      DUMMY_TR("Manage default root window/non-Xinerama screen only")},
52
53 #if defined(CF_XINERAMA) || defined(CF_SUN_XINERAMA)
54     {OPT_ID('x'), "xinerama", OPT_ARG, "1|0", 
55      DUMMY_TR("Use Xinerama screen information (default: 1/yes)")},
56 #else
57     {OPT_ID('x'), "xinerama", OPT_ARG, "?", 
58      DUMMY_TR("Ignored: not compiled with Xinerama support")},
59 #endif
60     
61     {OPT_ID('s'), "session",  OPT_ARG, "session_name", 
62      DUMMY_TR("Name of session (affects savefiles)")},
63     
64     {OPT_ID('S'), "smclientid", OPT_ARG, "client_id", 
65      DUMMY_TR("Session manager client ID")},
66
67     {OPT_ID('N'), "noerrorlog", 0, NULL, 
68      DUMMY_TR("Do not create startup error log and display it "
69               "with xmessage.")},
70     
71     {'h', "help", 0, NULL, 
72      DUMMY_TR("Show this help")},
73     
74     {'V', "version", 0, NULL,
75      DUMMY_TR("Show program version")},
76     
77     {OPT_ID('a'), "about", 0, NULL,
78      DUMMY_TR("Show about text")},
79     
80     END_OPTPARSEROPTS
81 };
82
83
84 void check_new_user_help()
85 {
86     const char *userdir=extl_userdir();
87     char *oldbeard=NULL;
88     char *tmp=NULL, *cmd=NULL;
89     pid_t pid;
90     bool ret;
91
92     if(userdir==NULL){
93         warn(TR("Could not get user configuration file directory."));
94         return;
95     }
96     
97     libtu_asprintf(&oldbeard, "%s/.welcome_msg_displayed", userdir);
98     
99     if(oldbeard==NULL)
100         return;
101     
102     if(access(oldbeard, F_OK)==0){
103         free(oldbeard);
104         return;
105     }
106
107     libtu_asprintf(&tmp, TR("%s/welcome.txt"), SHAREDIR);
108     
109     if(tmp!=NULL){
110         if(access(tmp, F_OK)==0)
111             libtu_asprintf(&cmd, "%s %s", CF_XMESSAGE, tmp);
112         else
113             libtu_asprintf(&cmd, "%s %s/welcome.txt", CF_XMESSAGE, SHAREDIR);
114     
115         free(tmp);
116         
117         if(cmd!=NULL){
118             ret=ioncore_exec(cmd);
119     
120             free(cmd);
121     
122             if(ret){
123                 /* This should actually be done when less or xmessage returns,
124                  * but that would mean yet another script...
125                  */
126                 mkdir(userdir, 0700);
127                 if(open(oldbeard, O_CREAT|O_RDWR, 0600)<0)
128                     warn_err_obj(oldbeard);
129             }
130         }
131     }
132
133     free(oldbeard);
134 }
135
136
137 static void help()
138 {
139     int i;
140     printf(TR("Usage: %s [options]\n\n"), prog_execname());
141     for(i=0; ion_opts[i].descr!=NULL; i++)
142         ion_opts[i].descr=TR(ion_opts[i].descr);
143     optparser_printhelp(OPTP_MIDLONG, ion_opts);
144     printf("\n");
145 }
146
147
148 int main(int argc, char*argv[])
149 {
150     const char *cfgfile="cfg_ion";
151     const char *display=NULL;
152     char *cmd=NULL;
153     int stflags=0;
154     int opt;
155     ErrorLog el;
156     FILE *ef=NULL;
157     char *efnam=NULL;
158     bool may_continue=FALSE;
159     bool noerrorlog=FALSE;
160
161     libtu_init(argv[0]);
162
163     if(!ioncore_init("ion3", argc, argv, LOCALEDIR))
164         return EXIT_FAILURE;
165
166     extl_add_searchdir(EXTRABINDIR); /* ion-completefile */
167     extl_add_searchdir(MODULEDIR);
168     extl_add_searchdir(ETCDIR);
169     extl_add_searchdir(SHAREDIR);
170     extl_add_searchdir(LCDIR);
171     extl_set_userdirs("ion3");
172
173     optparser_init(argc, argv, OPTP_MIDLONG, ion_opts);
174     
175     while((opt=optparser_get_opt())){
176         switch(opt){
177         case OPT_ID('d'):
178             display=optparser_get_arg();
179             break;
180         case 'c':
181             cfgfile=optparser_get_arg();
182             break;
183         case 's':
184             extl_add_searchdir(optparser_get_arg());
185             break;
186         case OPT_ID('S'):
187             ioncore_g.sm_client_id=optparser_get_arg();
188             break;
189         case OPT_ID('o'):
190             stflags|=IONCORE_STARTUP_ONEROOT;
191             break;
192         case OPT_ID('x'):
193             {
194                 const char *p=optparser_get_arg();
195                 if(strcmp(p, "1")==0)
196                     stflags&=~IONCORE_STARTUP_NOXINERAMA;
197                 else if(strcmp(p, "0")==0)
198                     stflags|=IONCORE_STARTUP_NOXINERAMA;
199                 else
200                     warn(TR("Invalid parameter to -xinerama."));
201             }
202             break;
203         case OPT_ID('s'):
204             extl_set_sessiondir(optparser_get_arg());
205             break;
206         case OPT_ID('N'):
207             noerrorlog=TRUE;
208             break;
209         case 'h':
210             help();
211             return EXIT_SUCCESS;
212         case 'V':
213             printf("%s\n", ION_VERSION);
214             return EXIT_SUCCESS;
215         case OPT_ID('a'):
216             printf("%s\n", ioncore_aboutmsg());
217             return EXIT_SUCCESS;
218         default:
219             warn(TR("Invalid command line."));
220             help();
221             return EXIT_FAILURE;
222         }
223     }
224
225     if(!noerrorlog){
226         /* We may have to pass the file to xmessage so just using tmpfile()
227          * isn't sufficient.
228          */
229         libtu_asprintf(&efnam, "%s/ion-%d-startup-errorlog", P_tmpdir,
230                        getpid());
231         if(efnam==NULL){
232             warn_err();
233         }else{
234             ef=fopen(efnam, "wt");
235             if(ef==NULL){
236                 warn_err_obj(efnam);
237                 free(efnam);
238                 efnam=NULL;
239             }else{
240                 cloexec_braindamage_fix(fileno(ef));
241                 fprintf(ef, TR("Ion startup error log:\n"));
242                 errorlog_begin_file(&el, ef);
243             }
244         }
245     }
246
247     if(ioncore_startup(display, cfgfile, stflags))
248         may_continue=TRUE;
249
250 fail:
251     if(!may_continue)
252         warn(TR("Refusing to start due to encountered errors."));
253     else
254         check_new_user_help();
255     
256     if(ef!=NULL){
257         pid_t pid=-1;
258         if(errorlog_end(&el) && ioncore_g.dpy!=NULL){
259             fclose(ef);
260             pid=fork();
261             if(pid==0){
262                 ioncore_setup_environ(DefaultScreen(ioncore_g.dpy));
263                 if(!may_continue)
264                     XCloseDisplay(ioncore_g.dpy);
265                 else
266                     close(ioncore_g.conn);
267                 libtu_asprintf(&cmd, CF_XMESSAGE " %s", efnam);
268                 if(cmd==NULL){
269                     warn_err();
270                 }else if(system(cmd)==-1){
271                     warn_err_obj(cmd);
272                 }
273                 unlink(efnam);
274                 exit(EXIT_SUCCESS);
275             }
276             if(!may_continue && pid>0)
277                 waitpid(pid, NULL, 0);
278         }else{
279             fclose(ef);
280         }
281         if(pid<0)
282             unlink(efnam);
283         free(efnam);
284     }
285
286     if(!may_continue)
287         return EXIT_FAILURE;
288     
289     ioncore_mainloop();
290     
291     /* The code should never return here */
292     return EXIT_SUCCESS;
293 }