preliminary support for ovr edits within mmenu
[pandora-libraries.git] / minimenu / mmwrapper.c
1
2 /* minimenu
3  * aka "2wm" - too weak menu, two week menu, akin to twm
4  *
5  * Craig wants a super minimal menu ASAP before launch, so lets see what I can put together in 2 weeks with not much
6  * free time ;) I'd like to do a fuller ('tiny', but with plugin support and a decent expansion and customizing design..)
7  * but later, baby!
8  *
9  */
10
11 /* mmwrapper -- we probably want the menu to exeunt-with-alarums when running applications, to minimize the memory and
12  * performance footprint; it could be running in-X or atop a desktop-env, or purely on SDL or framebuffer with nothing..
13  * so wrapper will actually do the running, and be tiny.
14  * Likewise, if the menu proper dies, the wrapper can fire it up again.
15  * A side effect is, people could use the wrappers abilities, and slap another cruddy menu on top of it .. yay for pure
16  * curses based or lynx-based menus ;)
17  */
18
19 /* mmwrapper's lifecycle:
20  * 1) launch 'frontend' (mmmenu, could be others)
21  * 2) when it exits, pick up the output...
22  *    a) either a command (quit, run some app, pick new frontend)
23  *    b) or a crash, in which case, back to (1)
24  * 3) execute command, if any
25  * 4) go to (1)
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <strings.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/wait.h>
37
38 #include "pnd_logger.h"
39
40 #include "mmwrapcmd.h"
41
42 unsigned char g_daemon_mode = 0;
43 char *g_frontend = NULL;
44
45 typedef enum {
46   pndn_debug = 0,
47   pndn_rem,          // will set default log level to here, so 'debug' is omitted
48   pndn_warning,
49   pndn_error,
50   pndn_none
51 } pndnotify_loglevels_e;
52
53 int main ( int argc, char *argv[] ) {
54   int logall = -1; // -1 means normal logging rules; >=0 means log all!
55   int i;
56
57   // pull conf, determine frontend; alternate is to check command line.
58
59   // boilerplate stuff from pndnotifyd and pndevmapperd
60
61   /* iterate across args
62    */
63   for ( i = 1; i < argc; i++ ) {
64
65     if ( argv [ i ][ 0 ] == '-' && argv [ i ][ 1 ] == 'd' ) {
66       //printf ( "Going daemon mode. Silent running.\n" );
67       g_daemon_mode = 1;
68     } else if ( argv [ i ][ 0 ] == '-' && argv [ i ][ 1 ] == 'l' ) {
69
70       if ( isdigit ( argv [ i ][ 2 ] ) ) {
71         unsigned char x = atoi ( argv [ i ] + 2 );
72         if ( x >= 0 &&
73              x < pndn_none )
74         {
75           logall = x;
76         }
77       } else {
78         logall = 0;
79       }
80
81     } else if ( argv [ i ][ 0 ] == '-' && argv [ i ][ 1 ] == 'f' && argv [ i ][ 2 ] != '\0' )
82     {
83       g_frontend = argv [ i ] + 2;
84     } else {
85       //printf ( "Unknown: %s\n", argv [ i ] );
86       printf ( "%s [-l[##]] [-d] [-fFRONTENDPATH]\n", argv [ 0 ] );
87       printf ( "-d\tDaemon mode; detach from terminal, chdir to /tmp, suppress output. Optional.\n" );
88       printf ( "-l#\tLog-it; -l is 0-and-up (or all), and -l2 means 2-and-up (not all); l[0-3] for now. Log goes to /tmp/mmwrapper.log\n" );
89       printf ( "-f\tFull path of frontend to run\n" );
90       exit ( 0 );
91     }
92
93   } // for
94
95   /* enable logging?
96    */
97   pnd_log_set_pretext ( "mmwrapper" );
98   pnd_log_set_flush ( 1 );
99
100   if ( logall == -1 ) {
101     // standard logging; non-daemon versus daemon
102
103     if ( g_daemon_mode ) {
104       // nada
105     } else {
106       pnd_log_set_filter ( pndn_rem );
107       //pnd_log_set_filter ( pndn_debug );
108       pnd_log_to_stdout();
109     }
110
111   } else {
112     FILE *f;
113
114     f = fopen ( "/tmp/mmwrapper.log", "w" );
115
116     if ( f ) {
117       pnd_log_set_filter ( logall );
118       pnd_log_to_stream ( f );
119       pnd_log ( pndn_rem, "logall mode - logging to /tmp/mmwrapper.log\n" );
120     }
121
122     if ( logall == pndn_debug ) {
123       pnd_log_set_buried_logging ( 1 ); // log the shit out of it
124       pnd_log ( pndn_rem, "logall mode 0 - turned on buried logging\n" );
125     }
126
127   } // logall
128
129   pnd_log ( pndn_rem, "%s built %s %s", argv [ 0 ], __DATE__, __TIME__ );
130
131   pnd_log ( pndn_rem, "log level starting as %u", pnd_log_get_filter() );
132
133   pnd_log ( pndn_rem, "Frontend is %s", g_frontend );
134
135   if ( g_daemon_mode ) {
136
137     // set a CWD somewhere else
138 #if 0
139     chdir ( "/tmp" );
140 #endif
141
142     // detach from terminal
143     if ( ( i = fork() ) < 0 ) {
144       pnd_log ( pndn_error, "ERROR: Couldn't fork()\n" );
145       exit ( i );
146     }
147     if ( i ) {
148       exit ( 0 ); // exit parent
149     }
150     setsid();
151
152     // umask
153     umask ( 022 ); // emitted files can be rwxr-xr-x
154     
155   } // set up daemon
156
157   // check frontend
158   if ( ! g_frontend ) {
159     pnd_log ( pndn_error, "ERROR: No frontend specified!\n" );
160     exit ( -1 );
161   }
162
163   /* actual work now
164    */
165
166   // invoke frontend
167   // wait for something to come back when it exits
168
169   char cmdbuf [ 1024 ];
170   char *c;
171   char *args;
172
173   while ( 1 ) {
174
175     // reset
176     bzero ( cmdbuf, 1024 );
177     args = NULL;
178
179     // invoke frontend
180     pnd_log ( pndn_debug, "Invoking frontend: %s\n", g_frontend );
181
182     FILE *fe = popen ( g_frontend, "r" );
183     while ( fgets ( cmdbuf, 1000, fe ) ) {
184       if ( strstr ( cmdbuf, MM_WATCHIT ) ) {
185         break;
186       }
187       pnd_log ( pndn_debug, "Junk: %s", cmdbuf );
188     }
189     pclose ( fe );
190
191     if ( ( c = strchr ( cmdbuf, '\n' ) ) ) {
192       *c = '\0'; // truncate trailing newline
193     }
194
195     if ( ( c = strchr ( cmdbuf, ' ' ) ) ) {
196       *c = '\0';
197       args = c + 1;
198     }
199
200     pnd_log ( pndn_debug, "Command from frontend: '%s' args: '%s'\n", cmdbuf, args ? args : "none" );
201
202     // deal with command
203     if ( strcasecmp ( cmdbuf, MM_QUIT ) == 0 ) {
204       // time to die!
205       pnd_log ( pndn_rem, "Frontend requests shutdown.\n" );
206       exit ( 0 );
207     } else if ( strcasecmp ( cmdbuf, MM_RUN ) == 0 ) {
208       // shell out and run it
209       int retval = system ( args );
210
211       if ( retval < 0 ) {
212         pnd_log ( pndn_error, "ERROR: Couldn't invoke application specified by frontend: '%s'\n", args );
213       } else {
214         pnd_log ( pndn_rem, "Invoked application returned %d\n", WEXITSTATUS(retval) );
215       }
216
217     } else {
218       pnd_log ( pndn_rem, "Unexpected exit of frontend; restarting it!\n" );
219       // next time around the loop
220     }
221
222   } // while
223
224   return ( 0 );
225 } // main