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