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