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